Skip to content

Commit 1925349

Browse files
committed
Add JUnit Jupiter support for App Engine and migrate all flowable-app-engine tests to JUnit Jupiter
1 parent de40800 commit 1925349

13 files changed

Lines changed: 376 additions & 53 deletions

File tree

modules/flowable-app-engine/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@
8181
<dependency>
8282
<groupId>org.junit.jupiter</groupId>
8383
<artifactId>junit-jupiter-api</artifactId>
84-
<scope>test</scope>
84+
<scope>provided</scope>
8585
</dependency>
8686
<dependency>
8787
<groupId>org.junit.jupiter</groupId>
88-
<artifactId>junit-jupiter-engine</artifactId>
88+
<artifactId>junit-jupiter</artifactId>
8989
<scope>test</scope>
9090
</dependency>
9191
<dependency>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/* Licensed under the Apache License, Version 2.0 (the "License");
2+
* you may not use this file except in compliance with the License.
3+
* You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
package org.flowable.app.engine.test;
14+
15+
import java.lang.annotation.Documented;
16+
import java.lang.annotation.ElementType;
17+
import java.lang.annotation.Inherited;
18+
import java.lang.annotation.Retention;
19+
import java.lang.annotation.RetentionPolicy;
20+
import java.lang.annotation.Target;
21+
22+
/**
23+
* An annotation that can be used on test classes or as a meta annotation to use a custom configuration resource for the {@link FlowableAppExtension}.
24+
* <p>
25+
* This annotation can be used to create a custom annotation that would provide the configuration resource to the {@link FlowableAppExtension}.
26+
* </p>
27+
* Usage
28+
* <pre><code>
29+
* &#64;Target({ElementType.TYPE})
30+
* &#64;Retention(RetentionPolicy.RUNTIME)
31+
* &#64;Documented
32+
* &#64;AppConfigurationResource("flowable.custom.app.cfg.xm")
33+
* public &#64;interface MyCustomResource {
34+
*
35+
* }
36+
*
37+
* &#64;FlowableAppTest
38+
* &#64;MyCustomResource
39+
* class YourTest {
40+
*
41+
* &#64;BeforeEach
42+
* void setUp(AppEngine appEngine) {
43+
* ...
44+
* }
45+
*
46+
* &#64;Test
47+
* void myTest(AppRepositoryService repositoryService) {
48+
* ...
49+
* }
50+
* ...
51+
* }
52+
* </code></pre>
53+
* In this example the configuration flowable.custom.app.cfg.xml will be used to create the AppEngine
54+
*
55+
* <b>NB:</b> This only works for the tests with JUnit Jupiter.
56+
*
57+
* @author Filip Hrisafov
58+
*/
59+
@Target({ ElementType.TYPE })
60+
@Retention(RetentionPolicy.RUNTIME)
61+
@Documented
62+
@Inherited
63+
public @interface AppConfigurationResource {
64+
65+
/**
66+
* The location of the resource that should be used to create the ProcessEngine.
67+
*/
68+
String value() default "flowable.app.cfg.xml";
69+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/* Licensed under the Apache License, Version 2.0 (the "License");
2+
* you may not use this file except in compliance with the License.
3+
* You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
package org.flowable.app.engine.test;
14+
15+
import java.lang.annotation.Documented;
16+
import java.lang.annotation.ElementType;
17+
import java.lang.annotation.Retention;
18+
import java.lang.annotation.RetentionPolicy;
19+
import java.lang.annotation.Target;
20+
21+
/**
22+
* An annotation that can be used on test and lifecycle methods to inject the id of the deployment deployed via {@link AppDeployment}.
23+
*
24+
* <b>NB:</b> This only works for tests with JUnit Jupiter.
25+
*
26+
* @author Filip Hrisafov
27+
*/
28+
@Target({ ElementType.PARAMETER })
29+
@Retention(RetentionPolicy.RUNTIME)
30+
@Documented
31+
public @interface AppDeploymentId {
32+
33+
}
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/* Licensed under the Apache License, Version 2.0 (the "License");
2+
* you may not use this file except in compliance with the License.
3+
* You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
package org.flowable.app.engine.test;
14+
15+
import java.lang.reflect.InvocationTargetException;
16+
import java.util.Set;
17+
18+
import org.flowable.app.api.AppManagementService;
19+
import org.flowable.app.api.AppRepositoryService;
20+
import org.flowable.app.engine.AppEngine;
21+
import org.flowable.app.engine.AppEngineConfiguration;
22+
import org.flowable.app.engine.test.impl.AppTestHelper;
23+
import org.junit.jupiter.api.extension.AfterEachCallback;
24+
import org.junit.jupiter.api.extension.BeforeEachCallback;
25+
import org.junit.jupiter.api.extension.ExtensionContext;
26+
import org.junit.jupiter.api.extension.ParameterContext;
27+
import org.junit.jupiter.api.extension.ParameterResolutionException;
28+
import org.junit.jupiter.api.extension.ParameterResolver;
29+
import org.junit.platform.commons.support.AnnotationSupport;
30+
31+
/**
32+
* JUnit Jupiter extension for the Flowable AppEngine and services initialization.
33+
*
34+
* <p>
35+
* Usage:
36+
* </p>
37+
*
38+
* <pre>
39+
* &#64;ExtendWith(FlowableAppExtension.class)
40+
* class YourTest {
41+
*
42+
* &#64;BeforeEach
43+
* void setUp(AppEngine appEngine) {
44+
* ...
45+
* }
46+
*
47+
* &#64;Test
48+
* void myTest(AppRepositoryService appRepositoryService) {
49+
* ...
50+
* }
51+
*
52+
* ...
53+
* }
54+
* </pre>
55+
*
56+
* <p>
57+
* The AppEngine and the services will be made available to the test class through the parameter resolution (BeforeEach, AfterEach, test methods).
58+
* The AppEngine will be initialized by default with the flowable.app.cfg.xml resource on the classpath.
59+
* To specify a different configuration file, annotate your class with {@link AppConfigurationResource}.
60+
* App engines will be cached as part of the JUnit Jupiter Extension context.
61+
* Right before the first time the setUp is called for a given configuration resource, the cmmn engine will be constructed.
62+
* </p>
63+
*
64+
* <p>
65+
* You can declare a deployment with the {@link AppDeployment} annotation. This extension will make sure that this deployment gets deployed before the setUp
66+
* and {@link AppRepositoryService#deleteDeployment(String, boolean) cascade deleted} after the tearDown.
67+
* The id of the deployment can be accessed by using {@link AppDeploymentId} in a test method.
68+
* </p>
69+
*
70+
* @author Filip Hrisafov
71+
*/
72+
public class FlowableAppExtension implements ParameterResolver, BeforeEachCallback, AfterEachCallback {
73+
74+
public static final String DEFAULT_CONFIGURATION_RESOURCE = "flowable.app.cfg.xml";
75+
76+
private static final ExtensionContext.Namespace NAMESPACE = ExtensionContext.Namespace.create(FlowableAppExtension.class);
77+
78+
private static final Set<Class<?>> SUPPORTED_PARAMETER_TYPES = Set.of(
79+
AppEngine.class,
80+
AppEngineConfiguration.class,
81+
AppRepositoryService.class,
82+
AppManagementService.class
83+
);
84+
85+
@Override
86+
public void beforeEach(ExtensionContext context) {
87+
FlowableAppTestHelper testHelper = getTestHelper(context);
88+
AnnotationSupport.findAnnotation(context.getTestMethod(), AppDeployment.class)
89+
.ifPresent(deployment -> {
90+
String deploymentId = AppTestHelper.annotationDeploymentSetUp(testHelper.getAppEngine(), context.getRequiredTestClass(),
91+
context.getRequiredTestMethod(), deployment);
92+
testHelper.setDeploymentIdFromDeploymentAnnotation(deploymentId);
93+
});
94+
95+
}
96+
97+
@Override
98+
public void afterEach(ExtensionContext context) {
99+
FlowableAppTestHelper testHelper = getTestHelper(context);
100+
String deploymentId = testHelper.getDeploymentIdFromDeploymentAnnotation();
101+
if (deploymentId != null) {
102+
testHelper.getAppEngine().getAppRepositoryService().deleteDeployment(deploymentId, true);
103+
testHelper.setDeploymentIdFromDeploymentAnnotation(null);
104+
}
105+
testHelper.getAppEngine().getAppEngineConfiguration().getClock().reset();
106+
107+
}
108+
109+
@Override
110+
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
111+
Class<?> parameterType = parameterContext.getParameter().getType();
112+
return SUPPORTED_PARAMETER_TYPES.contains(parameterType)
113+
|| AnnotationSupport.isAnnotated(parameterContext.getParameter(), AppDeploymentId.class);
114+
}
115+
116+
@Override
117+
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
118+
FlowableAppTestHelper testHelper = getTestHelper(extensionContext);
119+
if (parameterContext.isAnnotated(AppDeploymentId.class)) {
120+
return testHelper.getDeploymentIdFromDeploymentAnnotation();
121+
}
122+
123+
Class<?> parameterType = parameterContext.getParameter().getType();
124+
AppEngine appEngine = testHelper.getAppEngine();
125+
if (parameterType.isInstance(appEngine)) {
126+
return appEngine;
127+
}
128+
129+
try {
130+
return AppEngine.class.getDeclaredMethod("get" + parameterType.getSimpleName()).invoke(appEngine);
131+
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
132+
throw new ParameterResolutionException("Could not find service " + parameterType, e);
133+
}
134+
}
135+
136+
protected String getConfigurationResource(ExtensionContext context) {
137+
return AnnotationSupport.findAnnotation(context.getTestClass(), AppConfigurationResource.class)
138+
.map(AppConfigurationResource::value)
139+
.orElse(DEFAULT_CONFIGURATION_RESOURCE);
140+
}
141+
142+
protected FlowableAppTestHelper getTestHelper(ExtensionContext context) {
143+
return getStore(context)
144+
.getOrComputeIfAbsent(context.getRequiredTestClass(), key -> new FlowableAppTestHelper(createAppEngine(context)), FlowableAppTestHelper.class);
145+
}
146+
147+
protected AppEngine createAppEngine(ExtensionContext context) {
148+
return AppTestHelper.getAppEngine(getConfigurationResource(context));
149+
}
150+
151+
protected ExtensionContext.Store getStore(ExtensionContext context) {
152+
return context.getRoot().getStore(NAMESPACE);
153+
}
154+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/* Licensed under the Apache License, Version 2.0 (the "License");
2+
* you may not use this file except in compliance with the License.
3+
* You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
package org.flowable.app.engine.test;
14+
15+
import org.flowable.app.engine.AppEngine;
16+
17+
/**
18+
* A helper for the Flowable {@link FlowableAppExtension} that can be used within the JUnit Jupiter context store.
19+
*
20+
* @author Filip Hrisafov
21+
*/
22+
public class FlowableAppTestHelper {
23+
24+
protected final AppEngine appEngine;
25+
protected String deploymentIdFromDeploymentAnnotation;
26+
27+
public FlowableAppTestHelper(AppEngine appEngine) {
28+
this.appEngine = appEngine;
29+
}
30+
31+
public AppEngine getAppEngine() {
32+
return appEngine;
33+
}
34+
35+
public String getDeploymentIdFromDeploymentAnnotation() {
36+
return deploymentIdFromDeploymentAnnotation;
37+
}
38+
39+
public void setDeploymentIdFromDeploymentAnnotation(String deploymentIdFromDeploymentAnnotation) {
40+
this.deploymentIdFromDeploymentAnnotation = deploymentIdFromDeploymentAnnotation;
41+
}
42+
}

modules/flowable-app-engine/src/main/java/org/flowable/app/engine/test/impl/AppTestHelper.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ public abstract class AppTestHelper {
4141
// Test annotation support /////////////////////////////////////////////
4242

4343
public static String annotationDeploymentSetUp(AppEngine appEngine, Class<?> testClass, String methodName) {
44-
String deploymentId = null;
4544
Method method = null;
4645
try {
4746
method = testClass.getMethod(methodName, (Class<?>[]) null);
@@ -50,6 +49,12 @@ public static String annotationDeploymentSetUp(AppEngine appEngine, Class<?> tes
5049
return null;
5150
}
5251
AppDeployment deploymentAnnotation = method.getAnnotation(AppDeployment.class);
52+
return annotationDeploymentSetUp(appEngine, testClass, method, deploymentAnnotation);
53+
}
54+
55+
public static String annotationDeploymentSetUp(AppEngine appEngine, Class<?> testClass, Method method, AppDeployment deploymentAnnotation) {
56+
String deploymentId = null;
57+
String methodName = method.getName();
5358
if (deploymentAnnotation != null) {
5459
LOGGER.debug("annotation @AppDeployment creates deployment for {}.{}", testClass.getSimpleName(), methodName);
5560
String[] resources = deploymentAnnotation.resources();
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/* Licensed under the Apache License, Version 2.0 (the "License");
2+
* you may not use this file except in compliance with the License.
3+
* You may obtain a copy of the License at
4+
*
5+
* http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software
8+
* distributed under the License is distributed on an "AS IS" BASIS,
9+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
* See the License for the specific language governing permissions and
11+
* limitations under the License.
12+
*/
13+
package org.flowable.app.engine.test;
14+
15+
import org.flowable.app.api.AppManagementService;
16+
import org.flowable.app.api.AppRepositoryService;
17+
import org.flowable.app.engine.AppEngine;
18+
import org.flowable.app.engine.AppEngineConfiguration;
19+
import org.junit.jupiter.api.BeforeEach;
20+
import org.junit.jupiter.api.extension.ExtendWith;
21+
22+
/**
23+
* @author Filip Hrisafov
24+
*/
25+
@ExtendWith(FlowableAppExtension.class)
26+
public class BaseFlowableAppTest {
27+
28+
protected AppEngineConfiguration appEngineConfiguration;
29+
protected AppManagementService appManagementService;
30+
protected AppRepositoryService appRepositoryService;
31+
32+
@BeforeEach
33+
void setupServices(AppEngine appEngine) {
34+
this.appEngineConfiguration = appEngine.getAppEngineConfiguration();
35+
this.appManagementService = appEngineConfiguration.getAppManagementService();
36+
this.appRepositoryService = appEngineConfiguration.getAppRepositoryService();
37+
}
38+
39+
40+
}

modules/flowable-app-engine/src/test/java/org/flowable/app/engine/test/persistence/AppEngineDropScriptsTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414

1515
import static org.assertj.core.api.Assertions.assertThat;
1616

17-
import org.flowable.app.engine.test.FlowableAppTestCase;
17+
import org.flowable.app.engine.test.BaseFlowableAppTest;
1818
import org.flowable.common.engine.impl.db.SchemaOperationsEngineBuild;
1919
import org.flowable.common.engine.impl.db.SchemaOperationsEngineDropDbCmd;
20-
import org.junit.Test;
20+
import org.junit.jupiter.api.Test;
2121

2222
/**
2323
* @author Joram Barrez
2424
*/
25-
public class AppEngineDropScriptsTest extends FlowableAppTestCase {
25+
class AppEngineDropScriptsTest extends BaseFlowableAppTest {
2626

2727
@Test
2828
public void testDropSchema() {

0 commit comments

Comments
 (0)