Skip to content

Commit 941a36e

Browse files
authored
Merge pull request #114 from vert-x3/fix-checkpoint-flagging-reporting
Fix bad reporting of excessive flagging
2 parents 504b7bb + 63f346c commit 941a36e

File tree

10 files changed

+119
-81
lines changed

10 files changed

+119
-81
lines changed

src/main/asciidoc/index.adoc

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ Here is a very basic usage:
3939
----
4040
{@link examples.Examples.BTest}
4141
----
42+
4243
<1> {@link io.vertx.junit5.VertxTestContext#succeedingThenComplete} returns an asynchronous result handler that is expected to succeed and then make the test context pass.
4344
<2> {@link io.vertx.junit5.VertxTestContext#awaitCompletion} has the semantics of a `java.util.concurrent.CountDownLatch`, and returns `false` if the waiting delay expired before the test passed.
4445
<3> If the context captures a (potentially asynchronous) error, then after completion we must throw the failure exception to make the test fail.
@@ -98,7 +99,8 @@ The Vert.x integration is primarily done using the {@link io.vertx.junit5.VertxE
9899
{@link examples.Examples.CTest.SomeTest}
99100
----
100101

101-
NOTE: The `Vertx` instance is not clustered and has the default configuration. If you need something else then just don't use injection on that parameter and prepare a `Vertx` object by yourself.
102+
NOTE: The `Vertx` instance is not clustered and has the default configuration.
103+
If you need something else then just don't use injection on that parameter and prepare a `Vertx` object by yourself.
102104

103105
The test is automatically wrapped around the {@link io.vertx.junit5.VertxTestContext} instance lifecycle, so you don't need to insert {@link io.vertx.junit5.VertxTestContext#awaitCompletion} calls yourself:
104106

@@ -151,8 +153,10 @@ Generally-speaking, we respect the JUnit extension scoping rules, but here are t
151153

152154
==== Configuring `Vertx` instances
153155

154-
By default the `Vertx` objects get created with `Vertx.vertx()`, using the default settings for `Vertx`. However you have the ability to configure `VertxOptions` to suit your needs.
155-
A typical use case would be "extending blocking timeout warning for debugging". To configure the `Vertx` object you must:
156+
By default the `Vertx` objects get created with `Vertx.vertx()`, using the default settings for `Vertx`.
157+
However you have the ability to configure `VertxOptions` to suit your needs.
158+
A typical use case would be "extending blocking timeout warning for debugging".
159+
To configure the `Vertx` object you must:
156160

157161
1. create a json file with the `VertxOptions` in https://vertx.io/docs/apidocs/io/vertx/core/VertxOptions.html#VertxOptions-io.vertx.core.json.JsonObject-[json format]
158162
2. create an environment variable `vertx.parameter.filename` pointing to that file
@@ -183,7 +187,8 @@ JUnit 5 allows multiple methods to exist for the same lifecycle events.
183187
As an example, it is possible to define 3 `@BeforeEach` methods on the same test.
184188
Because of asynchronous operations it is possible that the effects of these methods happen concurrently rather than sequentially, which may lead to inconsistent states.
185189

186-
This is a problem of JUnit 5 rather than this module. In case of doubt you may always wonder why a single method can't be better than many.
190+
This is a problem of JUnit 5 rather than this module.
191+
In case of doubt you may always wonder why a single method can't be better than many.
187192

188193
== Support for additional parameter types
189194

@@ -217,15 +222,15 @@ In any case it is a good idea to have the `Vertx` parameter first, and the next
217222

218223
== Parameterized tests with `@MethodSource`
219224

220-
You can use parameterized tests with `@MethodSource` with vertx-junit5. Therefore you need to declare the method source parameters before the vertx test parameters in
221-
the method definition.
225+
You can use parameterized tests with `@MethodSource` with vertx-junit5. Therefore you need to declare the method source parameters before the vertx test parameters in the method definition.
222226

223227
[source,java]
224228
----
225229
{@link examples.Examples.PTest.SomeTest}
226230
----
227231

228-
The same holds for the other `ArgumentSources`. See the section `Formal Parameter List` in the API doc of
232+
The same holds for the other `ArgumentSources`.
233+
See the section `Formal Parameter List` in the API doc of
229234
https://junit.org/junit5/docs/current/api/org.junit.jupiter.params/org/junit/jupiter/params/ParameterizedTest.html[ParameterizedTest]
230235

231236
== Running tests on a Vert.x context

src/main/java/examples/Examples.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
import org.junit.jupiter.api.Test;
3232
import org.junit.jupiter.api.extension.ExtendWith;
3333
import org.junit.jupiter.params.ParameterizedTest;
34-
import org.junit.jupiter.params.provider.MethodSource;
3534
import org.junit.jupiter.params.provider.Arguments;
35+
import org.junit.jupiter.params.provider.MethodSource;
3636

3737
import java.util.concurrent.TimeUnit;
3838
import java.util.stream.Stream;
@@ -243,7 +243,7 @@ static Stream<Arguments> testData() {
243243

244244
@ParameterizedTest
245245
@MethodSource("testData")
246-
void test2(String obj, int count, Vertx vertx, VertxTestContext testContext) {
246+
void test2(String obj, int count, Vertx vertx, VertxTestContext testContext) {
247247
// your test code
248248
testContext.completeNow();
249249
}

src/main/java/examples/RunTestOnContextExampleTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818

1919
import io.vertx.core.Vertx;
2020
import io.vertx.junit5.RunTestOnContext;
21+
import io.vertx.junit5.VertxExtension;
2122
import io.vertx.junit5.VertxTestContext;
2223
import org.junit.jupiter.api.AfterEach;
2324
import org.junit.jupiter.api.BeforeEach;
2425
import org.junit.jupiter.api.Test;
26+
import org.junit.jupiter.api.extension.ExtendWith;
2527
import org.junit.jupiter.api.extension.RegisterExtension;
2628

29+
@ExtendWith(VertxExtension.class)
2730
class RunTestOnContextExampleTest {
2831

2932
@RegisterExtension

src/main/java/io/vertx/junit5/Checkpoint.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919
/**
2020
* A test completion checkpoint, flagging it advances towards the test context completion.
2121
*
22-
* @see VertxTestContext
2322
* @author <a href="https://julien.ponge.org/">Julien Ponge</a>
23+
* @see VertxTestContext
2424
*/
2525
public interface Checkpoint {
2626

src/main/java/io/vertx/junit5/VertxParameterProvider.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616

1717
package io.vertx.junit5;
1818

19-
import static io.vertx.junit5.VertxExtension.DEFAULT_TIMEOUT_DURATION;
20-
import static io.vertx.junit5.VertxExtension.DEFAULT_TIMEOUT_UNIT;
19+
import io.vertx.core.Vertx;
20+
import io.vertx.core.VertxException;
21+
import io.vertx.core.VertxOptions;
22+
import io.vertx.core.json.JsonObject;
23+
import org.junit.jupiter.api.extension.ExtensionContext;
24+
import org.junit.jupiter.api.extension.ParameterContext;
2125

2226
import java.io.IOException;
2327
import java.nio.charset.StandardCharsets;
@@ -29,13 +33,8 @@
2933
import java.util.concurrent.atomic.AtomicReference;
3034
import java.util.stream.Collectors;
3135

32-
import org.junit.jupiter.api.extension.ExtensionContext;
33-
import org.junit.jupiter.api.extension.ParameterContext;
34-
35-
import io.vertx.core.Vertx;
36-
import io.vertx.core.VertxException;
37-
import io.vertx.core.VertxOptions;
38-
import io.vertx.core.json.JsonObject;
36+
import static io.vertx.junit5.VertxExtension.DEFAULT_TIMEOUT_DURATION;
37+
import static io.vertx.junit5.VertxExtension.DEFAULT_TIMEOUT_UNIT;
3938

4039
public class VertxParameterProvider implements VertxExtensionParameterProvider<Vertx> {
4140

src/main/java/io/vertx/junit5/VertxTestContext.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public interface ExecutionBlock {
5050
// ........................................................................................... //
5151

5252
private Throwable throwableReference = null;
53+
private boolean done = false;
5354
private final CountDownLatch releaseLatch = new CountDownLatch(1);
5455
private final HashSet<CountingCheckpoint> checkpoints = new HashSet<>();
5556

@@ -79,7 +80,7 @@ public synchronized Throwable causeOfFailure() {
7980
* @return {@code true} if the context has completed, {@code false} otherwise.
8081
*/
8182
public synchronized boolean completed() {
82-
return !failed() && releaseLatch.getCount() == 0;
83+
return !failed() && (done || releaseLatch.getCount() == 0);
8384
}
8485

8586
/**
@@ -101,6 +102,7 @@ public Set<StackTraceElement> unsatisfiedCheckpointCallSites() {
101102
* Complete the test context immediately, making the corresponding test pass.
102103
*/
103104
public synchronized void completeNow() {
105+
done = true;
104106
releaseLatch.countDown();
105107
}
106108

@@ -111,7 +113,7 @@ public synchronized void completeNow() {
111113
*/
112114
public synchronized void failNow(Throwable t) {
113115
Objects.requireNonNull(t, "The exception cannot be null");
114-
if (!completed()) {
116+
if (throwableReference == null) {
115117
throwableReference = t;
116118
releaseLatch.countDown();
117119
}
@@ -120,7 +122,7 @@ public synchronized void failNow(Throwable t) {
120122
/**
121123
* Calls {@link #failNow(Throwable)} with the {@code message}.
122124
*
123-
* @param message the cause of failure
125+
* @param message the cause of failure
124126
*/
125127
public synchronized void failNow(String message) {
126128
failNow(new NoStackTraceThrowable(message));
@@ -185,8 +187,8 @@ public synchronized Checkpoint checkpoint(int requiredNumberOfPasses) {
185187
* @param <T> the asynchronous result type.
186188
* @return the handler.
187189
* @deprecated Use {@link #succeedingThenComplete()} or {@link #succeeding(Handler)}, for example
188-
* <code>succeeding(value -> checkpoint.flag())</code>, <code>succeeding(value -> { more testing code })</code>, or
189-
* <code>succeeding(value -> {})</code>.
190+
* <code>succeeding(value -> checkpoint.flag())</code>, <code>succeeding(value -> { more testing code })</code>, or
191+
* <code>succeeding(value -> {})</code>.
190192
*/
191193
@Deprecated
192194
public <T> Handler<AsyncResult<T>> succeeding() {
@@ -225,8 +227,8 @@ public <T> Handler<AsyncResult<T>> succeeding(Handler<T> nextHandler) {
225227
* @param <T> the asynchronous result type.
226228
* @return the handler.
227229
* @deprecated Use {@link #failingThenComplete()} or {@link #failing(Handler)}, for example
228-
* <code>failing(e -> checkpoint.flag())</code>, <code>failing(e -> { more testing code })</code>, or
229-
* <code>failing(e -> {})</code>.
230+
* <code>failing(e -> checkpoint.flag())</code>, <code>failing(e -> { more testing code })</code>, or
231+
* <code>failing(e -> {})</code>.
230232
*/
231233
@Deprecated
232234
public <T> Handler<AsyncResult<T>> failing() {

src/test/java/io/vertx/junit5/AsyncBeforeEachTest.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,11 @@
1919
import org.junit.jupiter.api.BeforeEach;
2020
import org.junit.jupiter.api.DisplayName;
2121
import org.junit.jupiter.api.RepeatedTest;
22-
import org.junit.jupiter.api.Test;
2322
import org.junit.jupiter.api.extension.ExtendWith;
2423

2524
import java.util.concurrent.atomic.AtomicInteger;
2625

2726
import static org.junit.jupiter.api.Assertions.assertEquals;
28-
import static org.junit.jupiter.api.Assertions.assertFalse;
2927
import static org.junit.jupiter.api.Assertions.assertTrue;
3028

3129
@ExtendWith(VertxExtension.class)

src/test/java/io/vertx/junit5/VertxExtensionTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,40 @@ void doNothing(VertxTestContext testContext) {
214214
}
215215
}
216216

217+
@Nested
218+
@ExtendWith(VertxExtension.class)
219+
@DisplayName("🚫")
220+
class TooMuchFlagging {
221+
222+
@Test
223+
@Tag("programmatic")
224+
void flagTooMuch(VertxTestContext testContext) {
225+
Checkpoint checkpoint = testContext.checkpoint(3);
226+
for (int i = 0; i < 10; i++) {
227+
checkpoint.flag();
228+
}
229+
}
230+
}
231+
232+
@Test
233+
@DisplayName("⚙️ Check that too much flagging fails tests")
234+
void checkTooMuchFlaggingFails() {
235+
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
236+
.selectors(selectClass(EmbeddedWithARunner.TooMuchFlagging.class))
237+
.build();
238+
Launcher launcher = LauncherFactory.create();
239+
SummaryGeneratingListener listener = new SummaryGeneratingListener();
240+
launcher.registerTestExecutionListeners(listener);
241+
launcher.execute(request);
242+
TestExecutionSummary summary = listener.getSummary();
243+
assertThat(summary.getTestsStartedCount()).isEqualTo(1);
244+
assertThat(summary.getTestsFailedCount()).isEqualTo(1);
245+
Throwable exception = summary.getFailures().get(0).getException();
246+
assertThat(exception)
247+
.isInstanceOf(IllegalStateException.class)
248+
.hasMessage("Strict checkpoint flagged too many times");
249+
}
250+
217251
@Test
218252
@DisplayName("⚙️ Check a timeout diagnosis")
219253
void checkTimeoutFailureTestWithIntermediateAsyncVerifier() {

src/test/java/io/vertx/junit5/VertxParameterProviderTest.java

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,68 +16,67 @@
1616

1717
package io.vertx.junit5;
1818

19-
import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable;
20-
import static org.junit.jupiter.api.Assertions.assertEquals;
19+
import io.vertx.core.json.JsonObject;
20+
import org.junit.jupiter.api.DisplayName;
21+
import org.junit.jupiter.api.Test;
2122

2223
import java.io.BufferedWriter;
2324
import java.io.File;
2425
import java.io.FileWriter;
2526

26-
import org.junit.jupiter.api.DisplayName;
27-
import org.junit.jupiter.api.Test;
28-
29-
import io.vertx.core.json.JsonObject;
27+
import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable;
28+
import static org.junit.jupiter.api.Assertions.assertEquals;
3029

3130
/**
3231
* @author <a href="https://wissel.net/">Stephan Wisssel</a>
3332
*/
3433
@DisplayName("Test of VertxParameterProvider")
3534
public class VertxParameterProviderTest {
3635

37-
@Test
38-
@DisplayName("Default case - empty VertxOptions")
39-
void default_empty_options() {
40-
VertxParameterProvider provider = new VertxParameterProvider();
41-
JsonObject expected = new JsonObject();
42-
JsonObject actual = provider.getVertxOptions();
43-
assertEquals(expected.encode(), actual.encode(), "Options should be equally empty but are not");
44-
}
36+
@Test
37+
@DisplayName("Default case - empty VertxOptions")
38+
void default_empty_options() {
39+
VertxParameterProvider provider = new VertxParameterProvider();
40+
JsonObject expected = new JsonObject();
41+
JsonObject actual = provider.getVertxOptions();
42+
assertEquals(expected.encode(), actual.encode(), "Options should be equally empty but are not");
43+
}
4544

46-
@Test
47-
@DisplayName("Failed retrieval of options")
48-
void failed_retrieval_of_options() throws Exception {
49-
VertxParameterProvider provider = new VertxParameterProvider();
50-
final JsonObject expected = new JsonObject();
51-
final JsonObject actual = new JsonObject();
45+
@Test
46+
@DisplayName("Failed retrieval of options")
47+
void failed_retrieval_of_options() throws Exception {
48+
VertxParameterProvider provider = new VertxParameterProvider();
49+
final JsonObject expected = new JsonObject();
50+
final JsonObject actual = new JsonObject();
5251

53-
withEnvironmentVariable(VertxParameterProvider.VERTX_PARAMETER_FILENAME, "something.that.does.not.exist.json")
54-
.execute(() -> {
55-
actual.mergeIn(provider.getVertxOptions());
56-
});
52+
withEnvironmentVariable(VertxParameterProvider.VERTX_PARAMETER_FILENAME, "something.that.does.not.exist.json")
53+
.execute(() -> {
54+
actual.mergeIn(provider.getVertxOptions());
55+
});
5756

58-
assertEquals(expected.encode(), actual.encode(), "Options retrival failure not handled");
59-
}
57+
assertEquals(expected.encode(), actual.encode(), "Options retrival failure not handled");
58+
}
6059

61-
@Test
62-
@DisplayName("Retrieval of options")
63-
void retrieval_of_options() throws Exception {
64-
VertxParameterProvider provider = new VertxParameterProvider();
65-
final JsonObject expected = new JsonObject().put("BlockedThreadCheckInterval", 120).put("MaxWorkerExecuteTime",
66-
42);
67-
final JsonObject actual = new JsonObject();
68-
// Create a temp file and populate it with our expected values
69-
File tempOptionFile = File.createTempFile("VertxOptions-", ".json");
70-
tempOptionFile.deleteOnExit();
71-
BufferedWriter writer = new BufferedWriter(new FileWriter(tempOptionFile.getAbsolutePath()));
72-
writer.write(expected.encode());
73-
writer.close();
60+
@Test
61+
@DisplayName("Retrieval of options")
62+
void retrieval_of_options() throws Exception {
63+
VertxParameterProvider provider = new VertxParameterProvider();
64+
final JsonObject expected = new JsonObject().put("BlockedThreadCheckInterval", 120).put("MaxWorkerExecuteTime",
65+
42);
66+
final JsonObject actual = new JsonObject();
67+
// Create a temp file and populate it with our expected values
68+
File tempOptionFile = File.createTempFile("VertxOptions-", ".json");
69+
tempOptionFile.deleteOnExit();
70+
BufferedWriter writer = new BufferedWriter(new FileWriter(tempOptionFile.getAbsolutePath()));
71+
writer.write(expected.encode());
72+
writer.close();
7473

75-
withEnvironmentVariable(VertxParameterProvider.VERTX_PARAMETER_FILENAME, tempOptionFile.getAbsolutePath())
76-
.execute(() -> {
77-
actual.mergeIn(provider.getVertxOptions());
78-
});
74+
withEnvironmentVariable(VertxParameterProvider.VERTX_PARAMETER_FILENAME, tempOptionFile.getAbsolutePath())
75+
.execute(() -> {
76+
actual.mergeIn(provider.getVertxOptions());
77+
});
7978

80-
assertEquals(expected.encode(), actual.encode(), "Options retrival failed");
81-
}
79+
assertEquals(expected.encode(), actual.encode(), "Options retrival failed");
80+
}
8281

8382
}

0 commit comments

Comments
 (0)