Skip to content

Commit b196388

Browse files
committed
Add integration test
Issue: #2229 Signed-off-by: yongjunhong <[email protected]>
1 parent f9af925 commit b196388

File tree

2 files changed

+379
-0
lines changed

2 files changed

+379
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
/*
2+
* Copyright 2015-2024 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package org.junit.vintage.engine.execution;
12+
13+
import static org.assertj.core.api.Assertions.assertThat;
14+
import static org.junit.platform.testkit.engine.EventConditions.event;
15+
import static org.junit.platform.testkit.engine.EventConditions.finishedSuccessfully;
16+
import static org.junit.platform.testkit.engine.EventConditions.finishedWithFailure;
17+
import static org.junit.platform.testkit.engine.EventConditions.started;
18+
import static org.junit.platform.testkit.engine.EventConditions.test;
19+
import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.AtomicOperationParallelTestCase;
20+
import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.ConcurrentFailureTestCase;
21+
import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.ConcurrentIncrementTestCase;
22+
import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.FailingParallelTestCase;
23+
import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.ParallelFailingTestCase;
24+
import static org.junit.vintage.engine.samples.junit4.JUnit4ParallelTestCase.SuccessfulParallelTestCase;
25+
26+
import java.time.Instant;
27+
import java.util.Arrays;
28+
import java.util.HashSet;
29+
import java.util.List;
30+
import java.util.Set;
31+
32+
import org.assertj.core.api.Condition;
33+
import org.junit.jupiter.api.Test;
34+
import org.junit.jupiter.api.TestReporter;
35+
import org.junit.platform.engine.discovery.ClassSelector;
36+
import org.junit.platform.engine.discovery.DiscoverySelectors;
37+
import org.junit.platform.launcher.LauncherDiscoveryRequest;
38+
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
39+
import org.junit.platform.testkit.engine.EngineExecutionResults;
40+
import org.junit.platform.testkit.engine.EngineTestKit;
41+
import org.junit.platform.testkit.engine.Event;
42+
import org.junit.platform.testkit.engine.Events;
43+
import org.junit.vintage.engine.VintageTestEngine;
44+
45+
class ParallelExecutionIntegrationTests {
46+
47+
private static final String PARALLEL_EXECUTION_ENABLED = "junit.vintage.execution.parallel.enabled";
48+
private static final String PARALLEL_POOL_SIZE = "junit.vintage.execution.parallel.pool-size";
49+
50+
@Test
51+
void successfulParallelTest(TestReporter reporter) {
52+
var events = executeInParallelSuccessfully(3, SuccessfulParallelTestCase.class,
53+
ConcurrentIncrementTestCase.class, AtomicOperationParallelTestCase.class).list();
54+
55+
var startedTimestamps = getTimestampsFor(events, event(test(), started()));
56+
var finishedTimestamps = getTimestampsFor(events, event(test(), finishedSuccessfully()));
57+
var threadNames = new HashSet<>(Set.of(SuccessfulParallelTestCase.threadNames,
58+
ConcurrentIncrementTestCase.threadNames, AtomicOperationParallelTestCase.threadNames));
59+
60+
reporter.publishEntry("startedTimestamps", startedTimestamps.toString());
61+
reporter.publishEntry("finishedTimestamps", finishedTimestamps.toString());
62+
63+
assertThat(startedTimestamps).hasSize(9);
64+
assertThat(finishedTimestamps).hasSize(9);
65+
assertThat(threadNames).hasSize(3);
66+
}
67+
68+
@Test
69+
void failingParallelTest(TestReporter reporter) {
70+
var events = executeInParallel(3, FailingParallelTestCase.class, ConcurrentFailureTestCase.class,
71+
ParallelFailingTestCase.class).list();
72+
73+
var startedTimestamps = getTimestampsFor(events, event(test(), started()));
74+
var finishedTimestamps = getTimestampsFor(events, event(test(), finishedWithFailure()));
75+
var threadNames = new HashSet<>(Set.of(FailingParallelTestCase.threadNames,
76+
ConcurrentFailureTestCase.threadNames, ParallelFailingTestCase.threadNames));
77+
78+
reporter.publishEntry("startedTimestamps", startedTimestamps.toString());
79+
reporter.publishEntry("finishedTimestamps", finishedTimestamps.toString());
80+
81+
assertThat(startedTimestamps).hasSize(9);
82+
assertThat(finishedTimestamps).hasSize(9);
83+
assertThat(threadNames).hasSize(3);
84+
}
85+
86+
private List<Instant> getTimestampsFor(List<Event> events, Condition<Event> condition) {
87+
// @formatter:off
88+
return events.stream()
89+
.filter(condition::matches)
90+
.map(Event::getTimestamp)
91+
.toList();
92+
// @formatter:on
93+
}
94+
95+
private Events executeInParallelSuccessfully(int poolSize, Class<?>... testClasses) {
96+
var events = execute(poolSize, testClasses).allEvents();
97+
try {
98+
return events.assertStatistics(it -> it.failed(0));
99+
}
100+
catch (AssertionError error) {
101+
events.debug();
102+
throw error;
103+
}
104+
}
105+
106+
private Events executeInParallel(int poolSize, Class<?>... testClasses) {
107+
return execute(poolSize, testClasses).allEvents();
108+
}
109+
110+
private static EngineExecutionResults execute(int poolSize, Class<?>... testClass) {
111+
return EngineTestKit.execute(new VintageTestEngine(), request(poolSize, testClass));
112+
}
113+
114+
private static LauncherDiscoveryRequest request(int poolSize, Class<?>... testClasses) {
115+
var classSelectors = Arrays.stream(testClasses) //
116+
.map(DiscoverySelectors::selectClass) //
117+
.toArray(ClassSelector[]::new);
118+
119+
return LauncherDiscoveryRequestBuilder.request().selectors(classSelectors).configurationParameter(
120+
PARALLEL_EXECUTION_ENABLED, String.valueOf(true)).configurationParameter(PARALLEL_POOL_SIZE,
121+
String.valueOf(poolSize)).build();
122+
}
123+
124+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
/*
2+
* Copyright 2015-2024 the original author or authors.
3+
*
4+
* All rights reserved. This program and the accompanying materials are
5+
* made available under the terms of the Eclipse Public License v2.0 which
6+
* accompanies this distribution and is available at
7+
*
8+
* https://www.eclipse.org/legal/epl-v20.html
9+
*/
10+
11+
package org.junit.vintage.engine.samples.junit4;
12+
13+
import static java.util.concurrent.TimeUnit.MILLISECONDS;
14+
import static org.junit.Assert.fail;
15+
16+
import java.util.HashSet;
17+
import java.util.Set;
18+
import java.util.concurrent.CountDownLatch;
19+
import java.util.concurrent.atomic.AtomicInteger;
20+
21+
import org.junit.BeforeClass;
22+
import org.junit.Rule;
23+
import org.junit.Test;
24+
import org.junit.experimental.runners.Enclosed;
25+
import org.junit.rules.TestWatcher;
26+
import org.junit.runner.Description;
27+
import org.junit.runner.RunWith;
28+
29+
@RunWith(Enclosed.class)
30+
public class JUnit4ParallelTestCase {
31+
32+
public static class SuccessfulParallelTestCase {
33+
public static Set<String> threadNames;
34+
static AtomicInteger sharedResource;
35+
static CountDownLatch countDownLatch;
36+
37+
@Rule
38+
public final TestWatcher testWatcher = new TestWatcher() {
39+
@Override
40+
protected void starting(Description description) {
41+
super.starting(description);
42+
threadNames.add(Thread.currentThread().getName());
43+
}
44+
};
45+
46+
@BeforeClass
47+
public static void initialize() {
48+
sharedResource = new AtomicInteger();
49+
countDownLatch = new CountDownLatch(3);
50+
threadNames = new HashSet<>();
51+
}
52+
53+
@Test
54+
public void firstTest() throws Exception {
55+
incrementAndBlock(sharedResource, countDownLatch);
56+
}
57+
58+
@Test
59+
public void secondTest() throws Exception {
60+
incrementAndBlock(sharedResource, countDownLatch);
61+
}
62+
63+
@Test
64+
public void thirdTest() throws Exception {
65+
incrementAndBlock(sharedResource, countDownLatch);
66+
}
67+
}
68+
69+
public static class ConcurrentIncrementTestCase {
70+
public static Set<String> threadNames;
71+
static AtomicInteger sharedResource;
72+
static CountDownLatch countDownLatch;
73+
74+
@Rule
75+
public final TestWatcher testWatcher = new TestWatcher() {
76+
@Override
77+
protected void starting(Description description) {
78+
super.starting(description);
79+
threadNames.add(Thread.currentThread().getName());
80+
}
81+
};
82+
83+
@BeforeClass
84+
public static void initialize() {
85+
sharedResource = new AtomicInteger();
86+
countDownLatch = new CountDownLatch(3);
87+
threadNames = new HashSet<>();
88+
}
89+
90+
@Test
91+
public void firstTest() throws Exception {
92+
incrementAndBlock(sharedResource, countDownLatch);
93+
}
94+
95+
@Test
96+
public void secondTest() throws Exception {
97+
incrementAndBlock(sharedResource, countDownLatch);
98+
}
99+
100+
@Test
101+
public void thirdTest() throws Exception {
102+
incrementAndBlock(sharedResource, countDownLatch);
103+
}
104+
}
105+
106+
public static class AtomicOperationParallelTestCase {
107+
public static Set<String> threadNames;
108+
static AtomicInteger sharedResource;
109+
static CountDownLatch countDownLatch;
110+
111+
@Rule
112+
public final TestWatcher testWatcher = new TestWatcher() {
113+
@Override
114+
protected void starting(Description description) {
115+
super.starting(description);
116+
threadNames.add(Thread.currentThread().getName());
117+
}
118+
};
119+
120+
@BeforeClass
121+
public static void initialize() {
122+
sharedResource = new AtomicInteger();
123+
countDownLatch = new CountDownLatch(3);
124+
threadNames = new HashSet<>();
125+
}
126+
127+
@Test
128+
public void firstTest() throws Exception {
129+
incrementAndBlock(sharedResource, countDownLatch);
130+
}
131+
132+
@Test
133+
public void secondTest() throws Exception {
134+
incrementAndBlock(sharedResource, countDownLatch);
135+
}
136+
137+
@Test
138+
public void thirdTest() throws Exception {
139+
incrementAndBlock(sharedResource, countDownLatch);
140+
}
141+
}
142+
143+
public static class FailingParallelTestCase {
144+
public static Set<String> threadNames;
145+
146+
@Rule
147+
public final TestWatcher testWatcher = new TestWatcher() {
148+
@Override
149+
protected void starting(Description description) {
150+
super.starting(description);
151+
threadNames.add(Thread.currentThread().getName());
152+
}
153+
};
154+
155+
@BeforeClass
156+
public static void initialize() {
157+
threadNames = new HashSet<>();
158+
}
159+
160+
@Test
161+
public void firstTest() {
162+
fail("failing test");
163+
}
164+
165+
@Test
166+
public void secondTest() {
167+
fail("failing test");
168+
}
169+
170+
@Test
171+
public void thirdTest() {
172+
fail("failing test");
173+
}
174+
}
175+
176+
public static class ConcurrentFailureTestCase {
177+
public static Set<String> threadNames;
178+
179+
@Rule
180+
public final TestWatcher testWatcher = new TestWatcher() {
181+
@Override
182+
protected void starting(Description description) {
183+
super.starting(description);
184+
threadNames.add(Thread.currentThread().getName());
185+
}
186+
};
187+
188+
@BeforeClass
189+
public static void initialize() {
190+
threadNames = new HashSet<>();
191+
}
192+
193+
@Test
194+
public void firstTest() {
195+
fail("failing test");
196+
}
197+
198+
@Test
199+
public void secondTest() {
200+
fail("failing test");
201+
}
202+
203+
@Test
204+
public void thirdTest() {
205+
fail("failing test");
206+
}
207+
}
208+
209+
public static class ParallelFailingTestCase {
210+
public static Set<String> threadNames;
211+
212+
@Rule
213+
public final TestWatcher testWatcher = new TestWatcher() {
214+
@Override
215+
protected void starting(Description description) {
216+
super.starting(description);
217+
threadNames.add(Thread.currentThread().getName());
218+
}
219+
};
220+
221+
@BeforeClass
222+
public static void initialize() {
223+
threadNames = new HashSet<>();
224+
}
225+
226+
@Test
227+
public void firstTest() {
228+
fail("failing test");
229+
}
230+
231+
@Test
232+
public void secondTest() {
233+
fail("failing test");
234+
}
235+
236+
@Test
237+
public void thirdTest() {
238+
fail("failing test");
239+
}
240+
}
241+
242+
@SuppressWarnings("ResultOfMethodCallIgnored")
243+
private static int incrementAndBlock(AtomicInteger sharedResource, CountDownLatch countDownLatch)
244+
throws InterruptedException {
245+
var value = sharedResource.incrementAndGet();
246+
countDownLatch.countDown();
247+
countDownLatch.await(estimateSimulatedTestDurationInMiliseconds(), MILLISECONDS);
248+
return value;
249+
}
250+
251+
private static long estimateSimulatedTestDurationInMiliseconds() {
252+
var runningInCi = Boolean.parseBoolean(System.getenv("CI"));
253+
return runningInCi ? 1000 : 100;
254+
}
255+
}

0 commit comments

Comments
 (0)