Skip to content

Commit ecb5108

Browse files
authored
RUST-1636 Add RunCommand Test Specification (#901)
Add runCommand specification and remove readConcern and writeConcern options from unified test runCommand operation
1 parent a44f669 commit ecb5108

File tree

15 files changed

+2278
-61
lines changed

15 files changed

+2278
-61
lines changed

src/concern/test.rs

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -114,18 +114,6 @@ async fn inconsistent_write_concern_rejected() {
114114

115115
let client = TestClient::new().await;
116116
let db = client.database(function_name!());
117-
let error = db
118-
.run_command(
119-
doc! {
120-
"insert": function_name!(),
121-
"documents": [ {} ],
122-
"writeConcern": { "w": 0, "j": true }
123-
},
124-
None,
125-
)
126-
.await
127-
.expect_err("insert should fail");
128-
assert!(matches!(*error.kind, ErrorKind::InvalidArgument { .. }));
129117

130118
let coll = db.collection(function_name!());
131119
let wc = WriteConcern {
@@ -149,15 +137,15 @@ async fn unacknowledged_write_concern_rejected() {
149137

150138
let client = TestClient::new().await;
151139
let db = client.database(function_name!());
152-
let error = db
153-
.run_command(
154-
doc! {
155-
"insert": function_name!(),
156-
"documents": [ {} ],
157-
"writeConcern": { "w": 0 }
158-
},
159-
None,
160-
)
140+
let coll = db.collection(function_name!());
141+
let wc = WriteConcern {
142+
w: Acknowledgment::Nodes(0).into(),
143+
journal: false.into(),
144+
w_timeout: None,
145+
};
146+
let options = InsertOneOptions::builder().write_concern(wc).build();
147+
let error = coll
148+
.insert_one(doc! {}, options)
161149
.await
162150
.expect_err("insert should fail");
163151
assert!(matches!(*error.kind, ErrorKind::InvalidArgument { .. }));

src/db/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ impl Database {
458458
/// Note that no inspection is done on `doc`, so the command will not use the database's default
459459
/// read concern or write concern. If specific read concern or write concern is desired, it must
460460
/// be specified manually.
461+
/// Please note that run_command doesn't validate WriteConcerns passed into the body of the
462+
/// command document.
461463
pub async fn run_command(
462464
&self,
463465
command: Document,

src/operation/run_command/mod.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use crate::{
1111
client::SESSIONS_UNSUPPORTED_COMMANDS,
1212
cmap::{conn::PinnedConnectionHandle, Command, RawCommandResponse, StreamDescription},
1313
error::{ErrorKind, Result},
14-
options::WriteConcern,
1514
selection_criteria::SelectionCriteria,
1615
};
1716

@@ -20,7 +19,6 @@ pub(crate) struct RunCommand<'conn> {
2019
db: String,
2120
command: RawDocumentBuf,
2221
selection_criteria: Option<SelectionCriteria>,
23-
write_concern: Option<WriteConcern>,
2422
pinned_connection: Option<&'conn PinnedConnectionHandle>,
2523
}
2624

@@ -31,16 +29,10 @@ impl<'conn> RunCommand<'conn> {
3129
selection_criteria: Option<SelectionCriteria>,
3230
pinned_connection: Option<&'conn PinnedConnectionHandle>,
3331
) -> Result<Self> {
34-
let write_concern = command
35-
.get("writeConcern")
36-
.map(|doc| bson::from_bson::<WriteConcern>(doc.clone()))
37-
.transpose()?;
38-
3932
Ok(Self {
4033
db,
4134
command: RawDocumentBuf::from_document(&command)?,
4235
selection_criteria,
43-
write_concern,
4436
pinned_connection,
4537
})
4638
}
@@ -52,17 +44,10 @@ impl<'conn> RunCommand<'conn> {
5244
selection_criteria: Option<SelectionCriteria>,
5345
pinned_connection: Option<&'conn PinnedConnectionHandle>,
5446
) -> Result<Self> {
55-
let write_concern = command
56-
.get("writeConcern")?
57-
.and_then(|b| b.as_document())
58-
.map(|doc| bson::from_slice::<WriteConcern>(doc.as_bytes()))
59-
.transpose()?;
60-
6147
Ok(Self {
6248
db,
6349
command,
6450
selection_criteria,
65-
write_concern,
6651
pinned_connection,
6752
})
6853
}
@@ -121,10 +106,6 @@ impl<'conn> OperationWithDefaults for RunCommand<'conn> {
121106
self.selection_criteria.as_ref()
122107
}
123108

124-
fn write_concern(&self) -> Option<&WriteConcern> {
125-
self.write_concern.as_ref()
126-
}
127-
128109
fn supports_sessions(&self) -> bool {
129110
self.command_name()
130111
.map(|command_name| {

src/sdam/description/topology/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -228,8 +228,9 @@ impl TopologyDescription {
228228
},
229229
Some(other) => other,
230230
};
231-
232-
command.set_read_preference(resolved_read_pref)
231+
if resolved_read_pref != ReadPreference::Primary {
232+
command.set_read_preference(resolved_read_pref)
233+
}
233234
}
234235
_ => {
235236
let read_pref = match criteria {
@@ -239,7 +240,9 @@ impl TopologyDescription {
239240
},
240241
None => ReadPreference::Primary,
241242
};
242-
command.set_read_preference(read_pref)
243+
if read_pref != ReadPreference::Primary {
244+
command.set_read_preference(read_pref)
245+
}
243246
}
244247
}
245248
}

src/selection_criteria.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,8 @@ impl<'de> Deserialize<'de> for ReadPreference {
186186
options: ReadPreferenceOptions,
187187
}
188188
let preference = ReadPreferenceHelper::deserialize(deserializer)?;
189-
190-
match preference.mode.as_str() {
191-
"Primary" => {
189+
match preference.mode.to_ascii_lowercase().as_str() {
190+
"primary" => {
192191
if !preference.options.is_default() {
193192
return Err(D::Error::custom(&format!(
194193
"no options can be specified with read preference mode = primary, but got \
@@ -198,16 +197,16 @@ impl<'de> Deserialize<'de> for ReadPreference {
198197
}
199198
Ok(ReadPreference::Primary)
200199
}
201-
"Secondary" => Ok(ReadPreference::Secondary {
200+
"secondary" => Ok(ReadPreference::Secondary {
202201
options: preference.options,
203202
}),
204-
"PrimaryPreferred" => Ok(ReadPreference::PrimaryPreferred {
203+
"primarypreferred" => Ok(ReadPreference::PrimaryPreferred {
205204
options: preference.options,
206205
}),
207-
"SecondaryPreferred" | "secondaryPreferred" => Ok(ReadPreference::SecondaryPreferred {
206+
"secondarypreferred" => Ok(ReadPreference::SecondaryPreferred {
208207
options: preference.options,
209208
}),
210-
"Nearest" => Ok(ReadPreference::Nearest {
209+
"nearest" => Ok(ReadPreference::Nearest {
211210
options: preference.options,
212211
}),
213212
other => Err(D::Error::custom(format!(
@@ -231,7 +230,6 @@ impl Serialize for ReadPreference {
231230
#[serde(flatten)]
232231
options: Option<&'a ReadPreferenceOptions>,
233232
}
234-
235233
let helper = match self {
236234
ReadPreference::Primary => ReadPreferenceHelper {
237235
mode: "primary",
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
=================
2+
Run Command Tests
3+
=================
4+
5+
.. contents::
6+
7+
----
8+
9+
Introduction
10+
============
11+
12+
The YAML and JSON files in the ``unified`` sub-directories are platform-independent tests
13+
that drivers can use to prove their conformance to the RunCommand spec. Tests in the
14+
``unified`` directory are written using the `Unified Test Format <../../unified-test-format/unified-test-format.rst>`_.

0 commit comments

Comments
 (0)