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 .Before ;
31
36
import org .junit .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 .Assert .assertEquals ;
38
52
import static org .junit .Assert .assertFalse ;
39
53
import static org .junit .Assert .assertNotNull ;
@@ -116,6 +130,55 @@ 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
+ public void insertMustGenerateIdAtMostOnce () throws ExecutionException , InterruptedException {
139
+ assumeTrue (serverVersionAtLeast (4 , 0 ));
140
+ assumeTrue (isDiscoverableReplicaSet ());
141
+ ServerAddress primaryServerAddress = Fixture .getPrimary ();
142
+ CompletableFuture <BsonValue > futureIdGeneratedByFirstInsertAttempt = new CompletableFuture <>();
143
+ CompletableFuture <BsonValue > futureIdGeneratedBySecondInsertAttempt = new CompletableFuture <>();
144
+ CommandListener commandListener = new CommandListener () {
145
+ @ Override
146
+ public void commandStarted (final CommandStartedEvent event ) {
147
+ if (event .getCommandName ().equals ("insert" )) {
148
+ BsonValue generatedId = event .getCommand ().getArray ("documents" ).get (0 ).asDocument ().get ("_id" );
149
+ if (!futureIdGeneratedByFirstInsertAttempt .isDone ()) {
150
+ futureIdGeneratedByFirstInsertAttempt .complete (generatedId );
151
+ } else {
152
+ futureIdGeneratedBySecondInsertAttempt .complete (generatedId );
153
+ }
154
+ }
155
+ }
156
+ };
157
+ BsonDocument failPointDocument = new BsonDocument ("configureFailPoint" , new BsonString ("failCommand" ))
158
+ .append ("mode" , new BsonDocument ("times" , new BsonInt32 (1 )))
159
+ .append ("data" , new BsonDocument ()
160
+ .append ("failCommands" , new BsonArray (singletonList (new BsonString ("insert" ))))
161
+ .append ("errorLabels" , new BsonArray (singletonList (new BsonString ("RetryableWriteError" ))))
162
+ .append ("writeConcernError" , new BsonDocument ("code" , new BsonInt32 (91 ))
163
+ .append ("errmsg" , new BsonString ("Replication is being shut down" ))));
164
+ try (MongoClient client = MongoClients .create (getMongoClientSettingsBuilder ()
165
+ .retryWrites (true )
166
+ .addCommandListener (commandListener )
167
+ .applyToServerSettings (builder -> builder .heartbeatFrequency (50 , TimeUnit .MILLISECONDS ))
168
+ .build ());
169
+ FailPoint ignored = FailPoint .enable (failPointDocument , primaryServerAddress )) {
170
+ MongoCollection <MyDocument > coll = client .getDatabase (database .getName ())
171
+ .getCollection (collection .getNamespace ().getCollectionName (), MyDocument .class )
172
+ .withCodecRegistry (fromRegistries (
173
+ getDefaultCodecRegistry (),
174
+ fromProviders (PojoCodecProvider .builder ().automatic (true ).build ())));
175
+ BsonValue insertedId = coll .insertOne (new MyDocument ()).getInsertedId ();
176
+ BsonValue idGeneratedByFirstInsertAttempt = futureIdGeneratedByFirstInsertAttempt .get ();
177
+ assertEquals (idGeneratedByFirstInsertAttempt , insertedId );
178
+ assertEquals (idGeneratedByFirstInsertAttempt , futureIdGeneratedBySecondInsertAttempt .get ());
179
+ }
180
+ }
181
+
119
182
private void setFailPoint () {
120
183
failPointDocument = new BsonDocument ("configureFailPoint" , new BsonString ("failCommand" ))
121
184
.append ("mode" , new BsonDocument ("times" , new BsonInt32 (1 )))
@@ -132,4 +195,15 @@ private void setFailPoint() {
132
195
private void disableFailPoint () {
133
196
getCollectionHelper ().runAdminCommand (failPointDocument .append ("mode" , new BsonString ("off" )));
134
197
}
198
+
199
+ public static final class MyDocument {
200
+ private int v ;
201
+
202
+ public MyDocument () {
203
+ }
204
+
205
+ public int getV () {
206
+ return v ;
207
+ }
208
+ }
135
209
}
0 commit comments