You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rz...@apache.org on 2026/06/30 17:05:30 UTC
(tomee) branch TOMEE-4631 created (now 349efba294)
This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a change to branch TOMEE-4631
in repository https://gitbox.apache.org/repos/asf/tomee.git
at 349efba294 TOMEE-4631 - arquillian-tomee-remote: re-register container on every Manager bootstrap
This branch includes the following new commits:
new 349efba294 TOMEE-4631 - arquillian-tomee-remote: re-register container on every Manager bootstrap
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(tomee) 01/01: TOMEE-4631 - arquillian-tomee-remote: re-register container on every Manager bootstrap
Posted by rz...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch TOMEE-4631
in repository https://gitbox.apache.org/repos/asf/tomee.git
commit 349efba294cf760c25af0ba0bda1ca0838cf5c33
Author: Richard Zowalla <rz...@apache.org>
AuthorDate: Tue Jun 30 19:05:16 2026 +0200
TOMEE-4631 - arquillian-tomee-remote: re-register container on every Manager bootstrap
RemoteTomEEExtension guarded container registration behind a JVM-static
AtomicBoolean latch. Arquillian instantiates the extension and calls
register() once per Manager bootstrap, so the latch let only the first
Manager in a JVM fork register its DeployableContainer. Any second
Manager in the same fork (e.g. maven-failsafe-plugin's
rerunFailingTestsCount) got an empty ContainerRegistry and failed every
deployment with "DeploymentScenario contains a target (_DEFAULT_) not
matching any defined Container in the registry".
Drop the static latch (and the static lock that only guarded it) and
register unconditionally, matching EmbeddedTomEEExtension. The existing
try/catch(IllegalArgumentException) remains as the guard against a
genuine double-registration within a single builder.
Adds RemoteTomEEExtensionReRegistrationTest covering re-registration
across two Manager bootstraps in the same JVM.
---
.../arquillian/remote/RemoteTomEEExtension.java | 34 ++----
.../RemoteTomEEExtensionReRegistrationTest.java | 115 +++++++++++++++++++++
2 files changed, 126 insertions(+), 23 deletions(-)
diff --git a/arquillian/arquillian-tomee-remote/src/main/java/org/apache/tomee/arquillian/remote/RemoteTomEEExtension.java b/arquillian/arquillian-tomee-remote/src/main/java/org/apache/tomee/arquillian/remote/RemoteTomEEExtension.java
index d1bf834ce4..b11f65ae35 100644
--- a/arquillian/arquillian-tomee-remote/src/main/java/org/apache/tomee/arquillian/remote/RemoteTomEEExtension.java
+++ b/arquillian/arquillian-tomee-remote/src/main/java/org/apache/tomee/arquillian/remote/RemoteTomEEExtension.java
@@ -26,40 +26,28 @@ import org.jboss.arquillian.container.test.spi.client.deployment.AuxiliaryArchiv
import org.jboss.arquillian.core.spi.LoadableExtension;
import org.jboss.arquillian.test.spi.enricher.resource.ResourceProvider;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.ReentrantLock;
import java.util.logging.Level;
import java.util.logging.Logger;
public class RemoteTomEEExtension implements LoadableExtension {
private static final String ADAPTER = "tomee-remote";
- private static final AtomicBoolean registered = new AtomicBoolean(false);
- private static final ReentrantLock lock = new ReentrantLock();
@Override
public void register(final ExtensionBuilder builder) {
if (ArquillianUtil.isCurrentAdapter(ADAPTER)) {
-
- final ReentrantLock l = lock;
- l.lock();
-
+ // Register unconditionally (like EmbeddedTomEEExtension): register() runs once per
+ // Manager bootstrap, so a JVM-static latch skipped every Manager after the first in
+ // the same fork and broke failsafe reruns (TOMEE-4631). The try/catch below guards
+ // against a genuine double-registration within a single builder.
try {
-
- if (!registered.getAndSet(true)) {
-
- try {
- builder.observer(RemoteInitialContextObserver.class);
- builder.observer(DeploymentExceptionObserver.class);
- builder.service(DeployableContainer.class, RemoteTomEEContainer.class)
- .service(AuxiliaryArchiveAppender.class, RemoteTomEEEJBEnricherArchiveAppender.class)
- .service(ResourceProvider.class, DeploymentExceptionProvider.class);
- } catch (final IllegalArgumentException e) {
- Logger.getLogger(RemoteTomEEExtension.class.getName()).log(Level.WARNING, "RemoteTomEEExtension: " + e.getMessage());
- }
- }
- } finally {
- l.unlock();
+ builder.observer(RemoteInitialContextObserver.class);
+ builder.observer(DeploymentExceptionObserver.class);
+ builder.service(DeployableContainer.class, RemoteTomEEContainer.class)
+ .service(AuxiliaryArchiveAppender.class, RemoteTomEEEJBEnricherArchiveAppender.class)
+ .service(ResourceProvider.class, DeploymentExceptionProvider.class);
+ } catch (final IllegalArgumentException e) {
+ Logger.getLogger(RemoteTomEEExtension.class.getName()).log(Level.WARNING, "RemoteTomEEExtension: " + e.getMessage());
}
}
}
diff --git a/arquillian/arquillian-tomee-remote/src/test/java/org/apache/tomee/arquillian/remote/RemoteTomEEExtensionReRegistrationTest.java b/arquillian/arquillian-tomee-remote/src/test/java/org/apache/tomee/arquillian/remote/RemoteTomEEExtensionReRegistrationTest.java
new file mode 100644
index 0000000000..89a3cccb64
--- /dev/null
+++ b/arquillian/arquillian-tomee-remote/src/test/java/org/apache/tomee/arquillian/remote/RemoteTomEEExtensionReRegistrationTest.java
@@ -0,0 +1,115 @@
+/*
+ * 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.arquillian.remote;
+
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.core.spi.LoadableExtension;
+import org.jboss.arquillian.core.spi.LoadableExtension.ExtensionBuilder;
+import org.jboss.arquillian.core.spi.context.Context;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Reproducer for TOMEE-4631.
+ *
+ * <p>{@link RemoteTomEEExtension} guards container registration behind a JVM-static
+ * {@code AtomicBoolean} latch. {@link LoadableExtension#register(ExtensionBuilder)} is invoked
+ * once per Arquillian {@code Manager} bootstrap. When a second {@code Manager} is bootstrapped in
+ * the same JVM fork (the classic trigger being maven-failsafe-plugin's
+ * {@code rerunFailingTestsCount}, which spins up a fresh {@code Manager} to rerun a failed test),
+ * the static flag is already {@code true}, so the second bootstrap skips
+ * {@code builder.service(DeployableContainer.class, ...)} and that {@code Manager} ends up with an
+ * empty {@code ContainerRegistry}. Deployments then fail with:</p>
+ *
+ * <pre>
+ * org.jboss.arquillian.container.test.impl.client.deployment.ValidationException:
+ * DeploymentScenario contains a target (_DEFAULT_) not matching any defined Container in the
+ * registry. Please include at least 1 Deployable Container on your Classpath.
+ * </pre>
+ *
+ * <p>The sibling {@code EmbeddedTomEEExtension} has no such latch and registers unconditionally,
+ * which is why every other Arquillian adapter survives a rerun and only arquillian-tomee-remote
+ * does not.</p>
+ *
+ * <p>This test drives {@code register(...)} the same way Arquillian's {@code LoadableExtensionLoader}
+ * does (once per simulated {@code Manager} bootstrap, each with its own {@link ExtensionBuilder})
+ * and asserts the {@link DeployableContainer} is registered for every bootstrap, not just the
+ * first. It failed on the former static-latch implementation and guards the unconditional
+ * registration that replaced it.</p>
+ */
+public class RemoteTomEEExtensionReRegistrationTest {
+
+ @Test
+ public void containerIsReRegisteredOnEveryManagerBootstrap() {
+ // 1st Manager bootstrap (e.g. the initial failsafe run)
+ final RecordingExtensionBuilder first = new RecordingExtensionBuilder();
+ new RemoteTomEEExtension().register(first);
+ assertTrue("Sanity: the first Manager bootstrap must register the DeployableContainer",
+ first.registeredDeployableContainer());
+
+ // 2nd Manager bootstrap in the same JVM (e.g. a failsafe rerunFailingTestsCount rerun)
+ final RecordingExtensionBuilder second = new RecordingExtensionBuilder();
+ new RemoteTomEEExtension().register(second);
+
+ // TOMEE-4631: the static latch makes the second bootstrap skip the DeployableContainer
+ // service, leaving the second Manager's ContainerRegistry empty -> _DEFAULT_ matches nothing.
+ assertTrue("TOMEE-4631: a second Arquillian Manager in the same JVM did NOT get a "
+ + "DeployableContainer registered; reruns (e.g. failsafe rerunFailingTestsCount) "
+ + "will fail with 'DeploymentScenario contains a target (_DEFAULT_) not matching "
+ + "any defined Container in the registry'.",
+ second.registeredDeployableContainer());
+ }
+
+ /**
+ * Minimal {@link ExtensionBuilder} that records which service contracts were registered,
+ * standing in for the real builder backed by Arquillian's {@code ServiceRegistry}.
+ */
+ private static final class RecordingExtensionBuilder implements ExtensionBuilder {
+ private final List<Class<?>> services = new ArrayList<>();
+
+ @Override
+ public <T> ExtensionBuilder service(final Class<T> service, final Class<? extends T> impl) {
+ services.add(service);
+ return this;
+ }
+
+ @Override
+ public <T> ExtensionBuilder override(final Class<T> service, final Class<? extends T> oldImpl,
+ final Class<? extends T> newImpl) {
+ return this;
+ }
+
+ @Override
+ public ExtensionBuilder observer(final Class<?> observer) {
+ return this;
+ }
+
+ @Override
+ public ExtensionBuilder context(final Class<? extends Context> context) {
+ return this;
+ }
+
+ boolean registeredDeployableContainer() {
+ return services.contains(DeployableContainer.class);
+ }
+ }
+}