From 007781b2f74691e9bbc40cab2cf522a77f1b204a Mon Sep 17 00:00:00 2001 From: Abraham Egnor Date: Thu, 28 Aug 2025 13:57:44 +0100 Subject: [PATCH 1/4] RUST-2190 Remove support for server 4.0 --- .evergreen/config.yml | 10 +-- .evergreen/generate-tasks/.gitignore | 1 + .evergreen/generate-tasks/src/main.rs | 4 +- .evergreen/suite-tasks.yml | 27 ------- src/action/find_and_modify.rs | 6 +- src/action/transaction.rs | 3 - src/action/update.rs | 12 +-- src/change_stream/options.rs | 2 - src/client/session.rs | 3 +- src/cmap/conn.rs | 6 +- src/coll/options.rs | 5 +- src/concern/test.rs | 5 -- src/event/sdam.rs | 15 ++-- src/operation/aggregate.rs | 8 +- src/sdam/description/server.rs | 4 +- src/sync/change_stream.rs | 2 +- src/test/change_stream.rs | 77 +------------------ src/test/spec/connection_stepdown.rs | 73 +----------------- .../spec/sessions/sessions_not_supported.rs | 9 +-- src/test/util/fail_point.rs | 2 +- 20 files changed, 37 insertions(+), 237 deletions(-) diff --git a/.evergreen/config.yml b/.evergreen/config.yml index cddf502b8..ae40bd38a 100644 --- a/.evergreen/config.yml +++ b/.evergreen/config.yml @@ -94,9 +94,9 @@ buildvariants: SSL: ssl tasks: # Ubuntu 22.04 does not support MongoDB versions below 6.0. - - name: .standalone !.4.0 !.4.2 !.4.4 !.5.0 - - name: .replicaset !.4.0 !.4.2 !.4.4 !.5.0 - - name: .sharded !.4.0 !.4.2 !.4.4 !.5.0 + - name: .standalone !.4.2 !.4.4 !.5.0 + - name: .replicaset !.4.2 !.4.4 !.5.0 + - name: .sharded !.4.2 !.4.4 !.5.0 - name: macos-14.00 display_name: "MacOS 14.00" @@ -200,8 +200,8 @@ buildvariants: tasks: # The Stable API was introduced in MongoDB version 5.0. Drivers Evergreen Tools only supports # setting REQUIRE_API_VERSION on standalones and sharded clusters. - - .standalone !.4.0 !.4.2 !.4.4 - - .sharded !.4.0 !.4.2 !.4.4 + - .standalone !.4.2 !.4.4 + - .sharded !.4.2 !.4.4 - name: sync-api display_name: "Sync API" diff --git a/.evergreen/generate-tasks/.gitignore b/.evergreen/generate-tasks/.gitignore index eb5a316cb..f2f9e58ec 100644 --- a/.evergreen/generate-tasks/.gitignore +++ b/.evergreen/generate-tasks/.gitignore @@ -1 +1,2 @@ target +Cargo.lock \ No newline at end of file diff --git a/.evergreen/generate-tasks/src/main.rs b/.evergreen/generate-tasks/src/main.rs index 49550e696..eb1cd37fb 100644 --- a/.evergreen/generate-tasks/src/main.rs +++ b/.evergreen/generate-tasks/src/main.rs @@ -1,6 +1,4 @@ -static VERSIONS: &[&str] = &[ - "4.0", "4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "rapid", "latest", -]; +static VERSIONS: &[&str] = &["4.2", "4.4", "5.0", "6.0", "7.0", "8.0", "rapid", "latest"]; static TOPOLOGIES: &[(&str, &str)] = &[ ("standalone", "server"), diff --git a/.evergreen/suite-tasks.yml b/.evergreen/suite-tasks.yml index b414a2700..b4b71b4b2 100644 --- a/.evergreen/suite-tasks.yml +++ b/.evergreen/suite-tasks.yml @@ -3,15 +3,6 @@ tasks: - - name: test-4.0-standalone - tags: [4.0, standalone] - commands: - - func: "bootstrap mongo-orchestration" - vars: - MONGODB_VERSION: 4.0 - TOPOLOGY: server - - func: "run driver test suite" - - name: test-4.2-standalone tags: [4.2, standalone] commands: @@ -84,15 +75,6 @@ tasks: TOPOLOGY: server - func: "run driver test suite" - - name: test-4.0-replicaset - tags: [4.0, replicaset] - commands: - - func: "bootstrap mongo-orchestration" - vars: - MONGODB_VERSION: 4.0 - TOPOLOGY: replica_set - - func: "run driver test suite" - - name: test-4.2-replicaset tags: [4.2, replicaset] commands: @@ -165,15 +147,6 @@ tasks: TOPOLOGY: replica_set - func: "run driver test suite" - - name: test-4.0-sharded - tags: [4.0, sharded] - commands: - - func: "bootstrap mongo-orchestration" - vars: - MONGODB_VERSION: 4.0 - TOPOLOGY: sharded_cluster - - func: "run driver test suite" - - name: test-4.2-sharded tags: [4.2, sharded] commands: diff --git a/src/action/find_and_modify.rs b/src/action/find_and_modify.rs index 72be715c3..e8025fd87 100644 --- a/src/action/find_and_modify.rs +++ b/src/action/find_and_modify.rs @@ -61,8 +61,7 @@ impl Collection { /// Atomically finds up to one document in the collection matching `filter` and updates it. /// Both `Document` and `Vec` implement `Into`, so either can be - /// passed in place of constructing the enum case. Note: pipeline updates are only supported - /// in MongoDB 4.2+. + /// passed in place of constructing the enum case. /// /// This operation will retry once upon failure if the connection and encountered error support /// retryability. See the documentation @@ -133,8 +132,7 @@ impl crate::sync::Collection { /// Atomically finds up to one document in the collection matching `filter` and updates it. /// Both `Document` and `Vec` implement `Into`, so either can be - /// passed in place of constructing the enum case. Note: pipeline updates are only supported - /// in MongoDB 4.2+. + /// passed in place of constructing the enum case. /// /// This operation will retry once upon failure if the connection and encountered error support /// retryability. See the documentation diff --git a/src/action/transaction.rs b/src/action/transaction.rs index c1de5ba71..306e242d6 100644 --- a/src/action/transaction.rs +++ b/src/action/transaction.rs @@ -19,9 +19,6 @@ impl ClientSession { /// [`crate::error::TRANSIENT_TRANSACTION_ERROR`] label. This label indicates that the entire /// transaction can be retried with a reasonable expectation that it will succeed. /// - /// Transactions on replica sets are supported on MongoDB 4.0+. Transactions on sharded - /// clusters are supported on MongoDB 4.2+. - /// /// ```rust /// # use mongodb::{bson::{doc, Document}, error::Result, Client, ClientSession}; /// # diff --git a/src/action/update.rs b/src/action/update.rs index d53bdd590..de7deb5bf 100644 --- a/src/action/update.rs +++ b/src/action/update.rs @@ -20,8 +20,7 @@ where /// Updates all documents matching `query` in the collection. /// /// Both `Document` and `Vec` implement `Into`, so either can be - /// passed in place of constructing the enum case. Note: pipeline updates are only supported - /// in MongoDB 4.2+. See the official MongoDB + /// passed in place of constructing the enum case. See the official MongoDB /// [documentation](https://www.mongodb.com/docs/manual/reference/command/update/#behavior) for more information on specifying updates. /// /// `await` will return d[`Result`]. @@ -41,8 +40,7 @@ where /// Updates up to one document matching `query` in the collection. /// /// Both `Document` and `Vec` implement `Into`, so either can be - /// passed in place of constructing the enum case. Note: pipeline updates are only supported - /// in MongoDB 4.2+. See the official MongoDB + /// passed in place of constructing the enum case. See the official MongoDB /// [documentation](https://www.mongodb.com/docs/manual/reference/command/update/#behavior) for more information on specifying updates. /// /// This operation will retry once upon failure if the connection and encountered error support @@ -73,8 +71,7 @@ where /// Updates all documents matching `query` in the collection. /// /// Both `Document` and `Vec` implement `Into`, so either can be - /// passed in place of constructing the enum case. Note: pipeline updates are only supported - /// in MongoDB 4.2+. See the official MongoDB + /// passed in place of constructing the enum case. See the official MongoDB /// [documentation](https://www.mongodb.com/docs/manual/reference/command/update/#behavior) for more information on specifying updates. /// /// [`run`](Update::run) will return d[`Result`]. @@ -87,8 +84,7 @@ where /// Updates up to one document matching `query` in the collection. /// /// Both `Document` and `Vec` implement `Into`, so either can be - /// passed in place of constructing the enum case. Note: pipeline updates are only supported - /// in MongoDB 4.2+. See the official MongoDB + /// passed in place of constructing the enum case. See the official MongoDB /// [documentation](https://www.mongodb.com/docs/manual/reference/command/update/#behavior) for more information on specifying updates. /// /// This operation will retry once upon failure if the connection and encountered error support diff --git a/src/change_stream/options.rs b/src/change_stream/options.rs index 802795624..0212bd732 100644 --- a/src/change_stream/options.rs +++ b/src/change_stream/options.rs @@ -51,8 +51,6 @@ pub struct ChangeStreamOptions { /// the token. This will allow users to watch collections that have been dropped and /// recreated or newly renamed collections without missing any notifications. /// - /// This feature is only available on MongoDB 4.2+. - /// /// See the documentation [here](https://www.mongodb.com/docs/master/changeStreams/#change-stream-start-after) for more /// information. pub start_after: Option, diff --git a/src/client/session.rs b/src/client/session.rs index b87a26207..ca463ec03 100644 --- a/src/client/session.rs +++ b/src/client/session.rs @@ -45,8 +45,7 @@ pub(crate) static SESSIONS_UNSUPPORTED_COMMANDS: Lazy> = L /// collections atomically. For more information about when and how to use transactions in MongoDB, /// see the [manual](https://www.mongodb.com/docs/manual/core/transactions/). /// -/// Replica set transactions are supported on MongoDB 4.0+. Sharded transactions are supported on -/// MongoDDB 4.2+. Transactions are associated with a `ClientSession`. To begin a transaction, call +/// Transactions are associated with a `ClientSession`. To begin a transaction, call /// [`ClientSession::start_transaction`] on a `ClientSession`. The `ClientSession` must be passed to /// operations to be executed within the transaction. /// diff --git a/src/cmap/conn.rs b/src/cmap/conn.rs index d7c39cca7..00142e1af 100644 --- a/src/cmap/conn.rs +++ b/src/cmap/conn.rs @@ -44,8 +44,8 @@ pub struct ConnectionInfo { /// A driver-generated identifier that uniquely identifies the connection. pub id: u32, - /// A server-generated identifier that uniquely identifies the connection. Available on server - /// versions 4.2+. This may be used to correlate driver connections with server logs. + /// A server-generated identifier that uniquely identifies the connection. This may be used to + /// correlate driver connections with server logs. pub server_id: Option, /// The address that the connection is connected to. @@ -64,7 +64,7 @@ pub(crate) struct Connection { /// Driver-generated ID for the connection. pub(crate) id: u32, - /// The server-side ID for this connection. Only set on server versions 4.2+. + /// The server-side ID for this connection. pub(crate) server_id: Option, /// The address of the server to which this connection connects. diff --git a/src/coll/options.rs b/src/coll/options.rs index df1385273..63ea6e61c 100644 --- a/src/coll/options.rs +++ b/src/coll/options.rs @@ -177,7 +177,6 @@ pub enum UpdateModifications { Document(Document), /// An aggregation pipeline. - /// Only available in MongoDB 4.2+. Pipeline(Vec), } @@ -223,7 +222,7 @@ pub struct UpdateOptions { /// A document or string that specifies the index to use to support the query predicate. /// - /// Only available in MongoDB 4.2+. See the official MongoDB + /// See the official MongoDB /// [documentation](https://www.mongodb.com/docs/manual/reference/command/update/#ex-update-command-hint) for examples. pub hint: Option, @@ -290,7 +289,7 @@ pub struct ReplaceOptions { /// A document or string that specifies the index to use to support the query predicate. /// - /// Only available in MongoDB 4.2+. See the official MongoDB + /// See the official MongoDB /// [documentation](https://www.mongodb.com/docs/manual/reference/command/update/#ex-update-command-hint) for examples. pub hint: Option, diff --git a/src/concern/test.rs b/src/concern/test.rs index d897c95fe..b8ecfa7e2 100644 --- a/src/concern/test.rs +++ b/src/concern/test.rs @@ -134,11 +134,6 @@ async fn unacknowledged_write_concern_rejected() { #[tokio::test] #[function_name::named] async fn snapshot_read_concern() { - // snapshot read concern was introduced in 4.0 - if server_version_lt(4, 0).await { - return; - } - let client = Client::for_test().monitor_events().await; let coll = client diff --git a/src/event/sdam.rs b/src/event/sdam.rs index 7d7857b44..decf25bb3 100644 --- a/src/event/sdam.rs +++ b/src/event/sdam.rs @@ -125,9 +125,9 @@ pub struct ServerHeartbeatStartedEvent { /// The driver-generated ID for the connection used for the heartbeat. pub driver_connection_id: u32, - /// The server-generated ID for the connection used for the heartbeat. This value is only - /// present on server versions 4.2+. If this event corresponds to the first heartbeat on a - /// new monitoring connection, this value will not be present. + /// The server-generated ID for the connection used for the heartbeat. If this event + /// corresponds to the first heartbeat on a new monitoring connection, this value will not + /// be present. pub server_connection_id: Option, } @@ -151,8 +151,7 @@ pub struct ServerHeartbeatSucceededEvent { /// The driver-generated ID for the connection used for the heartbeat. pub driver_connection_id: u32, - /// The server-generated ID for the connection used for the heartbeat. This value is only - /// present for server versions 4.2+. + /// The server-generated ID for the connection used for the heartbeat. pub server_connection_id: Option, } @@ -177,9 +176,9 @@ pub struct ServerHeartbeatFailedEvent { /// The driver-generated ID for the connection used for the heartbeat. pub driver_connection_id: u32, - /// The server-generated ID for the connection used for the heartbeat. This value is only - /// present on server versions 4.2+. If this event corresponds to the first heartbeat on a - /// new monitoring connection, this value will not be present. + /// The server-generated ID for the connection used for the heartbeat. If this event + /// corresponds to the first heartbeat on a new monitoring connection, this value will not + /// be present. pub server_connection_id: Option, } diff --git a/src/operation/aggregate.rs b/src/operation/aggregate.rs index c6d36dfc1..cd7697d03 100644 --- a/src/operation/aggregate.rs +++ b/src/operation/aggregate.rs @@ -17,7 +17,6 @@ use super::{ ExecutionContext, OperationWithDefaults, WriteConcernOnlyBody, - SERVER_4_2_0_WIRE_VERSION, SERVER_4_4_0_WIRE_VERSION, }; @@ -115,10 +114,9 @@ impl OperationWithDefaults for Aggregate { .and_then(|opts| opts.selection_criteria.as_ref()) } - fn supports_read_concern(&self, description: &StreamDescription) -> bool { - // for aggregates that write, read concern is only supported in MongoDB 4.2+. - !self.is_out_or_merge() - || description.max_wire_version.unwrap_or(0) >= SERVER_4_2_0_WIRE_VERSION + fn supports_read_concern(&self, _description: &StreamDescription) -> bool { + // for aggregates that write, read concern is supported in MongoDB 4.2+. + true } fn write_concern(&self) -> Option<&WriteConcern> { diff --git a/src/sdam/description/server.rs b/src/sdam/description/server.rs index cc9fa00b8..7b9d01b7b 100644 --- a/src/sdam/description/server.rs +++ b/src/sdam/description/server.rs @@ -13,8 +13,8 @@ use crate::{ serde_util, }; -const DRIVER_MIN_DB_VERSION: &str = "4.0"; -const DRIVER_MIN_WIRE_VERSION: i32 = 7; +const DRIVER_MIN_DB_VERSION: &str = "4.2"; +const DRIVER_MIN_WIRE_VERSION: i32 = 8; const DRIVER_MAX_WIRE_VERSION: i32 = 25; /// Enum representing the possible types of servers that the driver can connect to. diff --git a/src/sync/change_stream.rs b/src/sync/change_stream.rs index d74e5bbc7..8206c3fdf 100644 --- a/src/sync/change_stream.rs +++ b/src/sync/change_stream.rs @@ -22,7 +22,7 @@ use super::ClientSession; /// errors, such as transient network failures. It can also be done manually by passing /// a [`ResumeToken`] retrieved from a past event into either the /// [`resume_after`](crate::action::Watch::resume_after) or -/// [`start_after`](crate::action::Watch::start_after) (4.2+) options used to create +/// [`start_after`](crate::action::Watch::start_after) options used to create /// the `ChangeStream`. Issuing a raw change stream aggregation is discouraged unless users wish to /// explicitly opt out of resumability. /// diff --git a/src/test/change_stream.rs b/src/test/change_stream.rs index 645ddb544..c0510fd8e 100644 --- a/src/test/change_stream.rs +++ b/src/test/change_stream.rs @@ -286,47 +286,7 @@ async fn resume_kill_cursor_error_suppressed() -> Result<()> { Ok(()) } -/// Prose test 9: $changeStream stage for ChangeStream against a server >=4.0 and <4.0.7 that has -/// not received any results yet MUST include a startAtOperationTime option when resuming a change -/// stream. -#[tokio::test(flavor = "multi_thread")] // multi_thread required for FailPoint -async fn resume_start_at_operation_time() -> Result<()> { - if !server_version_matches(">=4.0, <4.0.7").await { - log_uncaptured("skipping change stream test due to server version"); - return Ok(()); - } - - let (client, coll, mut stream) = - match init_stream("resume_start_at_operation_time", true).await? { - Some(t) => t, - None => return Ok(()), - }; - - let fail_point = FailPoint::fail_command(&["getMore"], FailPointMode::Times(1)).error_code(43); - let _guard = client.enable_fail_point(fail_point).await?; - - coll.insert_one(doc! { "_id": 2 }).await?; - stream.next().await.transpose()?; - - let events = client.events.get_command_events(&["aggregate"]); - assert_eq!(events.len(), 4); - - fn has_saot(command: &Document) -> Result { - Ok(command.get_array("pipeline")?[0] - .as_document() - .unwrap() - .get_document("$changeStream")? - .contains_key("startAtOperationTime")) - } - assert!(matches!(&events[2], - CommandEvent::Started(CommandStartedEvent { - command, - .. - }) if has_saot(command)? - )); - - Ok(()) -} +// Prose test 9: removed. // Prose test 10: removed. @@ -357,36 +317,7 @@ async fn batch_end_resume_token() -> Result<()> { Ok(()) } -/// Prose test 12: Running against a server <4.0.7, end of batch resume token must follow the spec -#[tokio::test] -async fn batch_end_resume_token_legacy() -> Result<()> { - if !server_version_matches("<4.0.7").await { - log_uncaptured("skipping change stream test due to server version"); - return Ok(()); - } - - let (_, coll, mut stream) = match init_stream("batch_end_resume_token_legacy", false).await? { - Some(t) => t, - None => return Ok(()), - }; - - // Case: empty batch, `resume_after` not specified - assert_eq!(stream.next_if_any().await?, None); - assert_eq!(stream.resume_token(), None); - - // Case: end of batch - coll.insert_one(doc! {}).await?; - let expected_id = stream.next_if_any().await?.unwrap().id; - assert_eq!(stream.next_if_any().await?, None); - assert_eq!(stream.resume_token().as_ref(), Some(&expected_id)); - - // Case: empty batch, `resume_after` specified - let mut stream = coll.watch().resume_after(expected_id.clone()).await?; - assert_eq!(stream.next_if_any().await?, None); - assert_eq!(stream.resume_token(), Some(expected_id)); - - Ok(()) -} +// Prose test 12: removed. /// Prose test 13: Mid-batch resume token must be `_id` of last document returned. #[tokio::test] @@ -430,10 +361,6 @@ async fn aggregate_batch() -> Result<()> { log_uncaptured("skipping change stream test on unsupported topology"); return Ok(()); } - if server_version_lt(4, 2).await { - log_uncaptured("skipping change stream test on unsupported version > 4.2"); - return Ok(()); - } let (_, coll, mut stream) = match init_stream("aggregate_batch", false).await? { Some(t) => t, diff --git a/src/test/spec/connection_stepdown.rs b/src/test/spec/connection_stepdown.rs index fc54407a4..d6a35a653 100644 --- a/src/test/spec/connection_stepdown.rs +++ b/src/test/spec/connection_stepdown.rs @@ -7,14 +7,7 @@ use crate::{ error::{CommandError, ErrorKind}, options::{Acknowledgment, WriteConcern}, selection_criteria::SelectionCriteria, - test::{ - get_client_options, - log_uncaptured, - server_version_eq, - server_version_lt, - topology_is_replica_set, - EventClient, - }, + test::{get_client_options, log_uncaptured, topology_is_replica_set, EventClient}, Collection, Database, }; @@ -58,12 +51,6 @@ async fn run_test( #[tokio::test] async fn get_more() { async fn get_more_test(client: EventClient, _db: Database, coll: Collection) { - // This test requires server version 4.2 or higher. - if server_version_lt(4, 2).await { - log_uncaptured("skipping get_more due to server version < 4.2"); - return; - } - let docs = vec![doc! { "x": 1 }; 5]; coll.insert_many(docs) .write_concern(WriteConcern::majority()) @@ -111,12 +98,6 @@ async fn notwritableprimary_keep_pool() { _db: Database, coll: Collection, ) { - // This test requires server version 4.2 or higher. - if server_version_lt(4, 2).await { - log_uncaptured("skipping notwritableprimary_keep_pool due to server version < 4.2"); - return; - } - client .database("admin") .run_command(doc! { @@ -154,58 +135,6 @@ async fn notwritableprimary_keep_pool() { .await; } -#[tokio::test] -async fn notwritableprimary_reset_pool() { - async fn notwritableprimary_reset_pool_test( - client: EventClient, - _db: Database, - coll: Collection, - ) { - // This test must only run on 4.0 servers. - if !server_version_eq(4, 0).await { - log_uncaptured( - "skipping notwritableprimary_reset_pool due to unsupported server version", - ); - return; - } - - client - .database("admin") - .run_command(doc! { - "configureFailPoint": "failCommand", - "mode": { "times": 1 }, - "data": { - "failCommands": ["insert"], - "errorCode": 10107 - } - }) - .await - .unwrap(); - - let result = coll.insert_one(doc! { "test": 1 }).await; - assert!( - matches!( - result.map_err(|e| *e.kind), - Err(ErrorKind::Command(CommandError { code: 10107, .. })) - ), - "insert should have failed" - ); - - tokio::time::sleep(Duration::from_millis(250)).await; - assert_eq!(client.events.count_pool_cleared_events(), 1); - - coll.insert_one(doc! { "test": 1 }) - .await - .expect("insert should have succeeded"); - } - - run_test( - "notwritableprimary_reset_pool", - notwritableprimary_reset_pool_test, - ) - .await; -} - #[tokio::test] async fn shutdown_in_progress() { async fn shutdown_in_progress_test( diff --git a/src/test/spec/sessions/sessions_not_supported.rs b/src/test/spec/sessions/sessions_not_supported.rs index 387503fb1..96e30352d 100644 --- a/src/test/spec/sessions/sessions_not_supported.rs +++ b/src/test/spec/sessions/sessions_not_supported.rs @@ -6,18 +6,11 @@ use crate::{ error::ErrorKind, event::command::CommandEvent, runtime::process::Process, - test::{log_uncaptured, server_version_lt, util::Event, EventClient}, + test::{util::Event, EventClient}, Client, }; async fn spawn_mongocryptd(name: &str) -> Option<(EventClient, Process)> { - if server_version_lt(4, 2).await { - log_uncaptured(format!( - "Skipping {name}: cannot spawn mongocryptd due to server version < 4.2" - )); - return None; - } - let pid_file_path = format!("--pidfilepath={name}.pid"); let args = vec!["--port=47017", &pid_file_path]; let process = Process::spawn("mongocryptd", args).expect("failed to spawn mongocryptd"); diff --git a/src/test/util/fail_point.rs b/src/test/util/fail_point.rs index c10e1dd59..1d125c54f 100644 --- a/src/test/util/fail_point.rs +++ b/src/test/util/fail_point.rs @@ -73,7 +73,7 @@ impl FailPoint { self } - /// How long the server should block the affected commands. Only available on 4.2.9+ servers. + /// How long the server should block the affected commands. pub(crate) fn block_connection(mut self, block_connection_duration: Duration) -> Self { self.data.insert("blockConnection", true); self.data From 8121589496207e5992a3ad169f5d0ce86348cb80 Mon Sep 17 00:00:00 2001 From: Abraham Egnor Date: Thu, 28 Aug 2025 13:59:44 +0100 Subject: [PATCH 2/4] missed a few --- README.md | 2 +- src/action/watch.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f02c0bde3..f9f323797 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ For more details, including features, runnable examples, troubleshooting resourc ### Requirements - Rust 1.83.0+ (See the [MSRV policy](#minimum-supported-rust-version-msrv-policy) for more information) -- MongoDB 4.0+ +- MongoDB 4.2+ #### Supported Platforms diff --git a/src/action/watch.rs b/src/action/watch.rs index fae772d53..b3044a286 100644 --- a/src/action/watch.rs +++ b/src/action/watch.rs @@ -33,8 +33,7 @@ use crate::{ impl Client { /// Starts a new [`ChangeStream`] that receives events for all changes in the cluster. The /// stream does not observe changes from system collections or the "config", "local" or - /// "admin" databases. Note that this method (`watch` on a cluster) is only supported in - /// MongoDB 4.0 or greater. + /// "admin" databases. /// /// See the documentation [here](https://www.mongodb.com/docs/manual/changeStreams/) on change /// streams. @@ -121,8 +120,7 @@ where impl crate::sync::Client { /// Starts a new [`ChangeStream`] that receives events for all changes in the cluster. The /// stream does not observe changes from system collections or the "config", "local" or - /// "admin" databases. Note that this method (`watch` on a cluster) is only supported in - /// MongoDB 4.0 or greater. + /// "admin" databases. /// /// See the documentation [here](https://www.mongodb.com/docs/manual/changeStreams/) on change /// streams. From dab885f8a5be2128ff7142c6a3381d14c483edab Mon Sep 17 00:00:00 2001 From: Abraham Egnor Date: Thu, 28 Aug 2025 14:15:14 +0100 Subject: [PATCH 3/4] lint --- src/operation.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/operation.rs b/src/operation.rs index 6cc73557d..d5fdeb0e1 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -75,7 +75,6 @@ pub(crate) use raw_output::RawOutput; pub(crate) use search_index::{CreateSearchIndexes, DropSearchIndex, UpdateSearchIndex}; pub(crate) use update::{Update, UpdateOrReplace}; -const SERVER_4_2_0_WIRE_VERSION: i32 = 8; const SERVER_4_4_0_WIRE_VERSION: i32 = 9; const SERVER_5_0_0_WIRE_VERSION: i32 = 13; const SERVER_8_0_0_WIRE_VERSION: i32 = 25; From d05d5d0f6fb28f1b1ca7667eff20e88c051338fe Mon Sep 17 00:00:00 2001 From: Abraham Egnor Date: Fri, 29 Aug 2025 10:24:18 +0100 Subject: [PATCH 4/4] review; more removals --- src/cmap/test/integration.rs | 28 --------- .../server_selection/test/in_window.rs | 7 --- src/test.rs | 13 +--- src/test/change_stream.rs | 24 +------ src/test/coll.rs | 12 +--- src/test/spec/gridfs.rs | 5 -- src/test/spec/retryable_reads.rs | 21 ------- src/test/spec/retryable_writes.rs | 63 +------------------ src/test/spec/sdam.rs | 5 -- src/test/spec/transactions.rs | 3 +- src/test/util.rs | 4 +- 11 files changed, 10 insertions(+), 175 deletions(-) diff --git a/src/cmap/test/integration.rs b/src/cmap/test/integration.rs index 94392305f..686dc94d8 100644 --- a/src/cmap/test/integration.rs +++ b/src/cmap/test/integration.rs @@ -17,8 +17,6 @@ use crate::{ sdam::TopologyUpdater, selection_criteria::ReadPreference, test::{ - block_connection_supported, - fail_command_supported, get_client_options, log_uncaptured, topology_is_load_balanced, @@ -86,13 +84,6 @@ async fn acquire_connection_and_send_command() { #[tokio::test] async fn concurrent_connections() { - if !block_connection_supported().await { - log_uncaptured( - "skipping concurrent_connections test due to server not supporting block connection", - ); - return; - } - let mut options = get_client_options().await.clone(); if options.load_balanced.unwrap_or(false) { log_uncaptured("skipping concurrent_connections test due to load-balanced topology"); @@ -166,8 +157,6 @@ async fn concurrent_connections() { } #[tokio::test(flavor = "multi_thread")] -#[function_name::named] - async fn connection_error_during_establishment() { if topology_is_load_balanced().await { log_uncaptured( @@ -175,13 +164,6 @@ async fn connection_error_during_establishment() { ); return; } - if !fail_command_supported().await { - log_uncaptured(format!( - "skipping {} due to failCommand not being supported", - function_name!() - )); - return; - } let mut client_options = get_client_options().await.clone(); client_options.heartbeat_freq = Duration::from_secs(300).into(); // high so that monitors dont trip failpoint @@ -227,17 +209,7 @@ async fn connection_error_during_establishment() { } #[tokio::test(flavor = "multi_thread")] -#[function_name::named] - async fn connection_error_during_operation() { - if !fail_command_supported().await { - log_uncaptured(format!( - "skipping {} due to failCommand not being supported", - function_name!() - )); - return; - } - let mut options = get_client_options().await.clone(); let buffer = EventBuffer::::new(); options.cmap_event_handler = Some(buffer.handler()); diff --git a/src/sdam/description/topology/server_selection/test/in_window.rs b/src/sdam/description/topology/server_selection/test/in_window.rs index af7dc0ac1..ff0b856df 100644 --- a/src/sdam/description/topology/server_selection/test/in_window.rs +++ b/src/sdam/description/topology/server_selection/test/in_window.rs @@ -14,7 +14,6 @@ use crate::{ selection_criteria::{ReadPreference, SelectionCriteria}, test::{ auth_enabled, - block_connection_supported, get_client_options, log_uncaptured, run_spec_test, @@ -126,12 +125,6 @@ async fn load_balancing_test() { log_uncaptured("skipping load_balancing_test test due to auth being enabled"); return; } - if !block_connection_supported().await { - log_uncaptured( - "skipping load_balancing_test test due to server not supporting blockConnection option", - ); - return; - } let mut setup_client_options = get_client_options().await.clone(); diff --git a/src/test.rs b/src/test.rs index 035247cfc..751247855 100644 --- a/src/test.rs +++ b/src/test.rs @@ -143,6 +143,7 @@ pub(crate) async fn server_version_eq(major: u64, minor: u64) -> bool { let server_version = &get_test_client_metadata().await.server_version; server_version.major == major && server_version.minor == minor } +#[expect(dead_code)] pub(crate) async fn server_version_gt(major: u64, minor: u64) -> bool { let server_version = &get_test_client_metadata().await.server_version; server_version.major > major || server_version.major == major && server_version.minor > minor @@ -238,17 +239,7 @@ pub(crate) async fn topology_is_load_balanced() -> bool { } pub(crate) async fn transactions_supported() -> bool { - topology_is_replica_set().await || topology_is_sharded().await && server_version_gte(4, 2).await -} -pub(crate) async fn block_connection_supported() -> bool { - server_version_matches(">=4.2.9").await -} -pub(crate) async fn fail_command_supported() -> bool { - if topology_is_sharded().await { - server_version_matches(">=4.1.5").await - } else { - true - } + topology_is_replica_set().await || topology_is_sharded().await } pub(crate) async fn fail_command_appname_initial_handshake_supported() -> bool { let requirements = [">= 4.2.15, < 4.3.0", ">= 4.4.7, < 4.5.0", ">= 4.9.0"]; diff --git a/src/test/change_stream.rs b/src/test/change_stream.rs index c0510fd8e..21635d425 100644 --- a/src/test/change_stream.rs +++ b/src/test/change_stream.rs @@ -17,7 +17,6 @@ use crate::{ }; use super::{ - fail_command_supported, get_client_options, log_uncaptured, server_version_gte, @@ -45,10 +44,6 @@ async fn init_stream( log_uncaptured("skipping change stream test on unsupported topology"); return Ok(None); } - if !fail_command_supported().await { - log_uncaptured("skipping change stream test on version without fail commands"); - return Ok(None); - } let mut options = get_client_options().await.clone(); // Direct connection is needed for reliable behavior with fail points. @@ -290,15 +285,10 @@ async fn resume_kill_cursor_error_suppressed() -> Result<()> { // Prose test 10: removed. -/// Prose test 11: Running against a server >=4.0.7, resume token at the end of a batch must return -/// the postBatchResumeToken from the current command response +/// Prose test 11: Resume token at the end of a batch must return the postBatchResumeToken from the +/// current command response #[tokio::test] async fn batch_end_resume_token() -> Result<()> { - if !server_version_matches(">=4.0.7").await { - log_uncaptured("skipping change stream test due to server version"); - return Ok(()); - } - let (client, _, mut stream) = match init_stream("batch_end_resume_token", false).await? { Some(t) => t, None => return Ok(()), @@ -393,11 +383,6 @@ async fn aggregate_batch() -> Result<()> { /// Prose test 17: Resuming a change stream with no results uses `startAfter`. #[tokio::test(flavor = "multi_thread")] // multi_thread required for FailPoint async fn resume_uses_start_after() -> Result<()> { - if !server_version_matches(">=4.1.1").await { - log_uncaptured("skipping change stream test on unsupported version"); - return Ok(()); - } - let (client, coll, mut stream) = match init_stream("resume_uses_start_after", true).await? { Some(t) => t, None => return Ok(()), @@ -438,11 +423,6 @@ async fn resume_uses_start_after() -> Result<()> { /// Prose test 18: Resuming a change stream after results uses `resumeAfter`. #[tokio::test(flavor = "multi_thread")] // multi_thread required for FailPoint async fn resume_uses_resume_after() -> Result<()> { - if !server_version_matches(">=4.1.1").await { - log_uncaptured("skipping change stream test on unsupported version"); - return Ok(()); - } - let (client, coll, mut stream) = match init_stream("resume_uses_resume_after", true).await? { Some(t) => t, None => return Ok(()), diff --git a/src/test/coll.rs b/src/test/coll.rs index 28d43d9cf..38a00cab0 100644 --- a/src/test/coll.rs +++ b/src/test/coll.rs @@ -44,7 +44,7 @@ use crate::{ #[tokio::test] #[function_name::named] async fn insert_err_details() { - if server_version_lt(4, 0).await || !topology_is_replica_set().await { + if !topology_is_replica_set().await { log_uncaptured("skipping insert_err_details due to test configuration"); return; } @@ -599,11 +599,6 @@ async fn delete_hint_not_specified() { } async fn find_one_and_delete_hint_test(options: Option, name: &str) { - if options.is_some() && server_version_lt(4, 2).await { - log_uncaptured("skipping find_one_and_delete_hint_test due to test configuration"); - return; - } - let client = Client::for_test().monitor_events().await; let coll = client.database(name).collection(name); @@ -661,10 +656,7 @@ async fn find_one_and_delete_hint_server_version() { .hint(Hint::Name(String::new())) .await; - if server_version_lt(4, 2).await { - let error = res.expect_err("find one and delete should fail"); - assert!(matches!(*error.kind, ErrorKind::InvalidArgument { .. })); - } else if server_version_eq(4, 2).await { + if server_version_eq(4, 2).await { let error = res.expect_err("find one and delete should fail"); assert!(matches!(*error.kind, ErrorKind::Command { .. })); } else { diff --git a/src/test/spec/gridfs.rs b/src/test/spec/gridfs.rs index 64ed53990..84d62f1e7 100644 --- a/src/test/spec/gridfs.rs +++ b/src/test/spec/gridfs.rs @@ -9,7 +9,6 @@ use crate::{ options::{FindOneOptions, GridFsBucketOptions, GridFsUploadOptions}, runtime, test::{ - fail_command_supported, get_client_options, spec::unified_runner::run_unified_tests, topology_is_sharded, @@ -216,10 +215,6 @@ async fn upload_stream_errors() { upload_stream.abort().await.unwrap(); assert_closed(&bucket, upload_stream).await; - if !fail_command_supported().await { - return; - } - // Error attempting to write to stream after write failure. let mut upload_stream = bucket .open_upload_stream("upload_stream_errors") diff --git a/src/test/spec/retryable_reads.rs b/src/test/spec/retryable_reads.rs index f330c1227..50cd12e2c 100644 --- a/src/test/spec/retryable_reads.rs +++ b/src/test/spec/retryable_reads.rs @@ -11,8 +11,6 @@ use crate::{ options::SelectionCriteria, runtime::{self, AsyncJoinHandle}, test::{ - block_connection_supported, - fail_command_supported, get_client_options, log_uncaptured, spec::unified_runner::run_unified_tests, @@ -36,11 +34,6 @@ async fn run_unified() { /// pool before the second attempt. #[tokio::test(flavor = "multi_thread")] async fn retry_releases_connection() { - if !fail_command_supported().await { - log_uncaptured("skipping retry_releases_connection due to failCommand not being supported"); - return; - } - let mut client_options = get_client_options().await.clone(); client_options.hosts.drain(1..); client_options.retry_reads = Some(true); @@ -71,12 +64,6 @@ async fn retry_releases_connection() { /// Prose test from retryable reads spec verifying that PoolClearedErrors are retried. #[tokio::test(flavor = "multi_thread")] async fn retry_read_pool_cleared() { - if !block_connection_supported().await { - log_uncaptured( - "skipping retry_read_pool_cleared due to blockConnection not being supported", - ); - return; - } if topology_is_load_balanced().await { log_uncaptured("skipping retry_read_pool_cleared due to load-balanced topology"); return; @@ -159,10 +146,6 @@ async fn retry_read_pool_cleared() { // Retryable Reads Are Retried on a Different mongos if One is Available #[tokio::test(flavor = "multi_thread")] async fn retry_read_different_mongos() { - if !fail_command_supported().await { - log_uncaptured("skipping retry_read_different_mongos: requires failCommand"); - return; - } let mut client_options = get_client_options().await.clone(); if !(topology_is_sharded().await && client_options.hosts.len() >= 2) { log_uncaptured( @@ -242,10 +225,6 @@ async fn retry_read_different_mongos() { // Retryable Reads Are Retried on the Same mongos if No Others are Available #[tokio::test(flavor = "multi_thread")] async fn retry_read_same_mongos() { - if !fail_command_supported().await { - log_uncaptured("skipping retry_read_same_mongos: requires failCommand"); - return; - } if !topology_is_sharded().await { log_uncaptured("skipping retry_read_same_mongos: requires sharded cluster"); return; diff --git a/src/test/spec/retryable_writes.rs b/src/test/spec/retryable_writes.rs index cd88b7e51..bbc6581a8 100644 --- a/src/test/spec/retryable_writes.rs +++ b/src/test/spec/retryable_writes.rs @@ -5,18 +5,15 @@ use tokio::sync::Mutex; use crate::{ bson::{doc, Document}, - error::{ErrorKind, Result, RETRYABLE_WRITE_ERROR}, + error::{Result, RETRYABLE_WRITE_ERROR}, event::{ cmap::{CmapEvent, ConnectionCheckoutFailedReason}, command::CommandEvent, }, runtime::{self, spawn, AcknowledgedMessage, AsyncJoinHandle}, test::{ - block_connection_supported, - fail_command_supported, get_client_options, log_uncaptured, - server_version_gt, server_version_lt, spec::unified_runner::run_unified_tests, topology_is_load_balanced, @@ -41,45 +38,6 @@ async fn run_unified() { .await; } -#[tokio::test] -#[function_name::named] -async fn mmapv1_error_raised() { - if server_version_gt(4, 0).await || !topology_is_replica_set().await { - log_uncaptured("skipping mmapv1_error_raised due to test topology"); - return; - } - - let client = Client::for_test().await; - let coll = client.init_db_and_coll(function_name!(), "coll").await; - - let server_status = client - .database(function_name!()) - .run_command(doc! { "serverStatus": 1 }) - .await - .unwrap(); - let name = server_status - .get_document("storageEngine") - .unwrap() - .get_str("name") - .unwrap(); - if name != "mmapv1" { - log_uncaptured("skipping mmapv1_error_raised due to unsupported storage engine"); - return; - } - - let err = coll.insert_one(doc! { "x": 1 }).await.unwrap_err(); - match *err.kind { - ErrorKind::Command(err) => { - assert_eq!( - err.message, - "This MongoDB deployment does not support retryable writes. Please add \ - retryWrites=false to your connection string." - ); - } - e => panic!("expected command error, got: {e:?}"), - } -} - #[tokio::test] async fn label_not_added_first_read_error() { label_not_added(false).await; @@ -92,11 +50,6 @@ async fn label_not_added_second_read_error() { #[function_name::named] async fn label_not_added(retry_reads: bool) { - if !fail_command_supported().await { - log_uncaptured("skipping label_not_added due to fail command unsupported"); - return; - } - let mut options = get_client_options().await.clone(); options.retry_reads = Some(retry_reads); let client = Client::for_test() @@ -138,12 +91,6 @@ async fn retry_write_pool_cleared() { log_uncaptured("skipping retry_write_pool_cleared due to load-balanced topology"); return; } - if !block_connection_supported().await { - log_uncaptured( - "skipping retry_write_pool_cleared due to blockConnection not being supported", - ); - return; - } let buffer = EventBuffer::new(); @@ -304,10 +251,6 @@ async fn retry_write_retryable_write_error() { // Test that in a sharded cluster writes are retried on a different mongos if one available #[tokio::test(flavor = "multi_thread")] async fn retry_write_different_mongos() { - if !fail_command_supported().await { - log_uncaptured("skipping retry_write_different_mongos: requires failCommand"); - return; - } let mut client_options = get_client_options().await.clone(); if !(topology_is_sharded().await && client_options.hosts.len() >= 2) { log_uncaptured( @@ -388,10 +331,6 @@ async fn retry_write_different_mongos() { // Retryable Reads Are Retried on the Same mongos if No Others are Available #[tokio::test(flavor = "multi_thread")] async fn retry_write_same_mongos() { - if !fail_command_supported().await { - log_uncaptured("skipping retry_write_same_mongos: requires failCommand"); - return; - } if !topology_is_sharded().await { log_uncaptured("skipping retry_write_same_mongos: requires sharded cluster"); return; diff --git a/src/test/spec/sdam.rs b/src/test/spec/sdam.rs index 7e7bd9f25..9b78c5a50 100644 --- a/src/test/spec/sdam.rs +++ b/src/test/spec/sdam.rs @@ -7,7 +7,6 @@ use crate::{ hello::LEGACY_HELLO_COMMAND_NAME, runtime, test::{ - block_connection_supported, get_client_options, log_uncaptured, spec::unified_runner::run_unified_tests, @@ -161,10 +160,6 @@ async fn rtt_is_updated() { log_uncaptured("skipping rtt_is_updated due to load balanced topology"); return; } - if !block_connection_supported().await { - log_uncaptured("skipping rtt_is_updated due to not supporting block_connection"); - return; - } let app_name = "streamingRttTest"; diff --git a/src/test/spec/transactions.rs b/src/test/spec/transactions.rs index 29349d97d..754fdfdf3 100644 --- a/src/test/spec/transactions.rs +++ b/src/test/spec/transactions.rs @@ -9,7 +9,6 @@ use crate::{ test::{ get_client_options, log_uncaptured, - server_version_lt, spec::unified_runner::run_unified_tests, topology_is_sharded, transactions_supported, @@ -39,7 +38,7 @@ async fn run_unified_convenient_api() { #[tokio::test(flavor = "multi_thread")] #[function_name::named] async fn deserialize_recovery_token() { - if !topology_is_sharded().await || server_version_lt(4, 2).await { + if !topology_is_sharded().await { log_uncaptured("skipping deserialize_recovery_token due to test topology"); return; } diff --git a/src/test/util.rs b/src/test/util.rs index b3c04f2b1..526e9af95 100644 --- a/src/test/util.rs +++ b/src/test/util.rs @@ -17,7 +17,7 @@ use crate::{ error::Result, hello::{hello_command, HelloCommandResponse}, options::{AuthMechanism, ClientOptions, CollectionOptions, CreateCollectionOptions}, - test::{get_client_options, server_version_gte, topology_is_sharded}, + test::{get_client_options, topology_is_sharded}, BoxFuture, Client, Collection, @@ -155,7 +155,7 @@ impl TestClient { cmd.insert("pwd", pwd); } - if server_version_gte(4, 0).await && !mechanisms.is_empty() { + if !mechanisms.is_empty() { let ms: crate::bson::Array = mechanisms.iter().map(|s| Bson::from(s.as_str())).collect(); cmd.insert("mechanisms", ms);