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 fc54354abe TOMEE-4631 - arquillian-tomee-remote: re-register container
on every Manager bootstrap (#2817)
fc54354abe is described below
commit fc54354abe139244ae3dd6a8e1b016e26152a7a3
Author: Richard Zowalla <[email protected]>
AuthorDate: Thu Jul 2 11:53:12 2026 +0200
TOMEE-4631 - arquillian-tomee-remote: re-register container on every
Manager bootstrap (#2817)
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);
+ }
+ }
+}