This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch tomee-10.x
in repository https://gitbox.apache.org/repos/asf/tomee.git
The following commit(s) were added to refs/heads/tomee-10.x by this push:
new 16b3ca9059 TOMEE-4714 - Allow to restart the TomEE embedded runner and
add a container lifecycle mode to the JUnit 5 extension (#2957)
16b3ca9059 is described below
commit 16b3ca90597d27ff43dabd17a31a09b8ac734664
Author: Richard Zowalla <[email protected]>
AuthorDate: Mon Sep 28 20:35:48 2026 +0200
TOMEE-4714 - Allow to restart the TomEE embedded runner and add a container
lifecycle mode to the JUnit 5 extension (#2957)
TomEEEmbeddedApplicationRunner#close() did not reset the started flag, so
the runner could not be started again. The JUnit 5 extension closes the
container after each test (class), so only the first container start of a JVM
worked.
@RunWithTomEEEmbedded now has a mode (PER_JVM, PER_ALL, PER_EACH, AUTO)
similar to @RunWithApplicationComposer and is @Inherited like it. AUTO keeps
the current behaviour and follows the lifecycle of the test instance.
TomEEEmbeddedBase got a start(Class) overload, as there is no test instance
yet if the container is started for a test class.
---
tomee/tomee-embedded/pom.xml | 38 +++++++++++
.../embedded/TomEEEmbeddedApplicationRunner.java | 1 +
.../tomee/embedded/junit/TomEEEmbeddedBase.java | 6 +-
.../embedded/junit/jupiter/ExtensionMode.java | 47 +++++++++++++
.../junit/jupiter/RunWithTomEEEmbedded.java | 6 ++
.../junit/jupiter/TomEEEmbeddedExtension.java | 58 +++++++++++++----
.../AutoPerClassRunnerExtensionModeTest.java | 76 ++++++++++++++++++++++
.../embedded/AutoRunnerExtensionModeTest.java | 74 +++++++++++++++++++++
.../embedded/PerAllRunnerExtensionModeTest.java | 75 +++++++++++++++++++++
.../embedded/PerEachRunnerExtensionModeTest.java | 75 +++++++++++++++++++++
.../PerJvmOtherRunnerExtensionModeTest.java | 73 +++++++++++++++++++++
.../embedded/PerJvmRunnerExtensionModeTest.java | 75 +++++++++++++++++++++
.../tomee/embedded/RunnerExtensionModeApp.java} | 25 +++----
13 files changed, 603 insertions(+), 26 deletions(-)
diff --git a/tomee/tomee-embedded/pom.xml b/tomee/tomee-embedded/pom.xml
index 2b6bfacccc..361ceed057 100644
--- a/tomee/tomee-embedded/pom.xml
+++ b/tomee/tomee-embedded/pom.xml
@@ -226,6 +226,7 @@
<exclude>**/SingleInstanceRunnerExtensionTest*</exclude>
<exclude>**/NoScannerSingleRunnerTest*</exclude>
<exclude>**/NoScannerSingleRunnerExtensionTest*</exclude>
+ <exclude>**/*RunnerExtensionModeTest*</exclude>
</excludes>
</configuration>
</execution>
@@ -243,6 +244,43 @@
</systemPropertyVariables>
</configuration>
</execution>
+ <execution>
+ <id>junit5-extension-modes</id>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <!-- the test classes need to share the JVM to start the
container more than once / to share it -->
+ <forkCount>1</forkCount>
+ <reuseForks>true</reuseForks>
+ <includes>
+ <include>**/*RunnerExtensionModeTest*</include>
+ </includes>
+ <excludes>
+ <exclude>**/PerJvm*RunnerExtensionModeTest*</exclude>
+ </excludes>
+ <systemPropertyVariables>
+
<tomee.application-composer.application>org.apache.tomee.embedded.RunnerExtensionModeApp</tomee.application-composer.application>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ <execution>
+ <id>junit5-extension-mode-per-jvm</id>
+ <goals>
+ <goal>test</goal>
+ </goals>
+ <configuration>
+ <!-- the test classes need to share the JVM to start the
container more than once / to share it -->
+ <forkCount>1</forkCount>
+ <reuseForks>true</reuseForks>
+ <includes>
+ <include>**/PerJvm*RunnerExtensionModeTest*</include>
+ </includes>
+ <systemPropertyVariables>
+
<tomee.application-composer.application>org.apache.tomee.embedded.RunnerExtensionModeApp</tomee.application-composer.application>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
<execution>
<id>single-server-custom-scanning</id>
<goals>
diff --git
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/TomEEEmbeddedApplicationRunner.java
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/TomEEEmbeddedApplicationRunner.java
index 16a1082a1e..3c1b170f58 100644
---
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/TomEEEmbeddedApplicationRunner.java
+++
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/TomEEEmbeddedApplicationRunner.java
@@ -378,6 +378,7 @@ public class TomEEEmbeddedApplicationRunner implements
AutoCloseable {
SHUTDOWN_TASKS.remove(hook);
hook = null;
app = null;
+ started = false; // allow to start again, e.g. for the next test
}
}
diff --git
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/TomEEEmbeddedBase.java
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/TomEEEmbeddedBase.java
index cebd265c94..a6ee1ead50 100644
---
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/TomEEEmbeddedBase.java
+++
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/TomEEEmbeddedBase.java
@@ -27,7 +27,11 @@ public class TomEEEmbeddedBase {
private static final AtomicReference<TomEEEmbeddedApplicationRunner>
RUNNER = new AtomicReference<>();
public void start(final Object marker) throws Exception {
- getRunner().start(marker.getClass(), (Properties) null);
+ start(marker.getClass());
+ }
+
+ public void start(final Class<?> marker) throws Exception {
+ getRunner().start(marker, (Properties) null);
}
public void close() {
diff --git
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/ExtensionMode.java
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/ExtensionMode.java
new file mode 100644
index 0000000000..cc92a1535a
--- /dev/null
+++
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/ExtensionMode.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.embedded.junit.jupiter;
+
+/**
+ * The lifecycle of the TomEE embedded container used by {@link
RunWithTomEEEmbedded}.
+ * <p>
+ * It offers the same modes as the {@code ExtensionMode} of {@code
@RunWithApplicationComposer} (openejb-junit5).
+ * A single container is used per JVM, so tests sharing a JVM must not be
executed in parallel.
+ */
+public enum ExtensionMode {
+
+ /**
+ * When using this mode, a container instance will be created once for the
JVM lifetime.
+ */
+ PER_JVM,
+
+ /**
+ * When using this mode, a container instance will be created for each
test class.
+ */
+ PER_ALL,
+
+ /**
+ * When using this mode, a container instance will be created for each
test.
+ */
+ PER_EACH,
+
+ /**
+ * When using this mode, the container lifecycle follows the lifecycle of
the test instance:
+ * {@link #PER_ALL} for {@code TestInstance.Lifecycle.PER_CLASS}, {@link
#PER_EACH} otherwise.
+ */
+ AUTO
+}
diff --git
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/RunWithTomEEEmbedded.java
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/RunWithTomEEEmbedded.java
index 79bf10560e..d4c3ba5d87 100644
---
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/RunWithTomEEEmbedded.java
+++
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/RunWithTomEEEmbedded.java
@@ -20,13 +20,19 @@ package org.apache.tomee.embedded.junit.jupiter;
import org.junit.jupiter.api.extension.ExtendWith;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ExtendWith(org.apache.tomee.embedded.junit.jupiter.TomEEEmbeddedExtension.class)
public @interface RunWithTomEEEmbedded {
+ /**
+ * The test container lifecycle <em>mode</em> to use.
+ */
+ ExtensionMode mode() default ExtensionMode.AUTO;
}
diff --git
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/TomEEEmbeddedExtension.java
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/TomEEEmbeddedExtension.java
index 106555fb90..db1ecd3c42 100644
---
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/TomEEEmbeddedExtension.java
+++
b/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/TomEEEmbeddedExtension.java
@@ -25,6 +25,7 @@ import org.junit.jupiter.api.extension.BeforeAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestInstances;
+import org.junit.platform.commons.util.AnnotationUtils;
import java.util.List;
@@ -32,34 +33,53 @@ public class TomEEEmbeddedExtension implements
BeforeAllCallback, AfterAllCallba
private static final TomEEEmbeddedBase BASE = new TomEEEmbeddedBase();
+ // the container of PER_JVM is never closed, so the other modes can't be
used once it is started
+ private static volatile boolean perJvm;
+
@Override
- public void afterAll(ExtensionContext context) {
- if (isPerClass(context)) {
- BASE.close();
+ public void beforeAll(final ExtensionContext context) throws Exception {
+ final ExtensionMode mode = getMode(context);
+ validate(mode);
+
+ if (mode != ExtensionMode.PER_EACH) {
+ BASE.start(context.getRequiredTestClass());
+ if (mode == ExtensionMode.PER_JVM) {
+ perJvm = true;
+ }
+ if (isPerClass(context)) {
+ doInject(context);
+ }
}
}
@Override
- public void beforeAll(ExtensionContext context) throws Exception {
+ public void afterAll(final ExtensionContext context) {
+ if (getMode(context) == ExtensionMode.PER_ALL) {
+ BASE.close();
+ }
+ }
- if (isPerClass(context)) {
- BASE.start(context.getRequiredTestInstance());
+ @Override
+ public void beforeEach(final ExtensionContext context) throws Exception {
+ final boolean perEach = getMode(context) == ExtensionMode.PER_EACH;
+ if (perEach) {
+ BASE.start(context.getRequiredTestClass());
+ }
+ if (perEach || !isPerClass(context)) {
doInject(context);
}
}
@Override
- public void afterEach(ExtensionContext context) throws Exception {
- if (!isPerClass(context)) {
+ public void afterEach(final ExtensionContext context) {
+ if (getMode(context) == ExtensionMode.PER_EACH) {
BASE.close();
}
}
- @Override
- public void beforeEach(ExtensionContext context) throws Exception {
- if (!isPerClass(context)) {
- BASE.start(context.getRequiredTestInstance());
- doInject(context);
+ private void validate(final ExtensionMode mode) {
+ if (perJvm && mode != ExtensionMode.PER_JVM) {
+ throw new OpenEJBRuntimeException("Cannot run PER_JVM in
combination with PER_ALL, PER_EACH or AUTO");
}
}
@@ -78,6 +98,18 @@ public class TomEEEmbeddedExtension implements
BeforeAllCallback, AfterAllCallba
});
}
+ // resolves AUTO to the mode matching the lifecycle of the test instance
+ ExtensionMode getMode(final ExtensionContext context) {
+ final ExtensionMode mode = context.getTestClass()
+ .flatMap(test -> AnnotationUtils.findAnnotation(test,
RunWithTomEEEmbedded.class))
+ .map(RunWithTomEEEmbedded::mode)
+ .orElse(ExtensionMode.AUTO);
+ if (mode == ExtensionMode.AUTO) {
+ return isPerClass(context) ? ExtensionMode.PER_ALL :
ExtensionMode.PER_EACH;
+ }
+ return mode;
+ }
+
boolean isPerClass(final ExtensionContext context) {
return context.getTestInstanceLifecycle()
.map(it -> it.equals(TestInstance.Lifecycle.PER_CLASS))
diff --git
a/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/AutoPerClassRunnerExtensionModeTest.java
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/AutoPerClassRunnerExtensionModeTest.java
new file mode 100644
index 0000000000..a1c4802ab9
--- /dev/null
+++
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/AutoPerClassRunnerExtensionModeTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.embedded;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.testing.Application;
+import org.apache.openejb.testing.RandomPort;
+import org.apache.tomee.embedded.junit.jupiter.RunWithTomEEEmbedded;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInstance;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+// the container follows the lifecycle of the test instance, so it is started
once for the test class
+@RunWithTomEEEmbedded
+@TestInstance(TestInstance.Lifecycle.PER_CLASS)
+public class AutoPerClassRunnerExtensionModeTest {
+ // an application instance is created for each container start
+ private static final Set<Object> APPLICATIONS =
Collections.newSetFromMap(new IdentityHashMap<>());
+
+ @Application
+ private RunnerExtensionModeApp app;
+
+ @RandomPort("http")
+ private int port;
+
+ @Test
+ public void first() {
+ assertStarted();
+ }
+
+ @Test
+ public void second() {
+ assertStarted();
+ }
+
+ @Test
+ public void third() {
+ assertStarted();
+ }
+
+ @AfterAll
+ public static void containers() {
+ assertEquals(1, APPLICATIONS.size());
+ }
+
+ private void assertStarted() {
+ assertNotNull(SystemInstance.get().getComponent(Assembler.class));
+ assertNotNull(app);
+ assertNotEquals(0, app.getPort());
+ assertEquals(app.getPort(), port);
+ APPLICATIONS.add(app);
+ }
+}
diff --git
a/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/AutoRunnerExtensionModeTest.java
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/AutoRunnerExtensionModeTest.java
new file mode 100644
index 0000000000..3ec373e9c9
--- /dev/null
+++
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/AutoRunnerExtensionModeTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.embedded;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.testing.Application;
+import org.apache.openejb.testing.RandomPort;
+import org.apache.tomee.embedded.junit.jupiter.RunWithTomEEEmbedded;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+// the container follows the lifecycle of the test instance, so it is started
for each test
+@RunWithTomEEEmbedded
+public class AutoRunnerExtensionModeTest {
+ // an application instance is created for each container start
+ private static final Set<Object> APPLICATIONS =
Collections.newSetFromMap(new IdentityHashMap<>());
+
+ @Application
+ private RunnerExtensionModeApp app;
+
+ @RandomPort("http")
+ private int port;
+
+ @Test
+ public void first() {
+ assertStarted();
+ }
+
+ @Test
+ public void second() {
+ assertStarted();
+ }
+
+ @Test
+ public void third() {
+ assertStarted();
+ }
+
+ @AfterAll
+ public static void containers() {
+ assertEquals(3, APPLICATIONS.size());
+ }
+
+ private void assertStarted() {
+ assertNotNull(SystemInstance.get().getComponent(Assembler.class));
+ assertNotNull(app);
+ assertNotEquals(0, app.getPort());
+ assertEquals(app.getPort(), port);
+ APPLICATIONS.add(app);
+ }
+}
diff --git
a/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerAllRunnerExtensionModeTest.java
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerAllRunnerExtensionModeTest.java
new file mode 100644
index 0000000000..cd020237ab
--- /dev/null
+++
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerAllRunnerExtensionModeTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.embedded;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.testing.Application;
+import org.apache.openejb.testing.RandomPort;
+import org.apache.tomee.embedded.junit.jupiter.ExtensionMode;
+import org.apache.tomee.embedded.junit.jupiter.RunWithTomEEEmbedded;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+// the container is started once for the test class
+@RunWithTomEEEmbedded(mode = ExtensionMode.PER_ALL)
+public class PerAllRunnerExtensionModeTest {
+ // an application instance is created for each container start
+ private static final Set<Object> APPLICATIONS =
Collections.newSetFromMap(new IdentityHashMap<>());
+
+ @Application
+ private RunnerExtensionModeApp app;
+
+ @RandomPort("http")
+ private int port;
+
+ @Test
+ public void first() {
+ assertStarted();
+ }
+
+ @Test
+ public void second() {
+ assertStarted();
+ }
+
+ @Test
+ public void third() {
+ assertStarted();
+ }
+
+ @AfterAll
+ public static void containers() {
+ assertEquals(1, APPLICATIONS.size());
+ }
+
+ private void assertStarted() {
+ assertNotNull(SystemInstance.get().getComponent(Assembler.class));
+ assertNotNull(app);
+ assertNotEquals(0, app.getPort());
+ assertEquals(app.getPort(), port);
+ APPLICATIONS.add(app);
+ }
+}
diff --git
a/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerEachRunnerExtensionModeTest.java
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerEachRunnerExtensionModeTest.java
new file mode 100644
index 0000000000..140c85d33b
--- /dev/null
+++
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerEachRunnerExtensionModeTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.embedded;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.testing.Application;
+import org.apache.openejb.testing.RandomPort;
+import org.apache.tomee.embedded.junit.jupiter.ExtensionMode;
+import org.apache.tomee.embedded.junit.jupiter.RunWithTomEEEmbedded;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+// the container is started for each test
+@RunWithTomEEEmbedded(mode = ExtensionMode.PER_EACH)
+public class PerEachRunnerExtensionModeTest {
+ // an application instance is created for each container start
+ private static final Set<Object> APPLICATIONS =
Collections.newSetFromMap(new IdentityHashMap<>());
+
+ @Application
+ private RunnerExtensionModeApp app;
+
+ @RandomPort("http")
+ private int port;
+
+ @Test
+ public void first() {
+ assertStarted();
+ }
+
+ @Test
+ public void second() {
+ assertStarted();
+ }
+
+ @Test
+ public void third() {
+ assertStarted();
+ }
+
+ @AfterAll
+ public static void containers() {
+ assertEquals(3, APPLICATIONS.size());
+ }
+
+ private void assertStarted() {
+ assertNotNull(SystemInstance.get().getComponent(Assembler.class));
+ assertNotNull(app);
+ assertNotEquals(0, app.getPort());
+ assertEquals(app.getPort(), port);
+ APPLICATIONS.add(app);
+ }
+}
diff --git
a/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerJvmOtherRunnerExtensionModeTest.java
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerJvmOtherRunnerExtensionModeTest.java
new file mode 100644
index 0000000000..375d8e4520
--- /dev/null
+++
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerJvmOtherRunnerExtensionModeTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.embedded;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.testing.Application;
+import org.apache.openejb.testing.RandomPort;
+import org.apache.tomee.embedded.junit.jupiter.ExtensionMode;
+import org.apache.tomee.embedded.junit.jupiter.RunWithTomEEEmbedded;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+// the container is started once for the JVM and shared with
PerJvmRunnerExtensionModeTest
+@RunWithTomEEEmbedded(mode = ExtensionMode.PER_JVM)
+public class PerJvmOtherRunnerExtensionModeTest {
+ // shared with PerJvmRunnerExtensionModeTest as both tests use the same
container
+ private static final Set<Object> APPLICATIONS =
PerJvmRunnerExtensionModeTest.APPLICATIONS;
+
+ @Application
+ private RunnerExtensionModeApp app;
+
+ @RandomPort("http")
+ private int port;
+
+ @Test
+ public void first() {
+ assertStarted();
+ }
+
+ @Test
+ public void second() {
+ assertStarted();
+ }
+
+ @Test
+ public void third() {
+ assertStarted();
+ }
+
+ @AfterAll
+ public static void containers() {
+ assertEquals(1, APPLICATIONS.size());
+ }
+
+ private void assertStarted() {
+ assertNotNull(SystemInstance.get().getComponent(Assembler.class));
+ assertNotNull(app);
+ assertNotEquals(0, app.getPort());
+ assertEquals(app.getPort(), port);
+ APPLICATIONS.add(app);
+ }
+}
diff --git
a/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerJvmRunnerExtensionModeTest.java
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerJvmRunnerExtensionModeTest.java
new file mode 100644
index 0000000000..9181142665
--- /dev/null
+++
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/PerJvmRunnerExtensionModeTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tomee.embedded;
+
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.testing.Application;
+import org.apache.openejb.testing.RandomPort;
+import org.apache.tomee.embedded.junit.jupiter.ExtensionMode;
+import org.apache.tomee.embedded.junit.jupiter.RunWithTomEEEmbedded;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Set;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+// the container is started once for the JVM and shared with
PerJvmOtherRunnerExtensionModeTest
+@RunWithTomEEEmbedded(mode = ExtensionMode.PER_JVM)
+public class PerJvmRunnerExtensionModeTest {
+ // an application instance is created for each container start
+ static final Set<Object> APPLICATIONS = Collections.newSetFromMap(new
IdentityHashMap<>());
+
+ @Application
+ private RunnerExtensionModeApp app;
+
+ @RandomPort("http")
+ private int port;
+
+ @Test
+ public void first() {
+ assertStarted();
+ }
+
+ @Test
+ public void second() {
+ assertStarted();
+ }
+
+ @Test
+ public void third() {
+ assertStarted();
+ }
+
+ @AfterAll
+ public static void containers() {
+ assertEquals(1, APPLICATIONS.size());
+ }
+
+ private void assertStarted() {
+ assertNotNull(SystemInstance.get().getComponent(Assembler.class));
+ assertNotNull(app);
+ assertNotEquals(0, app.getPort());
+ assertEquals(app.getPort(), port);
+ APPLICATIONS.add(app);
+ }
+}
diff --git
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/RunWithTomEEEmbedded.java
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/RunnerExtensionModeApp.java
similarity index 64%
copy from
tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/RunWithTomEEEmbedded.java
copy to
tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/RunnerExtensionModeApp.java
index 79bf10560e..785b514ab6 100644
---
a/tomee/tomee-embedded/src/main/java/org/apache/tomee/embedded/junit/jupiter/RunWithTomEEEmbedded.java
+++
b/tomee/tomee-embedded/src/test/java/org/apache/tomee/embedded/RunnerExtensionModeApp.java
@@ -14,19 +14,20 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package org.apache.tomee.embedded;
-package org.apache.tomee.embedded.junit.jupiter;
+import org.apache.openejb.testing.Application;
+import org.apache.openejb.testing.Classes;
+import org.apache.openejb.testing.RandomPort;
-import org.junit.jupiter.api.extension.ExtendWith;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Target(ElementType.TYPE)
-@Retention(RetentionPolicy.RUNTIME)
-@ExtendWith(org.apache.tomee.embedded.junit.jupiter.TomEEEmbeddedExtension.class)
-public @interface RunWithTomEEEmbedded {
+// the application of the *RunnerExtensionModeTest, selected by the surefire
execution
+@Application
+@Classes(context = "app")
+public class RunnerExtensionModeApp {
+ @RandomPort("http")
+ private int port;
+ public int getPort() {
+ return port;
+ }
}