@@ -660,6 +660,77 @@ func TestClient(t *testing.T) {
660
660
"expected 'OP_MSG' OpCode in wire message, got %q" , pair .Sent .OpCode .String ())
661
661
}
662
662
})
663
+
664
+ opts := mtest .NewOptions ().
665
+ // Blocking failpoints don't work on pre-4.2 and sharded clusters.
666
+ Topologies (mtest .Single , mtest .ReplicaSet ).
667
+ MinServerVersion ("4.2" ).
668
+ // Expliticly enable retryable reads and retryable writes.
669
+ ClientOptions (options .Client ().SetRetryReads (true ).SetRetryWrites (true ))
670
+ mt .RunOpts ("operations don't retry after a context timeout" , opts , func (mt * mtest.T ) {
671
+ testCases := []struct {
672
+ desc string
673
+ operation func (context.Context , * mongo.Collection ) error
674
+ }{
675
+ {
676
+ desc : "read op" ,
677
+ operation : func (ctx context.Context , coll * mongo.Collection ) error {
678
+ return coll .FindOne (ctx , bson.D {}).Err ()
679
+ },
680
+ },
681
+ {
682
+ desc : "write op" ,
683
+ operation : func (ctx context.Context , coll * mongo.Collection ) error {
684
+ _ , err := coll .InsertOne (ctx , bson.D {})
685
+ return err
686
+ },
687
+ },
688
+ }
689
+
690
+ for _ , tc := range testCases {
691
+ mt .Run (tc .desc , func (mt * mtest.T ) {
692
+ _ , err := mt .Coll .InsertOne (context .Background (), bson.D {})
693
+ require .NoError (mt , err )
694
+
695
+ mt .SetFailPoint (mtest.FailPoint {
696
+ ConfigureFailPoint : "failCommand" ,
697
+ Mode : "alwaysOn" ,
698
+ Data : mtest.FailPointData {
699
+ FailCommands : []string {"find" , "insert" },
700
+ BlockConnection : true ,
701
+ BlockTimeMS : 500 ,
702
+ },
703
+ })
704
+
705
+ mt .ClearEvents ()
706
+
707
+ for i := 0 ; i < 50 ; i ++ {
708
+ // Run 50 operations, each with a timeout of 50ms. Expect
709
+ // them to all return a timeout error because the failpoint
710
+ // blocks find operations for 500ms. Run 50 to increase the
711
+ // probability that an operation will time out in a way that
712
+ // can cause a retry.
713
+ ctx , cancel := context .WithTimeout (context .Background (), 50 * time .Millisecond )
714
+ err = tc .operation (ctx , mt .Coll )
715
+ cancel ()
716
+ assert .ErrorIs (mt , err , context .DeadlineExceeded )
717
+ assert .True (mt , mongo .IsTimeout (err ), "expected mongo.IsTimeout(err) to be true" )
718
+
719
+ // Assert that each operation reported exactly one command
720
+ // started events, which means the operation did not retry
721
+ // after the context timeout.
722
+ evts := mt .GetAllStartedEvents ()
723
+ require .Len (mt ,
724
+ mt .GetAllStartedEvents (),
725
+ 1 ,
726
+ "expected exactly 1 command started event per operation, but got %d after %d iterations" ,
727
+ len (evts ),
728
+ i )
729
+ mt .ClearEvents ()
730
+ }
731
+ })
732
+ }
733
+ })
663
734
}
664
735
665
736
func TestClient_BSONOptions (t * testing.T ) {
0 commit comments