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