21
21
import com .mongodb .MongoNamespace ;
22
22
import com .mongodb .ReadPreference ;
23
23
import com .mongodb .UnixServerAddress ;
24
- import com .mongodb .client .unified .UnifiedTestModifications .TestDef ;
25
- import com .mongodb .event .TestServerMonitorListener ;
26
- import com .mongodb .internal .logging .LogMessage ;
27
- import com .mongodb .logging .TestLoggingInterceptor ;
28
24
import com .mongodb .WriteConcern ;
29
25
import com .mongodb .client .ClientSession ;
30
26
import com .mongodb .client .MongoClient ;
31
27
import com .mongodb .client .MongoDatabase ;
32
28
import com .mongodb .client .gridfs .GridFSBucket ;
33
29
import com .mongodb .client .model .Filters ;
34
30
import com .mongodb .client .test .CollectionHelper ;
31
+ import com .mongodb .client .unified .UnifiedTestModifications .TestDef ;
35
32
import com .mongodb .client .vault .ClientEncryption ;
36
33
import com .mongodb .connection .ClusterDescription ;
37
34
import com .mongodb .connection .ClusterType ;
38
35
import com .mongodb .connection .ServerDescription ;
39
36
import com .mongodb .event .CommandEvent ;
40
37
import com .mongodb .event .CommandStartedEvent ;
38
+ import com .mongodb .event .TestServerMonitorListener ;
41
39
import com .mongodb .internal .connection .TestCommandListener ;
42
40
import com .mongodb .internal .connection .TestConnectionPoolListener ;
41
+ import com .mongodb .internal .logging .LogMessage ;
43
42
import com .mongodb .lang .NonNull ;
44
43
import com .mongodb .lang .Nullable ;
44
+ import com .mongodb .logging .TestLoggingInterceptor ;
45
45
import com .mongodb .test .AfterBeforeParameterResolver ;
46
46
import org .bson .BsonArray ;
47
47
import org .bson .BsonBoolean ;
57
57
import org .junit .jupiter .params .ParameterizedTest ;
58
58
import org .junit .jupiter .params .provider .Arguments ;
59
59
import org .junit .jupiter .params .provider .MethodSource ;
60
+ import org .opentest4j .AssertionFailedError ;
60
61
import org .opentest4j .TestAbortedException ;
61
62
62
63
import java .io .File ;
63
64
import java .io .IOException ;
64
65
import java .net .URISyntaxException ;
66
+ import java .text .MessageFormat ;
65
67
import java .util .ArrayList ;
66
68
import java .util .Collection ;
67
69
import java .util .Collections ;
70
+ import java .util .HashSet ;
68
71
import java .util .List ;
69
72
import java .util .Set ;
70
73
import java .util .concurrent .ExecutionException ;
91
94
import static org .junit .jupiter .api .Assertions .assertNull ;
92
95
import static org .junit .jupiter .api .Assertions .assertTrue ;
93
96
import static org .junit .jupiter .api .Assertions .fail ;
97
+ import static org .junit .jupiter .api .Assumptions .assumeFalse ;
94
98
import static org .junit .jupiter .api .Assumptions .assumeTrue ;
95
99
import static util .JsonPoweredTestHelper .getTestDocument ;
96
100
import static util .JsonPoweredTestHelper .getTestFiles ;
@@ -100,6 +104,9 @@ public abstract class UnifiedTest {
100
104
private static final Set <String > PRESTART_POOL_ASYNC_WORK_MANAGER_FILE_DESCRIPTIONS = Collections .singleton (
101
105
"wait queue timeout errors include details about checked out connections" );
102
106
107
+ public static final int ATTEMPTS = 3 ;
108
+ private static Set <String > completed = new HashSet <>();
109
+
103
110
@ Nullable
104
111
private String fileDescription ;
105
112
private String schemaVersion ;
@@ -153,26 +160,40 @@ public Entities getEntities() {
153
160
return entities ;
154
161
}
155
162
163
+ public int attempts () {
164
+ return ATTEMPTS ;
165
+ }
166
+
156
167
@ NonNull
157
168
protected static Collection <Arguments > getTestData (final String directory ) throws URISyntaxException , IOException {
169
+ return getTestData (directory , ATTEMPTS );
170
+ }
171
+
172
+ @ NonNull
173
+ protected static Collection <Arguments > getTestData (final String directory , final int attempts ) throws URISyntaxException , IOException {
158
174
List <Arguments > data = new ArrayList <>();
159
175
for (File file : getTestFiles ("/" + directory + "/" )) {
160
176
BsonDocument fileDocument = getTestDocument (file );
161
-
162
177
for (BsonValue cur : fileDocument .getArray ("tests" )) {
163
- data .add (UnifiedTest .createTestData (directory , fileDocument , cur .asDocument ()));
178
+ for (int attempt = 1 ; attempt <= attempts ; attempt ++) {
179
+ data .add (UnifiedTest .createTestData (directory , fileDocument , cur .asDocument (), attempt ));
180
+ }
164
181
}
165
182
}
166
183
return data ;
167
184
}
168
185
169
186
@ NonNull
170
187
private static Arguments createTestData (
171
- final String directory , final BsonDocument fileDocument , final BsonDocument testDocument ) {
188
+ final String directory ,
189
+ final BsonDocument fileDocument ,
190
+ final BsonDocument testDocument ,
191
+ final int attempt ) {
172
192
return Arguments .of (
173
193
fileDocument .getString ("description" ).getValue (),
174
194
testDocument .getString ("description" ).getValue (),
175
195
directory ,
196
+ attempt ,
176
197
fileDocument .getString ("schemaVersion" ).getValue (),
177
198
fileDocument .getArray ("runOnRequirements" , null ),
178
199
fileDocument .getArray ("createEntities" , new BsonArray ()),
@@ -195,6 +216,7 @@ public void setUp(
195
216
@ Nullable final String fileDescription ,
196
217
@ Nullable final String testDescription ,
197
218
@ Nullable final String directoryName ,
219
+ final int attemptNumber ,
198
220
final String schemaVersion ,
199
221
@ Nullable final BsonArray runOnRequirements ,
200
222
final BsonArray entitiesArray ,
@@ -293,40 +315,53 @@ protected boolean isReactive() {
293
315
return false ;
294
316
}
295
317
296
- @ ParameterizedTest (name = "{0}: {1}" )
318
+ @ ParameterizedTest (name = "{0}: {1} ({3}) " )
297
319
@ MethodSource ("data" )
298
320
public void shouldPassAllOutcomes (
299
321
@ Nullable final String fileDescription ,
300
322
@ Nullable final String testDescription ,
301
323
@ Nullable final String directoryName ,
324
+ final int attemptNumber ,
302
325
final String schemaVersion ,
303
326
@ Nullable final BsonArray runOnRequirements ,
304
327
final BsonArray entitiesArray ,
305
328
final BsonArray initialData ,
306
329
final BsonDocument definition ) {
307
- BsonArray operations = definition .getArray ("operations" );
308
- for (int i = 0 ; i < operations .size (); i ++) {
309
- BsonValue cur = operations .get (i );
310
- assertOperation (rootContext , cur .asDocument (), i );
311
- }
330
+ String testId = MessageFormat .format ("{0}: {1}" , fileDescription , testDescription );
331
+ assumeFalse (completed .contains (testId ), "Skipping test already performed" );
332
+ completed .add (testId );
333
+ try {
334
+ BsonArray operations = definition .getArray ("operations" );
335
+ for (int i = 0 ; i < operations .size (); i ++) {
336
+ BsonValue cur = operations .get (i );
337
+ assertOperation (rootContext , cur .asDocument (), i );
338
+ }
312
339
313
- if (definition .containsKey ("outcome" )) {
314
- assertOutcome (rootContext );
315
- }
340
+ if (definition .containsKey ("outcome" )) {
341
+ assertOutcome (rootContext );
342
+ }
316
343
317
- if (definition .containsKey ("expectEvents" )) {
318
- compareEvents (rootContext , definition );
319
- }
344
+ if (definition .containsKey ("expectEvents" )) {
345
+ compareEvents (rootContext , definition );
346
+ }
320
347
321
- if (definition .containsKey ("expectLogMessages" )) {
322
- ArrayList <LogMatcher .Tweak > tweaks = new ArrayList <>(singletonList (
323
- // `LogMessage.Entry.Name.OPERATION` is not supported, therefore we skip matching its value
324
- LogMatcher .Tweak .skip (LogMessage .Entry .Name .OPERATION )));
325
- if (getMongoClientSettings ().getClusterSettings ()
326
- .getHosts ().stream ().anyMatch (serverAddress -> serverAddress instanceof UnixServerAddress )) {
327
- tweaks .add (LogMatcher .Tweak .skip (LogMessage .Entry .Name .SERVER_PORT ));
348
+ if (definition .containsKey ("expectLogMessages" )) {
349
+ ArrayList <LogMatcher .Tweak > tweaks = new ArrayList <>(singletonList (
350
+ // `LogMessage.Entry.Name.OPERATION` is not supported, therefore we skip matching its value
351
+ LogMatcher .Tweak .skip (LogMessage .Entry .Name .OPERATION )));
352
+ if (getMongoClientSettings ().getClusterSettings ()
353
+ .getHosts ().stream ().anyMatch (serverAddress -> serverAddress instanceof UnixServerAddress )) {
354
+ tweaks .add (LogMatcher .Tweak .skip (LogMessage .Entry .Name .SERVER_PORT ));
355
+ }
356
+ compareLogMessages (rootContext , definition , tweaks );
357
+ }
358
+ } catch (AssertionFailedError e ) {
359
+ completed .remove (testId );
360
+ if (attemptNumber == attempts ()) { // last attempt
361
+ throw e ;
362
+ } else {
363
+ assumeFalse (completed .contains (testId ), "Ignoring failure and retrying attempt " + attemptNumber );
328
364
}
329
- compareLogMessages (rootContext , definition , tweaks );
330
365
}
331
366
}
332
367
0 commit comments