19
19
import com .mongodb .MongoBulkWriteException ;
20
20
import com .mongodb .MongoWriteConcernException ;
21
21
import com .mongodb .MongoWriteException ;
22
+ import com .mongodb .ServerAddress ;
22
23
import com .mongodb .client .model .CreateCollectionOptions ;
23
24
import com .mongodb .client .model .Filters ;
24
25
import com .mongodb .client .model .ValidationOptions ;
26
+ import com .mongodb .event .CommandListener ;
27
+ import com .mongodb .event .CommandStartedEvent ;
25
28
import org .bson .BsonArray ;
26
29
import org .bson .BsonDocument ;
27
30
import org .bson .BsonInt32 ;
28
31
import org .bson .BsonString ;
32
+ import org .bson .BsonValue ;
29
33
import org .bson .Document ;
34
+ import org .bson .codecs .pojo .PojoCodecProvider ;
30
35
import org .junit .jupiter .api .BeforeEach ;
31
36
import org .junit .jupiter .api .Test ;
32
37
38
+ import java .util .concurrent .CompletableFuture ;
39
+ import java .util .concurrent .ExecutionException ;
40
+ import java .util .concurrent .TimeUnit ;
41
+
33
42
import static com .mongodb .ClusterFixture .isDiscoverableReplicaSet ;
34
43
import static com .mongodb .ClusterFixture .serverVersionAtLeast ;
44
+ import static com .mongodb .MongoClientSettings .getDefaultCodecRegistry ;
45
+ import static com .mongodb .client .Fixture .getMongoClientSettingsBuilder ;
35
46
import static java .lang .String .format ;
36
47
import static java .util .Arrays .asList ;
48
+ import static java .util .Collections .singletonList ;
49
+ import static org .bson .codecs .configuration .CodecRegistries .fromProviders ;
50
+ import static org .bson .codecs .configuration .CodecRegistries .fromRegistries ;
37
51
import static org .junit .jupiter .api .Assertions .assertEquals ;
38
52
import static org .junit .jupiter .api .Assertions .assertFalse ;
39
53
import static org .junit .jupiter .api .Assertions .assertNotNull ;
@@ -116,6 +130,54 @@ public void testWriteErrorDetailsIsPropagated() {
116
130
}
117
131
}
118
132
133
+ /**
134
+ * This test is not from the specification.
135
+ */
136
+ @ Test
137
+ @ SuppressWarnings ("try" )
138
+ void insertMustGenerateIdAtMostOnce () throws ExecutionException , InterruptedException {
139
+ assumeTrue (isDiscoverableReplicaSet ());
140
+ ServerAddress primaryServerAddress = Fixture .getPrimary ();
141
+ CompletableFuture <BsonValue > futureIdGeneratedByFirstInsertAttempt = new CompletableFuture <>();
142
+ CompletableFuture <BsonValue > futureIdGeneratedBySecondInsertAttempt = new CompletableFuture <>();
143
+ CommandListener commandListener = new CommandListener () {
144
+ @ Override
145
+ public void commandStarted (final CommandStartedEvent event ) {
146
+ if (event .getCommandName ().equals ("insert" )) {
147
+ BsonValue generatedId = event .getCommand ().getArray ("documents" ).get (0 ).asDocument ().get ("_id" );
148
+ if (!futureIdGeneratedByFirstInsertAttempt .isDone ()) {
149
+ futureIdGeneratedByFirstInsertAttempt .complete (generatedId );
150
+ } else {
151
+ futureIdGeneratedBySecondInsertAttempt .complete (generatedId );
152
+ }
153
+ }
154
+ }
155
+ };
156
+ BsonDocument failPointDocument = new BsonDocument ("configureFailPoint" , new BsonString ("failCommand" ))
157
+ .append ("mode" , new BsonDocument ("times" , new BsonInt32 (1 )))
158
+ .append ("data" , new BsonDocument ()
159
+ .append ("failCommands" , new BsonArray (singletonList (new BsonString ("insert" ))))
160
+ .append ("errorLabels" , new BsonArray (singletonList (new BsonString ("RetryableWriteError" ))))
161
+ .append ("writeConcernError" , new BsonDocument ("code" , new BsonInt32 (91 ))
162
+ .append ("errmsg" , new BsonString ("Replication is being shut down" ))));
163
+ try (MongoClient client = MongoClients .create (getMongoClientSettingsBuilder ()
164
+ .retryWrites (true )
165
+ .addCommandListener (commandListener )
166
+ .applyToServerSettings (builder -> builder .heartbeatFrequency (50 , TimeUnit .MILLISECONDS ))
167
+ .build ());
168
+ FailPoint ignored = FailPoint .enable (failPointDocument , primaryServerAddress )) {
169
+ MongoCollection <MyDocument > coll = client .getDatabase (database .getName ())
170
+ .getCollection (collection .getNamespace ().getCollectionName (), MyDocument .class )
171
+ .withCodecRegistry (fromRegistries (
172
+ getDefaultCodecRegistry (),
173
+ fromProviders (PojoCodecProvider .builder ().automatic (true ).build ())));
174
+ BsonValue insertedId = coll .insertOne (new MyDocument ()).getInsertedId ();
175
+ BsonValue idGeneratedByFirstInsertAttempt = futureIdGeneratedByFirstInsertAttempt .get ();
176
+ assertEquals (idGeneratedByFirstInsertAttempt , insertedId );
177
+ assertEquals (idGeneratedByFirstInsertAttempt , futureIdGeneratedBySecondInsertAttempt .get ());
178
+ }
179
+ }
180
+
119
181
private void setFailPoint () {
120
182
failPointDocument = new BsonDocument ("configureFailPoint" , new BsonString ("failCommand" ))
121
183
.append ("mode" , new BsonDocument ("times" , new BsonInt32 (1 )))
@@ -132,4 +194,15 @@ private void setFailPoint() {
132
194
private void disableFailPoint () {
133
195
getCollectionHelper ().runAdminCommand (failPointDocument .append ("mode" , new BsonString ("off" )));
134
196
}
197
+
198
+ public static final class MyDocument {
199
+ private int v ;
200
+
201
+ public MyDocument () {
202
+ }
203
+
204
+ public int getV () {
205
+ return v ;
206
+ }
207
+ }
135
208
}
0 commit comments