Skip to content

Commit 979edaa

Browse files
Run all multithreaded tests and print stack trace from all failures (#161)
The multithreaded tests included only an assertion that there weren't any failures as part of each of the individual tests. If any failures would occur, they wouldn't be saved or printed. However, the overall multithreaded test would fail without running the rest of the individual tests. The execution of the tests is changed to return the potential failures, instead of directly failing. Said failures are printed when all threads conclude. All of the individual tests conclude before the overall multithreaded test fails. Signed-off-by: Jason Katonica <katonica@us.ibm.com> Co-authored-by: KostasTsiounis <121899919+KostasTsiounis@users.noreply.github.com>
1 parent e76ac02 commit 979edaa

File tree

2 files changed

+74
-19
lines changed

2 files changed

+74
-19
lines changed

src/test/java/ibm/jceplus/junit/TestMultithread.java

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright IBM Corp. 2023
2+
* Copyright IBM Corp. 2023, 2024
33
*
44
* Licensed under the Apache License 2.0 (the "License"). You may not use
55
* this file except in compliance with the License. You can obtain a copy
@@ -11,12 +11,17 @@
1111
import java.util.ArrayList;
1212
import java.util.Collections;
1313
import java.util.List;
14+
import java.util.concurrent.Callable;
1415
import java.util.concurrent.CountDownLatch;
1516
import java.util.concurrent.ExecutorService;
1617
import java.util.concurrent.Executors;
1718
import java.util.concurrent.TimeUnit;
19+
1820
import org.junit.runner.JUnitCore;
1921
import org.junit.runner.Request;
22+
import org.junit.runner.Result;
23+
import org.junit.runner.notification.Failure;
24+
2025
import junit.framework.Test;
2126
import junit.framework.TestCase;
2227
import junit.framework.TestSuite;
@@ -78,9 +83,11 @@ public class TestMultithread extends TestCase {
7883

7984
public TestMultithread() {}
8085

81-
private void assertConcurrent(final String message, final Runnable runnable,
86+
private boolean assertConcurrent(final String message, final Callable<List<Failure>> callable,
8287
final int maxTimeoutSeconds) throws InterruptedException {
88+
boolean failed = false;
8389
final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
90+
final List<Failure> failures = Collections.synchronizedList(new ArrayList<Failure>());
8491
final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads);
8592
try {
8693
final CountDownLatch allExecutorThreadsReady = new CountDownLatch(numThreads);
@@ -92,7 +99,7 @@ public void run() {
9299
allExecutorThreadsReady.countDown();
93100
try {
94101
afterInitBlocker.await();
95-
runnable.run();
102+
failures.addAll(callable.call());
96103
} catch (final Throwable e) {
97104
exceptions.add(e);
98105
} finally {
@@ -112,10 +119,22 @@ public void run() {
112119
} finally {
113120
threadPool.shutdownNow();
114121
}
115-
assertTrue(message + "failed with exception(s)" + exceptions, exceptions.isEmpty());
122+
if (!exceptions.isEmpty()) {
123+
for (Throwable t : exceptions) {
124+
t.printStackTrace();
125+
}
126+
}
127+
failed = !exceptions.isEmpty();
128+
129+
for (Failure failure : failures) {
130+
failure.getException().printStackTrace();
131+
}
132+
//failed = !failures.isEmpty();
133+
134+
return failed;
116135
}
117136

118-
private Runnable testToRunnable(String classAndMethod) {
137+
private Callable<List<Failure>> testToCallable(String classAndMethod) {
119138
String[] classAndMethodList = classAndMethod.split("#");
120139
try {
121140
Request request = null;
@@ -126,10 +145,10 @@ private Runnable testToRunnable(String classAndMethod) {
126145
request = Request.aClass(Class.forName(classAndMethodList[0]));
127146
}
128147
final Request myrequest = request;
129-
return new Runnable() {
130-
public void run() {
131-
new JUnitCore().run(myrequest);
132-
//assertTrue(result.getFailureCount()== 0);
148+
return new Callable<List<Failure>>() {
149+
public List<Failure> call() {
150+
Result result = new JUnitCore().run(myrequest);
151+
return result.getFailures();
133152
}
134153
};
135154
} catch (ClassNotFoundException ex) {
@@ -141,16 +160,25 @@ public void run() {
141160
public void testMultithread() {
142161
System.out.println("#threads=" + numThreads + " timeout=" + timeoutSec);
143162

163+
List<String> failedTests = new ArrayList<>();
164+
144165
for (String test : testList) {
145166
try {
146167
System.out.println("Test calling: " + test);
147168

148-
assertConcurrent("Test failed: " + test, testToRunnable(test), timeoutSec);
169+
boolean failed = assertConcurrent("Test failed: " + test, testToCallable(test), timeoutSec);
170+
if (failed) {
171+
failedTests.add(test);
172+
}
149173

150174
} catch (InterruptedException e) {
151175
//System.out.println("Test interrupted: " + e);
152176
}
153177
System.out.println("Test finished: " + test);
178+
if (!failedTests.isEmpty()) {
179+
String allFailedTests = String.join("\n\t", failedTests);
180+
fail("Failed tests:\n\t" + allFailedTests);
181+
}
154182
}
155183
}
156184

src/test/java/ibm/jceplus/junit/TestMultithreadFIPS.java

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright IBM Corp. 2023
2+
* Copyright IBM Corp. 2023, 2024
33
*
44
* Licensed under the Apache License 2.0 (the "License"). You may not use
55
* this file except in compliance with the License. You can obtain a copy
@@ -10,13 +10,17 @@
1010
import java.util.ArrayList;
1111
import java.util.Collections;
1212
import java.util.List;
13+
import java.util.concurrent.Callable;
1314
import java.util.concurrent.CountDownLatch;
1415
import java.util.concurrent.ExecutorService;
1516
import java.util.concurrent.Executors;
1617
import java.util.concurrent.TimeUnit;
18+
1719
import org.junit.runner.JUnitCore;
1820
import org.junit.runner.Request;
1921
import org.junit.runner.Result;
22+
import org.junit.runner.notification.Failure;
23+
2024
import junit.framework.Test;
2125
import junit.framework.TestCase;
2226
import junit.framework.TestSuite;
@@ -68,9 +72,11 @@ public class TestMultithreadFIPS extends TestCase {
6872

6973
public TestMultithreadFIPS() {}
7074

71-
private void assertConcurrent(final String message, final Runnable runnable,
75+
private boolean assertConcurrent(final String message, final Callable<List<Failure>> callable,
7276
final int maxTimeoutSeconds) throws InterruptedException {
77+
boolean failed = false;
7378
final List<Throwable> exceptions = Collections.synchronizedList(new ArrayList<Throwable>());
79+
final List<Failure> failures = Collections.synchronizedList(new ArrayList<Failure>());
7480
final ExecutorService threadPool = Executors.newFixedThreadPool(numThreads);
7581
try {
7682
final CountDownLatch allExecutorThreadsReady = new CountDownLatch(numThreads);
@@ -82,7 +88,7 @@ public void run() {
8288
allExecutorThreadsReady.countDown();
8389
try {
8490
afterInitBlocker.await();
85-
runnable.run();
91+
failures.addAll(callable.call());
8692
} catch (final Throwable e) {
8793
exceptions.add(e);
8894
} finally {
@@ -102,10 +108,22 @@ public void run() {
102108
} finally {
103109
threadPool.shutdownNow();
104110
}
105-
assertTrue(message + "failed with exception(s)" + exceptions, exceptions.isEmpty());
111+
if (!exceptions.isEmpty()) {
112+
for (Throwable t : exceptions) {
113+
t.printStackTrace();
114+
}
115+
}
116+
failed = !exceptions.isEmpty();
117+
118+
for (Failure failure : failures) {
119+
failure.getException().printStackTrace();
120+
}
121+
failed = !failures.isEmpty();
122+
123+
return failed;
106124
}
107125

108-
private Runnable testToRunnable(String classAndMethod) {
126+
private Callable<List<Failure>> testToCallable(String classAndMethod) {
109127
String[] classAndMethodList = classAndMethod.split("#");
110128
try {
111129
Request request = null;
@@ -116,10 +134,10 @@ private Runnable testToRunnable(String classAndMethod) {
116134
request = Request.aClass(Class.forName(classAndMethodList[0]));
117135
}
118136
final Request myrequest = request;
119-
return new Runnable() {
120-
public void run() {
137+
return new Callable<List<Failure>>() {
138+
public List<Failure> call() {
121139
Result result = new JUnitCore().run(myrequest);
122-
assertTrue(result.getFailureCount()== 0);
140+
return result.getFailures();
123141
}
124142
};
125143
} catch (ClassNotFoundException ex) {
@@ -131,16 +149,25 @@ public void run() {
131149
public void testMultithreadFIPS() {
132150
System.out.println("#threads=" + numThreads + " timeout=" + timeoutSec);
133151

152+
List<String> failedTests = new ArrayList<>();
153+
134154
for (String test : testList) {
135155
try {
136156
System.out.println("Test calling: " + test);
137157

138-
assertConcurrent("Test failed: " + test, testToRunnable(test), timeoutSec);
158+
boolean failed = assertConcurrent("Test failed: " + test, testToCallable(test), timeoutSec);
159+
if (failed) {
160+
failedTests.add(test);
161+
}
139162

140163
} catch (InterruptedException e) {
141164
//System.out.println("Test interrupted: " + e);
142165
}
143166
System.out.println("Test finished: " + test);
167+
if (!failedTests.isEmpty()) {
168+
String allFailedTests = String.join("\n\t", failedTests);
169+
fail("Failed tests:\n\t" + allFailedTests);
170+
}
144171
}
145172
}
146173

0 commit comments

Comments
 (0)