Skip to content

Commit 8f11cc6

Browse files
committed
Fix usages of some async utilities
1 parent e3ec836 commit 8f11cc6

File tree

5 files changed

+48
-38
lines changed

5 files changed

+48
-38
lines changed

spock-core/src/main/java/org/spockframework/runtime/extension/builtin/RepeatUntilFailureExtension.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,8 @@ public void runIterations(IDataIterator dataIterator, IIterationRunner iteration
3737
dataIterator.forEachRemaining(data::add);
3838
for (int attempt = 0; attempt < maxAttempts; attempt++) {
3939
for (Object[] args : data) {
40-
try {
41-
ExecutionResult executionResult = iterationRunner.runIteration(args, maxIterations).get();
42-
if (executionResult == ExecutionResult.FAILED) {
43-
return;
44-
}
45-
} catch (InterruptedException | ExecutionException e) {
40+
ExecutionResult executionResult = iterationRunner.runIteration(args, maxIterations).join();
41+
if (executionResult == ExecutionResult.FAILED) {
4642
return;
4743
}
4844
}

spock-core/src/main/java/org/spockframework/runtime/extension/builtin/TimeoutInterceptor.java

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -70,33 +70,57 @@ public void run() {
7070
long timeoutAt = 0;
7171
int unsuccessfulInterruptAttempts = 0;
7272

73-
syncWithThread(startLatch, "feature", methodName);
73+
boolean syncedWithFeature = false;
74+
try {
75+
startLatch.countDown();
76+
syncedWithFeature = startLatch.await(5, TimeUnit.SECONDS);
77+
} catch (InterruptedException ignored) {
78+
// this is our own thread, so we can ignore the interruption safely
79+
}
80+
if (!syncedWithFeature) {
81+
System.out.printf("[spock.lang.Timeout] Could not sync with Feature for method '%s'", methodName);
82+
}
7483

84+
while (waitMillis > 0) {
85+
long waitStart = System.nanoTime();
86+
try {
87+
synced = sync.offer(stackTrace, waitMillis, TimeUnit.MILLISECONDS);
88+
} catch (InterruptedException ignored) {
89+
// this is our own thread, so we can ignore the interruption safely and continue the remaining waiting
90+
waitMillis -= TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - waitStart);
91+
continue;
92+
}
93+
break;
94+
}
95+
if (!synced) {
96+
stackTrace = mainThread.getStackTrace();
97+
waitMillis = 250;
98+
}
7599
while (!synced) {
100+
mainThread.interrupt();
76101
try {
77102
synced = sync.offer(stackTrace, waitMillis, TimeUnit.MILLISECONDS);
78103
} catch (InterruptedException ignored) {
79104
// The mission of this thread is to repeatedly interrupt the main thread until
80105
// the latter returns. Once this mission has been accomplished, this thread will die quickly
81106
}
82107
if (!synced) {
83-
long now = System.nanoTime();
84-
if (stackTrace.length == 0) {
85-
logMethodTimeout(methodName, timeoutSeconds);
86-
stackTrace = mainThread.getStackTrace();
87-
waitMillis = 250;
88-
timeoutAt = now;
89-
} else {
90-
waitMillis *= 2;
91-
logUnsuccessfulInterrupt(methodName, now, timeoutAt, waitMillis, ++unsuccessfulInterruptAttempts);
92-
}
93-
mainThread.interrupt();
108+
System.out.printf("[spock.lang.Timeout] Method '%s' has not yet returned - interrupting. Next try in %1.2f seconds.\n",
109+
methodName, waitMillis / 1000.);
94110
}
95111
}
96112
}
97113
}.start();
98114

99-
syncWithThread(startLatch, "watcher", methodName);
115+
boolean syncedWithWatcher = false;
116+
try {
117+
startLatch.countDown();
118+
syncedWithWatcher = startLatch.await(5, TimeUnit.SECONDS);
119+
} finally {
120+
if (!syncedWithWatcher) {
121+
System.out.printf("[spock.lang.Timeout] Could not sync with Watcher for method '%s'", invocation.getMethod().getName());
122+
}
123+
}
100124

101125
Throwable saved = null;
102126
try {
@@ -216,13 +240,4 @@ private static Pair<Integer, Integer> findThreadSection(List<String> lines, Stri
216240

217241
return null;
218242
}
219-
220-
private static void syncWithThread(CountDownLatch startLatch, String threadName, String methodName) {
221-
try {
222-
startLatch.countDown();
223-
startLatch.await(5, TimeUnit.SECONDS);
224-
} catch (InterruptedException ignored) {
225-
System.out.printf("[spock.lang.Timeout] Could not sync with %s thread for method '%s'", threadName, methodName);
226-
}
227-
}
228243
}

spock-core/src/main/java/spock/util/concurrent/AsyncConditions.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,15 +131,14 @@ public void await() throws Throwable {
131131
* @throws Throwable the first exception thrown by an evaluate block
132132
*/
133133
public void await(double seconds) throws Throwable {
134-
latch.await((long) (seconds * 1000), TimeUnit.MILLISECONDS);
134+
boolean evalBlocksFinished = latch.await((long) (seconds * 1000), TimeUnit.MILLISECONDS);
135135
if (!exceptions.isEmpty())
136136
throw exceptions.poll();
137137

138-
long pendingEvalBlocks = latch.getCount();
139-
if (pendingEvalBlocks > 0) {
138+
if (!evalBlocksFinished) {
140139
String msg = String.format("Async conditions timed out " +
141140
"after %1.2f seconds; %d out of %d evaluate blocks did not complete in time",
142-
seconds, pendingEvalBlocks, numEvalBlocks);
141+
seconds, latch.getCount(), numEvalBlocks);
143142
throw new SpockTimeoutError(seconds, msg);
144143
}
145144
}

spock-specs/src/test/groovy/org/spockframework/smoke/extension/ParallelSpec.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ class ParallelSpec extends EmbeddedSpecification {
265265
@ResourceLock(value = "a", mode = ResourceAccessMode.READ)
266266
def writeA() {
267267
when:
268-
incrementAndBlock(atomicInteger, latch)
268+
incrementAndBlock(atomicInteger, latch, 10000)
269269
270270
then:
271271
atomicInteger.get() == 3
@@ -519,15 +519,15 @@ class ParallelSpec extends EmbeddedSpecification {
519519
throws InterruptedException {
520520
int value = sharedResource.incrementAndGet()
521521
countDownLatch.countDown()
522-
countDownLatch.await(timeout, MILLISECONDS)
522+
assert countDownLatch.await(timeout, MILLISECONDS) : 'Timeout expired'
523523
return value
524524
}
525525

526526
static void storeAndBlockAndCheck(AtomicInteger sharedResource, CountDownLatch countDownLatch, long timeout = 100)
527527
throws InterruptedException {
528528
int value = sharedResource.get()
529529
countDownLatch.countDown()
530-
countDownLatch.await(timeout, MILLISECONDS)
530+
assert countDownLatch.await(timeout, MILLISECONDS) : 'Timeout expired'
531531
assert value == sharedResource.get()
532532
}
533533
}

spock-specs/src/test/groovy/org/spockframework/smoke/mock/InvokingMocksFromMultipleThreads.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class InvokingMocksFromMultipleThreads extends Specification {
4242
}
4343
}
4444
}
45-
latch.await(10, TimeUnit.SECONDS)
45+
assert latch.await(10, TimeUnit.SECONDS) : 'Timeout expired'
4646

4747
then:
4848
interaction {
@@ -68,7 +68,7 @@ class InvokingMocksFromMultipleThreads extends Specification {
6868
}
6969
}
7070
}
71-
latch.await(10, TimeUnit.SECONDS)
71+
assert latch.await(10, TimeUnit.SECONDS) : 'Timeout expired'
7272

7373
then:
7474
interaction {
@@ -93,7 +93,7 @@ class InvokingMocksFromMultipleThreads extends Specification {
9393
}
9494
}
9595
}
96-
latch.await(10, TimeUnit.SECONDS)
96+
assert latch.await(10, TimeUnit.SECONDS) : 'Timeout expired'
9797

9898
then:
9999
interaction {

0 commit comments

Comments
 (0)