Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.asset.StringAsset;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.extension.ExtendWith;

Expand All @@ -31,7 +30,6 @@
import static org.jboss.arquillian.integration.test.lifecycle.FileWriterExtension.getTmpFilePath;
import static org.jboss.arquillian.integration.test.lifecycle.FileWriterExtension.RunsWhere.SERVER;

@Disabled("https://github.com/arquillian/arquillian-core/issues/771")
@ExtendWith(FileWriterExtension.class)
@ArquillianTest
@ExpectedTrace("repeated_test,repeated_test,repeated_test")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,12 @@

import java.lang.reflect.Method;

import org.jboss.arquillian.junit5.extension.RunModeEvent;
import org.jboss.arquillian.test.spi.LifecycleMethodExecutor;
import org.jboss.arquillian.test.spi.TestMethodExecutor;
import org.jboss.arquillian.test.spi.TestResult;
import org.jboss.arquillian.test.spi.TestRunnerAdaptor;
import org.jboss.arquillian.test.spi.event.suite.TestLifecycleEvent;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.platform.launcher.listeners.TestExecutionSummary;
Expand All @@ -44,6 +46,13 @@ protected void executeAllLifeCycles(TestRunnerAdaptor adaptor) throws Exception
doAnswer(new ExecuteLifecycle()).when(adaptor).before(any(Object.class), any(Method.class), any(LifecycleMethodExecutor.class));
doAnswer(new ExecuteLifecycle()).when(adaptor).after(any(Object.class), any(Method.class), any(LifecycleMethodExecutor.class));
doAnswer(new TestExecuteLifecycle()).when(adaptor).test(any(TestMethodExecutor.class));
doAnswer(invocation -> {
TestLifecycleEvent event = invocation.getArgument(0);
if (event instanceof RunModeEvent) {
((RunModeEvent) event).setRunAsClient(false);
Comment thread
rhusar marked this conversation as resolved.
}
return null;
}).when(adaptor).fireCustomLifecycle(any(TestLifecycleEvent.class));
}

@Test
Expand All @@ -55,12 +64,29 @@ public void shouldExecuteRepeatedTestExactlyThreeTimes() throws Exception {
// when
TestExecutionSummary result = run(adaptor, ClassWithArquillianExtensionAndRepeatedTest.class);

// then — @RepeatedTest(3) must run exactly 3 times, not 9
Assertions.assertEquals(3, result.getTestsSucceededCount());
// then — @RepeatedTest(3) must invoke SPI lifecycle exactly 3 times, not 9
Assertions.assertEquals(0, result.getTestsFailedCount());
Assertions.assertEquals(0, result.getTestsSkippedCount());
assertCycle(1, Cycle.BEFORE_CLASS, Cycle.AFTER_CLASS);
assertCycle(3, Cycle.BEFORE, Cycle.TEST, Cycle.AFTER);
verify(adaptor, times(1)).beforeClass(any(Class.class), any(LifecycleMethodExecutor.class));
verify(adaptor, times(1)).afterClass(any(Class.class), any(LifecycleMethodExecutor.class));
verify(adaptor, times(3)).before(any(Object.class), any(Method.class), any(LifecycleMethodExecutor.class));
verify(adaptor, times(3)).after(any(Object.class), any(Method.class), any(LifecycleMethodExecutor.class));
verify(adaptor, times(1)).test(any(TestMethodExecutor.class));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would the test only be executed once? Maybe I don't understand this test framework though.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jamezp Good question, my understanding is that in container mode - which was the reason why the test was passing before as it was in the client mode - adaptor.test() sends the test to the container via the ARQ protocol. The container executes the test method remotely - once.

So what is the alternative - the client side would call adaptor.test() for each of the 3 repetitions, and the container would execute just the method body once per call and NOT expand to the @RepeatedTest template. The problem we have now is that both are expanding so we do get N*N.

}

@Test
public void shouldReportFailuresForAllRepetitions() throws Exception {
// given
TestRunnerAdaptor adaptor = mock(TestRunnerAdaptor.class);
executeAllLifeCycles(adaptor);
doAnswer(invocation -> TestResult.failed(new AssertionError("expected failure")))
.when(adaptor).test(any(TestMethodExecutor.class));

// when
TestExecutionSummary result = run(adaptor, ClassWithArquillianExtensionAndRepeatedTest.class);

// then — all 3 repetitions must report as failed
Assertions.assertEquals(3, result.getTestsFailedCount());
verify(adaptor, times(1)).test(any(TestMethodExecutor.class));
}

public static class TestExecuteLifecycle extends ExecuteLifecycle {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ public void interceptTestTemplateMethod(Invocation<Void> invocation, ReflectiveI
// Run as container (but only once)
if (!contextStore.isRegisteredTemplate(invocationContext.getExecutable())) {
result = interceptInvocation(invocation, extensionContext);
contextStore.registerTemplateResult(invocationContext.getExecutable(), result);
} else {
invocation.skip();
result = contextStore.getRegisteredTemplateResult(invocationContext.getExecutable());
}
}
throwError(result);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.lang.reflect.Method;

import org.jboss.arquillian.test.spi.TestResult;
import org.junit.jupiter.api.extension.ExtensionContext;

class ContextStore {
Expand All @@ -26,17 +27,20 @@ ExtensionContext.Store getRootStore() {
}

private ExtensionContext.Store getTemplateStore() {
return context.getStore(ExtensionContext.Namespace.create(NAMESPACE_KEY, INTERCEPTED_TEMPLATE_NAMESPACE_KEY));
ExtensionContext templateContext = context.getParent().orElse(context);
return templateContext.getStore(ExtensionContext.Namespace.create(NAMESPACE_KEY, INTERCEPTED_TEMPLATE_NAMESPACE_KEY));
}

boolean isRegisteredTemplate(Method method) {
final ExtensionContext.Store templateStore = getTemplateStore();
return getTemplateStore().get(method.toGenericString()) != null;
}

void registerTemplateResult(Method method, TestResult result) {
getTemplateStore().put(method.toGenericString(), result != null ? result : TestResult.passed());
}

final boolean isRegistered = templateStore.getOrDefault(method.toGenericString(), boolean.class, false);
if (!isRegistered) {
templateStore.put(method.toGenericString(), true);
}
return isRegistered;
TestResult getRegisteredTemplateResult(Method method) {
return getTemplateStore().get(method.toGenericString(), TestResult.class);
}

/**
Expand Down
Loading