// Copyright (C) MongoDB, Inc. 2017-present.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0

package integration

import (
	"context"
	"fmt"
	"net"
	"os"
	"reflect"
	"runtime"
	"strings"
	"testing"
	"time"

	"go.mongodb.org/mongo-driver/v2/bson"
	"go.mongodb.org/mongo-driver/v2/event"
	"go.mongodb.org/mongo-driver/v2/internal/assert"
	"go.mongodb.org/mongo-driver/v2/internal/assert/assertbson"
	"go.mongodb.org/mongo-driver/v2/internal/eventtest"
	"go.mongodb.org/mongo-driver/v2/internal/failpoint"
	"go.mongodb.org/mongo-driver/v2/internal/integration/mtest"
	"go.mongodb.org/mongo-driver/v2/internal/integtest"
	"go.mongodb.org/mongo-driver/v2/internal/require"
	"go.mongodb.org/mongo-driver/v2/internal/testutil"
	"go.mongodb.org/mongo-driver/v2/mongo"
	"go.mongodb.org/mongo-driver/v2/mongo/options"
	"go.mongodb.org/mongo-driver/v2/mongo/readpref"
	"go.mongodb.org/mongo-driver/v2/mongo/writeconcern"
	"go.mongodb.org/mongo-driver/v2/version"
	"go.mongodb.org/mongo-driver/v2/x/bsonx/bsoncore"
	"go.mongodb.org/mongo-driver/v2/x/mongo/driver"
	"go.mongodb.org/mongo-driver/v2/x/mongo/driver/session"
	"go.mongodb.org/mongo-driver/v2/x/mongo/driver/wiremessage"
	"go.mongodb.org/mongo-driver/v2/x/mongo/driver/xoptions"
	"golang.org/x/sync/errgroup"
)

var noClientOpts = mtest.NewOptions().CreateClient(false)

type negateCodec struct {
	ID int64 `bson:"_id"`
}

func (e *negateCodec) EncodeValue(_ bson.EncodeContext, vw bson.ValueWriter, val reflect.Value) error {
	return vw.WriteInt64(val.Int())
}

// DecodeValue negates the value of ID when reading
func (e *negateCodec) DecodeValue(_ bson.DecodeContext, vr bson.ValueReader, val reflect.Value) error {
	i, err := vr.ReadInt64()
	if err != nil {
		return err
	}

	val.SetInt(i * -1)
	return nil
}

type intKey int

func (i intKey) MarshalKey() (string, error) {
	return fmt.Sprintf("key_%d", i), nil
}

var _ options.ContextDialer = &slowConnDialer{}

// A slowConnDialer dials connections that delay network round trips by the given delay duration.
type slowConnDialer struct {
	dialer *net.Dialer
	delay  time.Duration
}

var (
	slowConnDialerDelay      = 300 * time.Millisecond
	reducedHeartbeatInterval = 500 * time.Millisecond
)

func newSlowConnDialer(delay time.Duration) *slowConnDialer {
	return &slowConnDialer{
		dialer: &net.Dialer{},
		delay:  delay,
	}
}

func (scd *slowConnDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
	conn, err := scd.dialer.DialContext(ctx, network, address)
	if err != nil {
		return nil, err
	}
	return &slowConn{
		Conn:  conn,
		delay: scd.delay,
	}, nil
}

var _ net.Conn = &slowConn{}

// slowConn is a net.Conn that delays all calls to Read() by given delay durations. All other
// net.Conn functions behave identically to the embedded net.Conn.
type slowConn struct {
	net.Conn
	delay time.Duration
}

func (sc *slowConn) Read(b []byte) (n int, err error) {
	time.Sleep(sc.delay)
	return sc.Conn.Read(b)
}

func TestClient(t *testing.T) {
	mt := mtest.New(t, noClientOpts)

	reg := bson.NewRegistry()
	reg.RegisterTypeEncoder(reflect.TypeOf(int64(0)), &negateCodec{})
	reg.RegisterTypeDecoder(reflect.TypeOf(int64(0)), &negateCodec{})
	registryOpts := options.Client().
		SetRegistry(reg)
	mt.RunOpts("registry passed to cursors", mtest.NewOptions().ClientOptions(registryOpts), func(mt *mtest.T) {
		_, err := mt.Coll.InsertOne(context.Background(), negateCodec{ID: 10})
		assert.Nil(mt, err, "InsertOne error: %v", err)
		var got negateCodec
		err = mt.Coll.FindOne(context.Background(), bson.D{}).Decode(&got)
		assert.Nil(mt, err, "Find error: %v", err)

		assert.Equal(mt, int64(-10), got.ID, "expected ID -10, got %v", got.ID)
	})
	mt.RunOpts("tls connection", mtest.NewOptions().MinServerVersion("3.0").SSL(true), func(mt *mtest.T) {
		var result bson.Raw
		err := mt.Coll.Database().RunCommand(context.Background(), bson.D{
			{"serverStatus", 1},
		}).Decode(&result)
		assert.Nil(mt, err, "serverStatus error: %v", err)

		security := result.Lookup("security")
		assert.Equal(mt, bson.TypeEmbeddedDocument, security.Type,
			"expected security field to be type %v, got %v", bson.TypeMaxKey, security.Type)
		_, found := security.Document().LookupErr("SSLServerSubjectName")
		assert.Nil(mt, found, "SSLServerSubjectName not found in result")
	})
	mt.RunOpts("x509", mtest.NewOptions().Auth(true).SSL(true), func(mt *mtest.T) {
		testCases := []struct {
			certificate string
			password    string
		}{
			{
				"MONGO_GO_DRIVER_KEY_FILE",
				"",
			},
			{
				"MONGO_GO_DRIVER_PKCS8_ENCRYPTED_KEY_FILE",
				"&sslClientCertificateKeyPassword=password",
			},
			{
				"MONGO_GO_DRIVER_PKCS8_UNENCRYPTED_KEY_FILE",
				"",
			},
		}
		for _, tc := range testCases {
			mt.Run(tc.certificate, func(mt *mtest.T) {
				const user = "C=US,ST=New York,L=New York City,O=MDB,OU=Drivers,CN=client"
				db := mt.Client.Database("$external")

				// We don't care if the user doesn't already exist.
				_ = db.RunCommand(
					context.Background(),
					bson.D{{"dropUser", user}},
				)
				err := db.RunCommand(
					context.Background(),
					bson.D{
						{"createUser", user},
						{"roles", bson.A{
							bson.D{{"role", "readWrite"}, {"db", "test"}},
						}},
					},
				).Err()
				assert.Nil(mt, err, "createUser error: %v", err)

				baseConnString := mtest.ClusterURI()
				// remove username/password from base conn string
				revisedConnString := "mongodb://"
				split := strings.Split(baseConnString, "@")
				assert.Equal(t, 2, len(split), "expected 2 parts after split, got %v (connstring %v)", split, baseConnString)
				revisedConnString += split[1]

				cs := fmt.Sprintf(
					"%s&sslClientCertificateKeyFile=%s&authMechanism=MONGODB-X509&authSource=$external%s",
					revisedConnString,
					os.Getenv(tc.certificate),
					tc.password,
				)
				authClientOpts := options.Client().ApplyURI(cs)
				integtest.AddTestServerAPIVersion(authClientOpts)
				authClient, err := mongo.Connect(authClientOpts)
				assert.Nil(mt, err, "authClient Connect error: %v", err)
				defer func() { _ = authClient.Disconnect(context.Background()) }()

				rdr, err := authClient.Database("test").RunCommand(context.Background(), bson.D{
					{"connectionStatus", 1},
				}).Raw()
				assert.Nil(mt, err, "connectionStatus error: %v", err)
				users, err := rdr.LookupErr("authInfo", "authenticatedUsers")
				assert.Nil(mt, err, "authenticatedUsers not found in response")
				elems, err := bson.Raw(users.Array()).Elements()
				assert.Nil(mt, err, "error getting users elements: %v", err)

				for _, userElem := range elems {
					rdr := userElem.Value().Document()
					var u struct {
						User string
						DB   string
					}

					if err := bson.Unmarshal(rdr, &u); err != nil {
						continue
					}
					if u.User == user && u.DB == "$external" {
						return
					}
				}
				mt.Fatal("unable to find authenticated user")
			})
		}
	})
	mt.RunOpts("list databases", noClientOpts, func(mt *mtest.T) {
		mt.RunOpts("filter", noClientOpts, func(mt *mtest.T) {
			testCases := []struct {
				name             string
				filter           bson.D
				hasTestDB        bool
				minServerVersion string
			}{
				{"empty", bson.D{}, true, ""},
				{"non-empty", bson.D{{"name", "foobar"}}, false, "3.6"},
			}

			for _, tc := range testCases {
				opts := mtest.NewOptions()
				if tc.minServerVersion != "" {
					opts.MinServerVersion(tc.minServerVersion)
				}

				mt.RunOpts(tc.name, opts, func(mt *mtest.T) {
					res, err := mt.Client.ListDatabases(context.Background(), tc.filter)
					assert.Nil(mt, err, "ListDatabases error: %v", err)

					var found bool
					for _, db := range res.Databases {
						if db.Name == mtest.TestDB {
							found = true
							break
						}
					}
					assert.Equal(mt, tc.hasTestDB, found, "expected to find test db: %v, found: %v", tc.hasTestDB, found)
				})
			}
		})
		mt.Run("options", func(mt *mtest.T) {
			allOpts := options.ListDatabases().SetNameOnly(true).SetAuthorizedDatabases(true)
			mt.ClearEvents()

			_, err := mt.Client.ListDatabases(context.Background(), bson.D{}, allOpts)
			assert.Nil(mt, err, "ListDatabases error: %v", err)

			evt := mt.GetStartedEvent()
			assert.Equal(mt, "listDatabases", evt.CommandName, "expected ")

			expectedDoc := bsoncore.BuildDocumentFromElements(nil,
				bsoncore.AppendBooleanElement(nil, "nameOnly", true),
				bsoncore.AppendBooleanElement(nil, "authorizedDatabases", true),
			)
			err = compareDocs(mt, expectedDoc, evt.Command)
			assert.Nil(mt, err, "compareDocs error: %v", err)
		})
	})
	mt.RunOpts("list database names", noClientOpts, func(mt *mtest.T) {
		mt.RunOpts("filter", noClientOpts, func(mt *mtest.T) {
			testCases := []struct {
				name             string
				filter           bson.D
				hasTestDB        bool
				minServerVersion string
			}{
				{"no filter", bson.D{}, true, ""},
				{"filter", bson.D{{"name", "foobar"}}, false, "3.6"},
			}

			for _, tc := range testCases {
				opts := mtest.NewOptions()
				if tc.minServerVersion != "" {
					opts.MinServerVersion(tc.minServerVersion)
				}

				mt.RunOpts(tc.name, opts, func(mt *mtest.T) {
					dbs, err := mt.Client.ListDatabaseNames(context.Background(), tc.filter)
					assert.Nil(mt, err, "ListDatabaseNames error: %v", err)

					var found bool
					for _, db := range dbs {
						if db == mtest.TestDB {
							found = true
							break
						}
					}
					assert.Equal(mt, tc.hasTestDB, found, "expected to find test db: %v, found: %v", tc.hasTestDB, found)
				})
			}
		})
		mt.Run("options", func(mt *mtest.T) {
			allOpts := options.ListDatabases().SetNameOnly(true).SetAuthorizedDatabases(true)
			mt.ClearEvents()

			_, err := mt.Client.ListDatabaseNames(context.Background(), bson.D{}, allOpts)
			assert.Nil(mt, err, "ListDatabaseNames error: %v", err)

			evt := mt.GetStartedEvent()
			assert.Equal(mt, "listDatabases", evt.CommandName, "expected ")

			expectedDoc := bsoncore.BuildDocumentFromElements(nil,
				bsoncore.AppendBooleanElement(nil, "nameOnly", true),
				bsoncore.AppendBooleanElement(nil, "authorizedDatabases", true),
			)
			err = compareDocs(mt, expectedDoc, evt.Command)
			assert.Nil(mt, err, "compareDocs error: %v", err)
		})
	})
	mt.RunOpts("ping", noClientOpts, func(mt *mtest.T) {
		mt.Run("default read preference", func(mt *mtest.T) {
			err := mt.Client.Ping(context.Background(), nil)
			assert.Nil(mt, err, "Ping error: %v", err)
		})
		mt.Run("invalid host", func(mt *mtest.T) {
			// manually create client rather than using RunOpts with ClientOptions because the testing lib will
			// apply the correct URI.
			invalidClientOpts := options.Client().
				SetServerSelectionTimeout(100 * time.Millisecond).SetHosts([]string{"invalid:123"}).
				SetConnectTimeout(500 * time.Millisecond).SetTimeout(500 * time.Millisecond)
			integtest.AddTestServerAPIVersion(invalidClientOpts)
			client, err := mongo.Connect(invalidClientOpts)
			assert.Nil(mt, err, "Connect error: %v", err)
			err = client.Ping(context.Background(), readpref.Primary())
			assert.NotNil(mt, err, "expected error for pinging invalid host, got nil")
			_ = client.Disconnect(context.Background())
		})
	})
	mt.RunOpts("disconnect", noClientOpts, func(mt *mtest.T) {
		mt.Run("nil context", func(mt *mtest.T) {
			err := mt.Client.Disconnect(nil)
			assert.Nil(mt, err, "Disconnect error: %v", err)
		})
	})
	mt.RunOpts("end sessions", mtest.NewOptions().MinServerVersion("3.6"), func(mt *mtest.T) {
		_, err := mt.Client.ListDatabases(context.Background(), bson.D{})
		assert.Nil(mt, err, "ListDatabases error: %v", err)

		mt.ClearEvents()
		err = mt.Client.Disconnect(context.Background())
		assert.Nil(mt, err, "Disconnect error: %v", err)

		started := mt.GetStartedEvent()
		assert.Equal(mt, "endSessions", started.CommandName, "expected cmd name endSessions, got %v", started.CommandName)
	})
	mt.RunOpts("hello lastWriteDate", mtest.NewOptions().Topologies(mtest.ReplicaSet), func(mt *mtest.T) {
		_, err := mt.Coll.InsertOne(context.Background(), bson.D{{"x", 1}})
		assert.Nil(mt, err, "InsertOne error: %v", err)
	})
	sessionOpts := mtest.NewOptions().MinServerVersion("3.6.0").CreateClient(false)
	mt.RunOpts("causal consistency", sessionOpts, func(mt *mtest.T) {
		testCases := []struct {
			name       string
			opts       *options.SessionOptionsBuilder
			consistent bool
		}{
			{"default", options.Session(), true},
			{"true", options.Session().SetCausalConsistency(true), true},
			{"false", options.Session().SetCausalConsistency(false), false},
		}

		for _, tc := range testCases {
			mt.Run(tc.name, func(mt *mtest.T) {
				sess, err := mt.Client.StartSession(tc.opts)
				assert.Nil(mt, err, "StartSession error: %v", err)
				defer sess.EndSession(context.Background())
				clientSession := testutil.GetUnexportedFieldAs[*session.Client](sess, "clientSession")

				consistent := clientSession.Consistent
				assert.Equal(mt, tc.consistent, consistent, "expected consistent to be %v, got %v", tc.consistent, consistent)
			})
		}
	})
	retryOpts := mtest.NewOptions().MinServerVersion("3.6.0").ClientType(mtest.Mock)
	mt.RunOpts("retry writes error 20 wrapped", retryOpts, func(mt *mtest.T) {
		writeErrorCode20 := mtest.CreateWriteErrorsResponse(mtest.WriteError{
			Message: "Transaction numbers",
			Code:    20,
		})
		writeErrorCode19 := mtest.CreateWriteErrorsResponse(mtest.WriteError{
			Message: "Transaction numbers",
			Code:    19,
		})
		writeErrorCode20WrongMsg := mtest.CreateWriteErrorsResponse(mtest.WriteError{
			Message: "Not transaction numbers",
			Code:    20,
		})
		cmdErrCode20 := mtest.CreateCommandErrorResponse(mtest.CommandError{
			Message: "Transaction numbers",
			Code:    20,
		})
		cmdErrCode19 := mtest.CreateCommandErrorResponse(mtest.CommandError{
			Message: "Transaction numbers",
			Code:    19,
		})
		cmdErrCode20WrongMsg := mtest.CreateCommandErrorResponse(mtest.CommandError{
			Message: "Not transaction numbers",
			Code:    20,
		})

		testCases := []struct {
			name                 string
			errResponse          bson.D
			expectUnsupportedMsg bool
		}{
			{"write error code 20", writeErrorCode20, true},
			{"write error code 20 wrong msg", writeErrorCode20WrongMsg, false},
			{"write error code 19 right msg", writeErrorCode19, false},
			{"command error code 20", cmdErrCode20, true},
			{"command error code 20 wrong msg", cmdErrCode20WrongMsg, false},
			{"command error code 19 right msg", cmdErrCode19, false},
		}
		for _, tc := range testCases {
			mt.Run(tc.name, func(mt *mtest.T) {
				mt.ClearMockResponses()
				mt.AddMockResponses(tc.errResponse)

				sess, err := mt.Client.StartSession()
				assert.Nil(mt, err, "StartSession error: %v", err)
				defer sess.EndSession(context.Background())

				_, err = mt.Coll.InsertOne(context.Background(), bson.D{{"x", 1}})
				assert.NotNil(mt, err, "expected err but got nil")
				if tc.expectUnsupportedMsg {
					assert.Equal(mt, driver.ErrUnsupportedStorageEngine.Error(), err.Error(),
						"expected error %v, got %v", driver.ErrUnsupportedStorageEngine, err)
					return
				}
				assert.NotEqual(mt, driver.ErrUnsupportedStorageEngine.Error(), err.Error(),
					"got ErrUnsupportedStorageEngine but wanted different error")
			})
		}
	})

	testAppName := "foo"
	appNameClientOpts := options.Client().
		SetAppName(testAppName)
	appNameMtOpts := mtest.NewOptions().
		ClientType(mtest.Proxy).
		ClientOptions(appNameClientOpts).
		Topologies(mtest.Single)
	mt.RunOpts("app name is always sent", appNameMtOpts, func(mt *mtest.T) {
		err := mt.Client.Ping(context.Background(), mtest.PrimaryRp)
		assert.Nil(mt, err, "Ping error: %v", err)

		want := mustMarshalBSON(bson.D{
			{Key: "application", Value: bson.D{
				bson.E{Key: "name", Value: "foo"},
			}},
			{Key: "driver", Value: bson.D{
				{Key: "name", Value: "mongo-go-driver"},
				{Key: "version", Value: version.Driver},
			}},
			{Key: "os", Value: bson.D{
				{Key: "type", Value: runtime.GOOS},
				{Key: "architecture", Value: runtime.GOARCH},
			}},
			{Key: "platform", Value: runtime.Version()},
		})

		for i := 0; i < 2; i++ {
			message := mt.GetProxyCapture().TryNext()
			require.NotNil(mt, message, "expected handshake message, got nil")

			clientMetadata := clientMetadataFromHandshake(mt, message.Sent.Command)
			assertbson.EqualDocument(mt, want, clientMetadata)
		}
	})

	// Test that direct connections work as expected.
	firstServerAddr := mtest.GlobalTopology().Description().Servers[0].Addr
	directConnectionOpts := options.Client().
		ApplyURI(fmt.Sprintf("mongodb://%s", firstServerAddr)).
		SetReadPreference(readpref.Primary()).
		SetDirect(true)
	mtOpts := mtest.NewOptions().
		ClientOptions(directConnectionOpts).
		CreateCollection(false).
		MinServerVersion("3.6").     // Minimum server version 3.6 to force OP_MSG.
		Topologies(mtest.ReplicaSet) // Read preference isn't sent to standalones so we can test on replica sets.
	mt.RunOpts("direct connection made", mtOpts, func(mt *mtest.T) {
		_, err := mt.Coll.Find(context.Background(), bson.D{})
		assert.Nil(mt, err, "Find error: %v", err)

		// When connected directly, the primary read preference should be overwritten to primaryPreferred.
		evt := mt.GetStartedEvent()
		assert.Equal(mt, "find", evt.CommandName, "expected 'find' event, got '%s'", evt.CommandName)

		// A direct connection will result in a single topology, and so
		// the default readPreference mode should be "primaryPrefered".
		modeVal, err := evt.Command.LookupErr("$readPreference", "mode")
		assert.Nil(mt, err, "expected command %s to include $readPreference", evt.Command)

		mode := modeVal.StringValue()
		assert.Equal(mt, mode, "primaryPreferred", "expected read preference mode primaryPreferred, got %v", mode)
	})

	// Test that using a client with minPoolSize set doesn't cause a data race.
	mtOpts = mtest.NewOptions().ClientOptions(options.Client().SetMinPoolSize(5))
	mt.RunOpts("minPoolSize", mtOpts, func(mt *mtest.T) {
		err := mt.Client.Ping(context.Background(), readpref.Primary())
		assert.Nil(t, err, "unexpected error calling Ping: %v", err)
	})

	mt.Run("minimum RTT is monitored", func(mt *mtest.T) {
		mt.Parallel()

		// Reset the client with a dialer that delays all network round trips by 300ms and set the
		// heartbeat interval to 500ms to reduce the time it takes to collect RTT samples.
		mt.ResetClient(options.Client().
			SetDialer(newSlowConnDialer(slowConnDialerDelay)).
			SetHeartbeatInterval(reducedHeartbeatInterval))

		// Assert that the minimum RTT is eventually >250ms.
		topo := getTopologyFromClient(mt.Client)
		callback := func() bool {
			// Wait for all of the server's minimum RTTs to be >250ms.
			for _, desc := range topo.Description().Servers {
				server, err := topo.FindServer(desc)
				assert.NoError(mt, err, "FindServer error: %v", err)
				if server.RTTMonitor().Min() <= 250*time.Millisecond {
					return false // the tick should wait for 100ms in this case
				}
			}

			return true
		}
		assert.Eventually(t,
			callback,
			10*time.Second,
			100*time.Millisecond,
			"expected that the minimum RTT is eventually >250ms")
	})

	// Test that if the minimum RTT is greater than the remaining timeout for an operation, the
	// operation is not sent to the server and no connections are closed.
	mt.Run("minimum RTT used to prevent sending requests", func(mt *mtest.T) {
		mt.Parallel()

		// Assert that we can call Ping with a 250ms timeout.
		ctx, cancel := context.WithTimeout(context.Background(), 250*time.Millisecond)
		defer cancel()
		err := mt.Client.Ping(ctx, nil)
		assert.Nil(mt, err, "Ping error: %v", err)

		// Reset the client with a dialer that delays all network round trips by 300ms and set the
		// heartbeat interval to 500ms to reduce the time it takes to collect RTT samples.
		tpm := eventtest.NewTestPoolMonitor()
		mt.ResetClient(options.Client().
			SetPoolMonitor(tpm.PoolMonitor).
			SetDialer(newSlowConnDialer(slowConnDialerDelay)).
			SetHeartbeatInterval(reducedHeartbeatInterval))

		// Assert that the minimum RTT is eventually >250ms.
		topo := getTopologyFromClient(mt.Client)
		callback := func() bool {
			// Wait for all of the server's minimum RTTs to be >250ms.
			for _, desc := range topo.Description().Servers {
				server, err := topo.FindServer(desc)
				assert.NoError(mt, err, "FindServer error: %v", err)
				if server.RTTMonitor().Min() <= 250*time.Millisecond {
					return false
				}
			}

			return true
		}
		assert.Eventually(t,
			callback,
			10*time.Second,
			100*time.Millisecond,
			"expected that the minimum RTT is eventually >250ms")

		// Once we've waited for the minimum RTT for the single server to be >250ms, run a bunch of
		// Ping operations with a timeout of 250ms and expect that they return errors.
		for i := 0; i < 10; i++ {
			ctx, cancel = context.WithTimeout(context.Background(), 250*time.Millisecond)
			err := mt.Client.Ping(ctx, nil)
			cancel()
			assert.NotNil(mt, err, "expected Ping to return an error")
		}

		// Assert that the Ping timeouts result in no connections being closed.
		closed := len(tpm.Events(func(e *event.PoolEvent) bool { return e.Type == event.ConnectionClosed }))
		assert.Equal(t, 0, closed, "expected no connections to be closed")
	})

	// Test that OP_MSG is used for authentication-related commands on 3.6+ (WV 6+). Do not test when API version is
	// set, as handshakes will always use OP_MSG.
	opMsgOpts := mtest.NewOptions().ClientType(mtest.Proxy).MinServerVersion("3.6").Auth(true).RequireAPIVersion(false)
	mt.RunOpts("OP_MSG used for authentication on 3.6+", opMsgOpts, func(mt *mtest.T) {
		err := mt.Client.Ping(context.Background(), mtest.PrimaryRp)
		assert.Nil(mt, err, "Ping error: %v", err)

		proxyCapture := mt.GetProxyCapture()

		// The first message should be a connection handshake.
		firstMessage := proxyCapture.TryNext()
		require.NotNil(mt, firstMessage, "expected handshake message, got nil")

		assert.True(t, firstMessage.IsHandshake())

		opCode := firstMessage.Sent.OpCode
		assert.Equal(mt, wiremessage.OpQuery, opCode,
			"expected 'OP_MSG' OpCode in wire message, got %q", opCode.String())

		// Look for a saslContinue in the remaining proxied messages and assert that
		// it uses the OP_MSG OpCode, as wire version is now known to be >= 6.
		var saslContinueFound bool
		for {
			message := proxyCapture.TryNext()
			if message == nil {
				break
			}

			if message.CommandName == "saslContinue" {
				saslContinueFound = true
				opCode := message.Sent.OpCode
				assert.Equal(mt, wiremessage.OpMsg, opCode,
					"expected 'OP_MSG' OpCode in wire message, got %q", opCode.String())
				break
			}
		}
		assert.True(mt, saslContinueFound, "did not find 'saslContinue' command in proxied messages")
	})

	// Test that OP_MSG is used for handshakes when API version is declared.
	opMsgSAPIOpts := mtest.NewOptions().ClientType(mtest.Proxy).MinServerVersion("5.0").RequireAPIVersion(true)
	mt.RunOpts("OP_MSG used for handshakes when API version declared", opMsgSAPIOpts, func(mt *mtest.T) {
		err := mt.Client.Ping(context.Background(), mtest.PrimaryRp)
		assert.Nil(mt, err, "Ping error: %v", err)

		// First three messages should be connection handshakes: one for the heartbeat connection, another for the
		// application connection, and a final one for the RTT monitor connection.
		for idx := 0; idx < 3; idx++ {
			message := mt.GetProxyCapture().TryNext()
			require.NotNil(mt, message, "expected handshake message, got nil")

			assert.True(t, message.IsHandshake())

			// Assert that appended OpCode is OP_MSG when API version is set.
			opCode := message.Sent.OpCode
			assert.Equal(mt, wiremessage.OpMsg, opCode,
				"expected 'OP_MSG' OpCode in wire message, got %q", opCode.String())
		}
	})

	opts := mtest.NewOptions().
		// Blocking failpoints don't work on pre-4.2 and sharded clusters.
		Topologies(mtest.Single, mtest.ReplicaSet).
		MinServerVersion("4.2").
		// Expliticly enable retryable reads and retryable writes.
		ClientOptions(options.Client().SetRetryReads(true).SetRetryWrites(true))
	mt.RunOpts("operations don't retry after a context timeout", opts, func(mt *mtest.T) {
		testCases := []struct {
			desc      string
			operation func(context.Context, *mongo.Collection) error
		}{
			{
				desc: "read op",
				operation: func(ctx context.Context, coll *mongo.Collection) error {
					return coll.FindOne(ctx, bson.D{}).Err()
				},
			},
			{
				desc: "write op",
				operation: func(ctx context.Context, coll *mongo.Collection) error {
					_, err := coll.InsertOne(ctx, bson.D{})
					return err
				},
			},
		}

		for _, tc := range testCases {
			mt.Run(tc.desc, func(mt *mtest.T) {
				_, err := mt.Coll.InsertOne(context.Background(), bson.D{})
				require.NoError(mt, err)

				mt.SetFailPoint(failpoint.FailPoint{
					ConfigureFailPoint: "failCommand",
					Mode:               failpoint.ModeAlwaysOn,
					Data: failpoint.Data{
						FailCommands:    []string{"find", "insert"},
						BlockConnection: true,
						BlockTimeMS:     500,
					},
				})

				mt.ClearEvents()

				for i := 0; i < 50; i++ {
					// Run 50 operations, each with a timeout of 50ms. Expect
					// them to all return a timeout error because the failpoint
					// blocks find operations for 500ms. Run 50 to increase the
					// probability that an operation will time out in a way that
					// can cause a retry.
					ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
					err = tc.operation(ctx, mt.Coll)
					cancel()
					assert.ErrorIs(mt, err, context.DeadlineExceeded)
					assert.True(mt, mongo.IsTimeout(err), "expected mongo.IsTimeout(err) to be true")

					// Assert that each operation reported exactly one command
					// started events, which means the operation did not retry
					// after the context timeout.
					evts := mt.GetAllStartedEvents()
					require.Len(mt,
						mt.GetAllStartedEvents(),
						1,
						"expected exactly 1 command started event per operation, but got %d after %d iterations",
						len(evts),
						i)
					mt.ClearEvents()
				}
			})
		}
	})
}

func TestClient_BulkWrite(t *testing.T) {
	mt := mtest.New(t, noClientOpts)

	mtBulkWriteOpts := mtest.NewOptions().MinServerVersion("8.0").ClientType(mtest.Pinned)
	mt.RunOpts("bulk write with nil filter", mtBulkWriteOpts, func(mt *mtest.T) {
		mt.Parallel()

		testCases := []struct {
			name        string
			writes      []mongo.ClientBulkWrite
			errorString string
		}{
			{
				name: "DeleteOne",
				writes: []mongo.ClientBulkWrite{{
					Database:   "foo",
					Collection: "bar",
					Model:      mongo.NewClientDeleteOneModel(),
				}},
				errorString: "delete filter cannot be nil",
			},
			{
				name: "DeleteMany",
				writes: []mongo.ClientBulkWrite{{
					Database:   "foo",
					Collection: "bar",
					Model:      mongo.NewClientDeleteManyModel(),
				}},
				errorString: "delete filter cannot be nil",
			},
			{
				name: "UpdateOne",
				writes: []mongo.ClientBulkWrite{{
					Database:   "foo",
					Collection: "bar",
					Model:      mongo.NewClientUpdateOneModel(),
				}},
				errorString: "update filter cannot be nil",
			},
			{
				name: "UpdateMany",
				writes: []mongo.ClientBulkWrite{{
					Database:   "foo",
					Collection: "bar",
					Model:      mongo.NewClientUpdateManyModel(),
				}},
				errorString: "update filter cannot be nil",
			},
		}
		for _, tc := range testCases {
			tc := tc

			mt.Run(tc.name, func(mt *mtest.T) {
				mt.Parallel()

				_, err := mt.Client.BulkWrite(context.Background(), tc.writes)
				require.EqualError(mt, err, tc.errorString)
			})
		}
	})
	mt.RunOpts("bulk write with write concern", mtBulkWriteOpts, func(mt *mtest.T) {
		mt.Parallel()

		testCases := []struct {
			name string
			opts *options.ClientBulkWriteOptionsBuilder
			want bool
		}{
			{
				name: "unacknowledged",
				opts: options.ClientBulkWrite().SetWriteConcern(writeconcern.Unacknowledged()).SetOrdered(false),
				want: false,
			},
			{
				name: "acknowledged",
				want: true,
			},
		}
		for _, tc := range testCases {
			tc := tc

			mt.Run(tc.name, func(mt *mtest.T) {
				mt.Parallel()

				insertOneModel := mongo.NewClientInsertOneModel().SetDocument(bson.D{{"x", 1}})
				writes := []mongo.ClientBulkWrite{{
					Database:   "foo",
					Collection: "bar",
					Model:      insertOneModel,
				}}
				res, err := mt.Client.BulkWrite(context.Background(), writes, tc.opts)
				require.NoError(mt, err, "BulkWrite error: %v", err)
				require.NotNil(mt, res, "expected a ClientBulkWriteResult")
				assert.Equal(mt, res.Acknowledged, tc.want, "expected Acknowledged: %v, got: %v", tc.want, res.Acknowledged)
			})
		}
	})
	var bulkWrites int
	cmdMonitor := &event.CommandMonitor{
		Started: func(_ context.Context, evt *event.CommandStartedEvent) {
			if evt.CommandName == "bulkWrite" {
				bulkWrites++
			}
		},
	}
	clientOpts := options.Client().SetMonitor(cmdMonitor)
	mt.RunOpts("bulk write with large messages", mtBulkWriteOpts.ClientOptions(clientOpts), func(mt *mtest.T) {
		mt.Parallel()

		document := bson.D{{"largeField", strings.Repeat("a", 16777216-100)}} // Adjust size to account for BSON overhead
		writes := []mongo.ClientBulkWrite{
			{"db", "x", mongo.NewClientInsertOneModel().SetDocument(document)},
			{"db", "x", mongo.NewClientInsertOneModel().SetDocument(document)},
			{"db", "x", mongo.NewClientInsertOneModel().SetDocument(document)},
		}

		_, err := mt.Client.BulkWrite(context.Background(), writes)
		require.NoError(mt, err)
		assert.Equal(mt, 2, bulkWrites, "expected %d bulkWrites, got %d", 2, bulkWrites)
	})
}

func TestClient_BulkWrite_AddCommandFields(t *testing.T) {
	newOpts := func(option bson.D) *options.ClientBulkWriteOptionsBuilder {
		opts := options.ClientBulkWrite()
		err := xoptions.SetInternalClientBulkWriteOptions(opts, "addCommandFields", option)
		require.NoError(t, err, "unexpected error: %v", err)
		return opts
	}

	marshalValue := func(val interface{}) bson.RawValue {
		t.Helper()

		valType, data, err := bson.MarshalValue(val)
		require.NoError(t, err, "MarshalValue error: %v", err)
		return bson.RawValue{
			Type:  valType,
			Value: data,
		}
	}

	models := []struct {
		name  string
		model mongo.ClientWriteModel
	}{
		{
			name:  "insert one",
			model: mongo.NewClientInsertOneModel().SetDocument(bson.D{{"x", 1}}),
		},
		{
			name:  "update one",
			model: mongo.NewClientUpdateOneModel().SetFilter(bson.D{{"x", 1}}).SetUpdate(bson.D{{"$set", bson.D{{"x", 3.14159}}}}),
		},
		{
			name:  "update many",
			model: mongo.NewClientUpdateManyModel().SetFilter(bson.D{{"x", 1}}).SetUpdate(bson.D{{"$set", bson.D{{"x", 3.14159}}}}),
		},
		{
			name:  "replace one",
			model: mongo.NewClientReplaceOneModel().SetFilter(bson.D{{"x", 1}}).SetReplacement(bson.D{{"x", 3.14159}}),
		},
	}

	testCases := []struct {
		name     string
		opts     *options.ClientBulkWriteOptionsBuilder
		expected bson.RawValue
	}{
		{
			name:     "empty",
			opts:     options.ClientBulkWrite(),
			expected: bson.RawValue{},
		},
		{
			name:     "false",
			opts:     newOpts(bson.D{{"bypassEmptyTsReplacement", false}}),
			expected: marshalValue(false),
		},
		{
			name:     "true",
			opts:     newOpts(bson.D{{"bypassEmptyTsReplacement", true}}),
			expected: marshalValue(true),
		},
	}

	mtBulkWriteOpts := mtest.NewOptions().MinServerVersion("8.0").ClientType(mtest.Pinned)
	mt := mtest.New(t, noClientOpts)
	for _, m := range models {
		for _, tc := range testCases {
			mt.RunOpts(fmt.Sprintf("%s %s", m.name, tc.name), mtBulkWriteOpts, func(mt *mtest.T) {
				mt.Parallel()

				writes := []mongo.ClientBulkWrite{{
					Database:   "foo",
					Collection: "bar",
					Model:      m.model,
				}}
				_, err := mt.Client.BulkWrite(context.Background(), writes, tc.opts)
				require.NoError(mt, err, "BulkWrite error: %v", err)
				evt := mt.GetStartedEvent()
				val := evt.Command.Lookup("bypassEmptyTsReplacement")
				assert.Equal(mt, tc.expected, val, "expected bypassEmptyTsReplacement to be %s", tc.expected.String())
			})
		}
	}
}

func TestClient_BSONOptions(t *testing.T) {
	t.Parallel()

	mt := mtest.New(t, noClientOpts)

	type jsonTagsTest struct {
		A string
		B string `json:"x"`
		C string `json:"y" bson:"3"`
	}

	type omitemptyTest struct {
		X jsonTagsTest `bson:"x,omitempty"`
	}

	type truncatingDoublesTest struct {
		X int
	}

	type timeZoneTest struct {
		X time.Time
	}

	timestamp, _ := time.Parse(time.RFC3339, "2006-01-02T15:04:05+07:00")

	testCases := []struct {
		name       string
		bsonOpts   *options.BSONOptions
		doc        any
		decodeInto func() any
		want       any
		wantRaw    bson.Raw
	}{
		{
			name: "UseJSONStructTags",
			bsonOpts: &options.BSONOptions{
				UseJSONStructTags: true,
			},
			doc: jsonTagsTest{
				A: "apple",
				B: "banana",
				C: "carrot",
			},
			decodeInto: func() any { return &jsonTagsTest{} },
			want: &jsonTagsTest{
				A: "apple",
				B: "banana",
				C: "carrot",
			},
			wantRaw: bson.Raw(bsoncore.NewDocumentBuilder().
				AppendString("a", "apple").
				AppendString("x", "banana").
				AppendString("3", "carrot").
				Build()),
		},
		{
			name: "IntMinSize",
			bsonOpts: &options.BSONOptions{
				IntMinSize: true,
			},
			doc:        bson.D{{Key: "x", Value: int64(1)}},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{{Key: "x", Value: int32(1)}},
			wantRaw: bson.Raw(bsoncore.NewDocumentBuilder().
				AppendInt32("x", 1).
				Build()),
		},
		{
			name: "NilMapAsEmpty",
			bsonOpts: &options.BSONOptions{
				NilMapAsEmpty: true,
			},
			doc:        bson.D{{Key: "x", Value: map[string]string(nil)}},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{{Key: "x", Value: bson.D{}}},
			wantRaw: bson.Raw(bsoncore.NewDocumentBuilder().
				AppendDocument("x", bsoncore.NewDocumentBuilder().Build()).
				Build()),
		},
		{
			name: "NilSliceAsEmpty",
			bsonOpts: &options.BSONOptions{
				NilSliceAsEmpty: true,
			},
			doc:        bson.D{{Key: "x", Value: []int(nil)}},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{{Key: "x", Value: bson.A{}}},
			wantRaw: bson.Raw(bsoncore.NewDocumentBuilder().
				AppendArray("x", bsoncore.NewDocumentBuilder().Build()).
				Build()),
		},
		{
			name: "NilByteSliceAsEmpty",
			bsonOpts: &options.BSONOptions{
				NilByteSliceAsEmpty: true,
			},
			doc:        bson.D{{Key: "x", Value: []byte(nil)}},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{{Key: "x", Value: bson.Binary{Data: []byte{}}}},
			wantRaw: bson.Raw(bsoncore.NewDocumentBuilder().
				AppendBinary("x", 0, nil).
				Build()),
		},
		{
			name: "OmitZeroStruct",
			bsonOpts: &options.BSONOptions{
				OmitZeroStruct: true,
			},
			doc:        omitemptyTest{},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{},
			wantRaw:    bson.Raw(bsoncore.NewDocumentBuilder().Build()),
		},
		{
			name: "OmitEmpty with non-zeroer struct",
			bsonOpts: &options.BSONOptions{
				OmitZeroStruct: true,
				OmitEmpty:      true,
			},
			doc: struct {
				X jsonTagsTest `bson:"x"`
			}{},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{},
			wantRaw:    bson.Raw(bsoncore.NewDocumentBuilder().Build()),
		},
		{
			name: "StringifyMapKeysWithFmt",
			bsonOpts: &options.BSONOptions{
				StringifyMapKeysWithFmt: true,
			},
			doc:        map[intKey]string{intKey(42): "foo"},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{{"42", "foo"}},
			wantRaw: bson.Raw(bsoncore.NewDocumentBuilder().
				AppendString("42", "foo").
				Build()),
		},
		{
			name: "AllowTruncatingDoubles",
			bsonOpts: &options.BSONOptions{
				AllowTruncatingDoubles: true,
			},
			doc:        bson.D{{Key: "x", Value: 3.14}},
			decodeInto: func() any { return &truncatingDoublesTest{} },
			want:       &truncatingDoublesTest{3},
			wantRaw: bson.Raw(bsoncore.NewDocumentBuilder().
				AppendDouble("x", 3.14).
				Build()),
		},
		{
			name: "BinaryAsSlice",
			bsonOpts: &options.BSONOptions{
				BinaryAsSlice: true,
			},
			doc:        bson.D{{Key: "x", Value: []byte{42}}},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{{Key: "x", Value: []byte{42}}},
			wantRaw: bson.Raw(bsoncore.NewDocumentBuilder().
				AppendBinary("x", 0, []byte{42}).
				Build()),
		},
		{
			name: "DefaultDocumentM",
			bsonOpts: &options.BSONOptions{
				DefaultDocumentM: true,
			},
			doc:        bson.D{{Key: "doc", Value: bson.D{{Key: "a", Value: int64(1)}}}},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{{Key: "doc", Value: bson.M{"a": int64(1)}}},
		},
		{
			name: "DefaultDocumentMap",
			bsonOpts: &options.BSONOptions{
				DefaultDocumentMap: true,
			},
			doc:        bson.D{{Key: "doc", Value: bson.D{{Key: "a", Value: int64(1)}}}},
			decodeInto: func() any { return &bson.D{} },
			want:       &bson.D{{Key: "doc", Value: map[string]any{"a": int64(1)}}},
		},
		{
			name: "UseLocalTimeZone",
			bsonOpts: &options.BSONOptions{
				UseLocalTimeZone: true,
			},
			doc:        bson.D{{Key: "x", Value: timestamp}},
			decodeInto: func() any { return &timeZoneTest{} },
			want:       &timeZoneTest{timestamp.In(time.Local)},
		},
		{
			name: "ZeroMaps",
			bsonOpts: &options.BSONOptions{
				ZeroMaps: true,
			},
			doc: bson.D{{"a", "apple"}, {"b", "banana"}},
			decodeInto: func() any {
				return &map[string]string{
					"b": "berry",
					"c": "carrot",
				}
			},
			want: &map[string]string{
				"a": "apple",
				"b": "banana",
			},
		},
		{
			name: "ZeroStructs",
			bsonOpts: &options.BSONOptions{
				ZeroStructs: true,
			},
			doc: bson.D{{"a", "apple"}, {"x", "broccoli"}},
			decodeInto: func() any {
				return &jsonTagsTest{
					B: "banana",
					C: "carrot",
				}
			},
			want: &jsonTagsTest{
				A: "apple",
				B: "broccoli",
				C: "",
			},
		},
	}

	for _, tc := range testCases {
		opts := mtest.NewOptions().ClientOptions(
			options.Client().SetBSONOptions(tc.bsonOpts))
		mt.RunOpts(tc.name, opts, func(mt *mtest.T) {
			res, err := mt.Coll.InsertOne(context.Background(), tc.doc)
			require.NoError(mt, err, "InsertOne error")

			sr := mt.Coll.FindOne(
				context.Background(),
				bson.D{{Key: "_id", Value: res.InsertedID}},
				// Exclude the auto-generated "_id" field so we can make simple
				// assertions on the return value.
				options.FindOne().SetProjection(bson.D{{Key: "_id", Value: 0}}))

			if tc.want != nil {
				got := tc.decodeInto()
				err := sr.Decode(got)
				require.NoError(mt, err, "Decode error")

				assert.Equal(mt, tc.want, got, "expected and actual decoded result are different")
			}

			if tc.wantRaw != nil {
				got, err := sr.Raw()
				require.NoError(mt, err, "Raw error")

				assertbson.EqualDocument(mt, tc.wantRaw, got)
			}
		})
	}

	opts := mtest.NewOptions().ClientOptions(
		options.Client().SetBSONOptions(&options.BSONOptions{
			ObjectIDAsHexString: true,
		}))
	mt.RunOpts("ObjectIDAsHexString", opts, func(mt *mtest.T) {
		res, err := mt.Coll.InsertOne(context.Background(), bson.D{{"x", 42}})
		require.NoError(mt, err, "InsertOne error")

		sr := mt.Coll.FindOne(
			context.Background(),
			bson.D{{Key: "_id", Value: res.InsertedID}},
		)

		type data struct {
			ID string `bson:"_id"`
			X  int    `bson:"x"`
		}
		var got data

		err = sr.Decode(&got)
		require.NoError(mt, err, "Decode error")

		want := data{
			ID: res.InsertedID.(bson.ObjectID).Hex(),
			X:  42,
		}
		assert.Equal(mt, want, got, "expected and actual decoded result are different")
	})

	opts = mtest.NewOptions().ClientOptions(
		options.Client().SetBSONOptions(&options.BSONOptions{
			ErrorOnInlineDuplicates: true,
		}))
	mt.RunOpts("ErrorOnInlineDuplicates", opts, func(mt *mtest.T) {
		type inlineDupInner struct {
			A string
		}

		type inlineDupOuter struct {
			A string
			B *inlineDupInner `bson:"b,inline"`
		}

		_, err := mt.Coll.InsertOne(context.Background(), inlineDupOuter{
			A: "outer",
			B: &inlineDupInner{
				A: "inner",
			},
		})
		require.Error(mt, err, "expected InsertOne to return an error")
	})
}

func TestClientStress(t *testing.T) {
	mtOpts := mtest.NewOptions().CreateClient(false)
	mt := mtest.New(t, mtOpts)

	// Test that a Client can recover from a massive traffic spike after the traffic spike is over.
	mt.Run("Client recovers from traffic spike", func(mt *mtest.T) {
		oid := bson.NewObjectID()
		doc := bson.D{{Key: "_id", Value: oid}, {Key: "key", Value: "value"}}
		_, err := mt.Coll.InsertOne(context.Background(), doc)
		assert.Nil(mt, err, "InsertOne error: %v", err)

		// findOne calls FindOne("_id": oid) on the given collection and with the given timeout. It
		// returns any errors.
		findOne := func(coll *mongo.Collection, timeout time.Duration) error {
			ctx, cancel := context.WithTimeout(context.Background(), timeout)
			defer cancel()
			var res map[string]any
			return coll.FindOne(ctx, bson.D{{Key: "_id", Value: oid}}).Decode(&res)
		}

		// findOneFor calls FindOne on the given collection and with the given timeout in a loop for
		// the given duration and returns any errors returned by FindOne.
		findOneFor := func(coll *mongo.Collection, timeout time.Duration, d time.Duration) []error {
			errs := make([]error, 0)
			start := time.Now()
			for time.Since(start) <= d {
				err := findOne(coll, timeout)
				if err != nil {
					errs = append(errs, err)
				}
				time.Sleep(10 * time.Microsecond)
			}
			return errs
		}

		// Calculate the maximum observed round-trip time by measuring the duration of some FindOne
		// operations and picking the max.
		var maxRTT time.Duration
		for i := 0; i < 50; i++ {
			start := time.Now()
			err := findOne(mt.Coll, 10*time.Second)
			assert.Nil(t, err, "FindOne error: %v", err)
			duration := time.Since(start)
			if duration > maxRTT {
				maxRTT = duration
			}
		}
		assert.True(mt, maxRTT > 0, "RTT must be greater than 0")

		// Run tests with various "maxPoolSize" values, including 1-connection pools and the default
		// size of 100, to test how the client handles traffic spikes using different connection
		// pool configurations.
		maxPoolSizes := []uint64{1, 10, 100}
		for _, maxPoolSize := range maxPoolSizes {
			tpm := eventtest.NewTestPoolMonitor()
			maxPoolSizeOpt := mtest.NewOptions().ClientOptions(
				options.Client().
					SetPoolMonitor(tpm.PoolMonitor).
					SetMaxPoolSize(maxPoolSize))
			mt.RunOpts(fmt.Sprintf("maxPoolSize %d", maxPoolSize), maxPoolSizeOpt, func(mt *mtest.T) {
				// Print the count of connection created, connection closed, and pool clear events
				// collected during the test to help with debugging.
				defer func() {
					created := len(tpm.Events(func(e *event.PoolEvent) bool { return e.Type == event.ConnectionCreated }))
					closed := len(tpm.Events(func(e *event.PoolEvent) bool { return e.Type == event.ConnectionClosed }))
					poolCleared := len(tpm.Events(func(e *event.PoolEvent) bool { return e.Type == event.ConnectionPoolCleared }))
					mt.Logf("Connections created: %d, connections closed: %d, pool clears: %d", created, closed, poolCleared)
				}()

				doc := bson.D{{Key: "_id", Value: oid}, {Key: "key", Value: "value"}}
				_, err := mt.Coll.InsertOne(context.Background(), doc)
				assert.Nil(mt, err, "InsertOne error: %v", err)

				// Set the timeout to be 100x the maximum observed RTT. Use a minimum 100ms timeout to
				// prevent spurious test failures due to extremely low timeouts.
				timeout := maxRTT * 100
				minTimeout := 100 * time.Millisecond
				if timeout < minTimeout {
					timeout = minTimeout
				}
				mt.Logf("Max RTT %v; using a timeout of %v", maxRTT, timeout)

				// Warm up the client for 1 second to allow connections to be established. Ignore
				// any errors.
				_ = findOneFor(mt.Coll, timeout, 1*time.Second)

				// Simulate normal traffic by running one FindOne loop for 1 second and assert that there
				// are no errors.
				errs := findOneFor(mt.Coll, timeout, 1*time.Second)
				assert.True(mt, len(errs) == 0, "expected no errors, but got %d (%v)", len(errs), errs)

				// Simulate an extreme traffic spike by running 1,000 FindOne loops in parallel for 10
				// seconds and expect at least some errors to occur.
				g := new(errgroup.Group)
				for i := 0; i < 1000; i++ {
					g.Go(func() error {
						errs := findOneFor(mt.Coll, timeout, 10*time.Second)
						if len(errs) == 0 {
							return nil
						}
						return errs[len(errs)-1]
					})
				}
				err = g.Wait()
				mt.Logf("Error from extreme traffic spike (errors are expected): %v", err)

				// Simulate normal traffic again for 10 seconds. Ignore any errors to allow any outstanding
				// connection errors to stop.
				_ = findOneFor(mt.Coll, timeout, 10*time.Second)

				// Simulate normal traffic again for 1 second and assert that there are no errors.
				errs = findOneFor(mt.Coll, timeout, 1*time.Second)
				assert.True(mt, len(errs) == 0, "expected no errors, but got %d (%v)", len(errs), errs)
			})
		}
	})
}
