@@ -11,6 +11,8 @@ import (
1111 "go.mongodb.org/mongo-driver/bson"
1212 "go.mongodb.org/mongo-driver/bson/primitive"
1313 "go.mongodb.org/mongo-driver/mongo"
14+ "go.mongodb.org/mongo-driver/mongo/options"
15+ "go.mongodb.org/mongo-driver/mongo/readconcern"
1416)
1517
1618func TestChangeStreamFilter (t * testing.T ) {
@@ -241,6 +243,106 @@ func (suite *IntegrationTestSuite) TestWithChangeEventsBatching() {
241243 )
242244}
243245
246+ func (suite * IntegrationTestSuite ) TestCursorKilledResilience () {
247+ ctx := suite .Context ()
248+
249+ verifier := suite .BuildVerifier ()
250+
251+ db := suite .srcMongoClient .Database (suite .DBNameForTest ())
252+ coll := db .Collection ("mycoll" )
253+ suite .Require ().NoError (
254+ db .CreateCollection (ctx , coll .Name ()),
255+ )
256+
257+ // start verifier
258+ verifierRunner := RunVerifierCheck (suite .Context (), suite .T (), verifier )
259+
260+ // wait for generation 0 to end
261+ verifierRunner .AwaitGenerationEnd ()
262+
263+ const mvName = "Migration Verifier"
264+
265+ // Kill verifier’s change stream.
266+ cursor , err := suite .srcMongoClient .Database (
267+ "admin" ,
268+ options .Database ().SetReadConcern (readconcern .Local ()),
269+ ).Aggregate (
270+ ctx ,
271+ mongo.Pipeline {
272+ {
273+ {"$currentOp" , bson.D {
274+ {"idleCursors" , true },
275+ }},
276+ },
277+ {
278+ {"$match" , bson.D {
279+ {"clientMetadata.application.name" , mvName },
280+ {"command.collection" , "$cmd.aggregate" },
281+ {"cursor.originatingCommand.pipeline.0.$_internalChangeStreamOplogMatch" ,
282+ bson.D {{"$type" , "object" }},
283+ },
284+ }},
285+ },
286+ },
287+ )
288+ suite .Require ().NoError (err )
289+
290+ var ops []bson.Raw
291+ suite .Require ().NoError (cursor .All (ctx , & ops ))
292+
293+ /*
294+ _, err = coll.InsertOne(
295+ ctx,
296+ bson.D{{"_id", "before kill"}},
297+ )
298+ suite.Require().NoError(err)
299+ */
300+
301+ for _ , cursorRaw := range ops {
302+ opId , err := cursorRaw .LookupErr ("opid" )
303+ suite .Require ().NoError (err , "should get opid from op" )
304+
305+ suite .T ().Logf ("Killing change stream op %+v" , opId )
306+
307+ suite .Require ().NoError (
308+ suite .srcMongoClient .Database ("admin" ).RunCommand (
309+ ctx ,
310+ bson.D {
311+ {"killOp" , 1 },
312+ {"op" , opId },
313+ },
314+ ).Err (),
315+ )
316+ }
317+
318+ sess , err := suite .srcMongoClient .StartSession ()
319+ suite .Require ().NoError (err )
320+ _ , err = coll .InsertOne (
321+ mongo .NewSessionContext (ctx , sess ),
322+ bson.D {{"_id" , "after kill" }},
323+ )
324+ suite .Require ().NoError (err )
325+
326+ suite .T ().Logf ("cluster time after insert: %+v" , sess .ClusterTime ())
327+
328+ suite .Require ().NoError (verifier .WritesOff (ctx ))
329+
330+ suite .Require ().NoError (verifierRunner .Await ())
331+
332+ failedTasks , incompleteTasks , err := FetchFailedAndIncompleteTasks (
333+ ctx ,
334+ verifier .verificationTaskCollection (),
335+ verificationTaskVerifyDocuments ,
336+ verifier .generation ,
337+ )
338+ suite .Require ().NoError (err )
339+
340+ suite .Assert ().Zero (incompleteTasks , "no incomplete tasks" )
341+ suite .Require ().Len (failedTasks , 1 , "expect one failed task" )
342+
343+ suite .T ().Logf ("task: %+v" , failedTasks [0 ])
344+ }
345+
244346func (suite * IntegrationTestSuite ) TestEventBeforeWritesOff () {
245347 ctx := suite .Context ()
246348
0 commit comments