Skip to content

Commit b6e4560

Browse files
RUST-991 Perform wire check when commitQuorum is provided to createIndexes (#443)
1 parent 280c87e commit b6e4560

File tree

5 files changed

+327
-283
lines changed

5 files changed

+327
-283
lines changed

src/operation/create_indexes/mod.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ mod test;
44
use crate::{
55
bson::{doc, Document},
66
cmap::{Command, StreamDescription},
7-
error::Result,
7+
error::{ErrorKind, Result},
88
index::IndexModel,
99
operation::{append_options, Operation},
1010
options::{CreateIndexOptions, WriteConcern},
@@ -53,7 +53,22 @@ impl Operation for CreateIndexes {
5353
type Response = CommandResponse<WriteConcernOnlyBody>;
5454
const NAME: &'static str = "createIndexes";
5555

56-
fn build(&mut self, _description: &StreamDescription) -> Result<Command> {
56+
fn build(&mut self, description: &StreamDescription) -> Result<Command> {
57+
// commit quorum is not supported on < 4.4
58+
if description.max_wire_version.unwrap_or(0) < 9
59+
&& self
60+
.options
61+
.as_ref()
62+
.map_or(false, |options| options.commit_quorum.is_some())
63+
{
64+
return Err(ErrorKind::InvalidArgument {
65+
message: "Specifying a commit quorum to create_index(es) is not supported on \
66+
server versions < 4.4"
67+
.to_string(),
68+
}
69+
.into());
70+
}
71+
5772
self.indexes.iter_mut().for_each(|i| i.update_name()); // Generate names for unnamed indexes.
5873
let indexes = bson::to_bson(&self.indexes)?;
5974
let mut body = doc! {

src/operation/create_indexes/test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ async fn build() {
3636
let mut create_indexes = CreateIndexes::new(ns, vec![index_model], Some(create_options));
3737

3838
let cmd = create_indexes
39-
.build(&StreamDescription::new_testing())
39+
.build(&StreamDescription::with_wire_version(10))
4040
.expect("CreateIndexes command failed to build when it should have succeeded.");
4141

4242
assert_eq!(

src/test/coll.rs

Lines changed: 0 additions & 280 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use tokio::sync::{RwLockReadGuard, RwLockWriteGuard};
99
use crate::{
1010
bson::{doc, to_document, Bson, Document},
1111
error::{ErrorKind, Result, WriteFailure},
12-
index::{options::IndexOptions, IndexModel},
1312
options::{
1413
Acknowledgment,
1514
AggregateOptions,
@@ -1050,282 +1049,3 @@ async fn collection_generic_bounds() {
10501049
.collection(function_name!());
10511050
let _result = coll.insert_one(Bar {}, None).await;
10521051
}
1053-
1054-
// Test that creating indexes works as expected.
1055-
#[cfg_attr(feature = "tokio-runtime", tokio::test)]
1056-
#[cfg_attr(feature = "async-std-runtime", async_std::test)]
1057-
#[function_name::named]
1058-
async fn index_management_creates() {
1059-
let _guard: RwLockReadGuard<()> = LOCK.run_concurrently().await;
1060-
let client = TestClient::new().await;
1061-
let coll = client
1062-
.init_db_and_coll(function_name!(), function_name!())
1063-
.await;
1064-
1065-
// Test creating a single index with driver-generated name.
1066-
let result = coll
1067-
.create_index(
1068-
IndexModel::builder()
1069-
.keys(bson::doc! { "a": 1, "b": -1 })
1070-
.build(),
1071-
None,
1072-
)
1073-
.await
1074-
.expect("Test failed to create index");
1075-
1076-
assert_eq!(result.index_name, "a_1_b_-1".to_string());
1077-
1078-
// Test creating several indexes, with both specified and unspecified names.
1079-
let result = coll
1080-
.create_indexes(
1081-
vec![
1082-
IndexModel::builder().keys(bson::doc! { "c": 1 }).build(),
1083-
IndexModel::builder()
1084-
.keys(bson::doc! { "d": 1 })
1085-
.options(
1086-
IndexOptions::builder()
1087-
.name("customname".to_string())
1088-
.build(),
1089-
)
1090-
.build(),
1091-
],
1092-
None,
1093-
)
1094-
.await
1095-
.expect("Test failed to create indexes");
1096-
1097-
assert_eq!(
1098-
result.index_names,
1099-
vec!["c_1".to_string(), "customname".to_string()]
1100-
);
1101-
1102-
// Pull all index names from db to verify the _id_ index.
1103-
let names = coll
1104-
.list_index_names()
1105-
.await
1106-
.expect("Test failed to list index names");
1107-
assert_eq!(names, vec!["_id_", "a_1_b_-1", "c_1", "customname"]);
1108-
}
1109-
1110-
// Test that creating a duplicate index works as expected.
1111-
#[cfg_attr(feature = "tokio-runtime", tokio::test)]
1112-
#[cfg_attr(feature = "async-std-runtime", async_std::test)]
1113-
#[function_name::named]
1114-
async fn index_management_handles_duplicates() {
1115-
let _guard: RwLockReadGuard<()> = LOCK.run_concurrently().await;
1116-
let client = TestClient::new().await;
1117-
let coll = client
1118-
.init_db_and_coll(function_name!(), function_name!())
1119-
.await;
1120-
1121-
let result = coll
1122-
.create_index(
1123-
IndexModel::builder().keys(bson::doc! { "a": 1 }).build(),
1124-
None,
1125-
)
1126-
.await
1127-
.expect("Test failed to create index");
1128-
1129-
assert_eq!(result.index_name, "a_1".to_string());
1130-
1131-
// Insert duplicate.
1132-
let result = coll
1133-
.create_index(
1134-
IndexModel::builder().keys(bson::doc! { "a": 1 }).build(),
1135-
None,
1136-
)
1137-
.await
1138-
.expect("Test failed to create index");
1139-
1140-
assert_eq!(result.index_name, "a_1".to_string());
1141-
1142-
// Test partial duplication.
1143-
let result = coll
1144-
.create_indexes(
1145-
vec![
1146-
IndexModel::builder().keys(bson::doc! { "a": 1 }).build(), // Duplicate
1147-
IndexModel::builder().keys(bson::doc! { "b": 1 }).build(), // Not duplicate
1148-
],
1149-
None,
1150-
)
1151-
.await
1152-
.expect("Test failed to create indexes");
1153-
1154-
assert_eq!(
1155-
result.index_names,
1156-
vec!["a_1".to_string(), "b_1".to_string()]
1157-
);
1158-
}
1159-
1160-
// Test that listing indexes works as expected.
1161-
#[cfg_attr(feature = "tokio-runtime", tokio::test)]
1162-
#[cfg_attr(feature = "async-std-runtime", async_std::test)]
1163-
#[function_name::named]
1164-
async fn index_management_lists() {
1165-
let _guard: RwLockReadGuard<()> = LOCK.run_concurrently().await;
1166-
let client = TestClient::new().await;
1167-
let coll = client
1168-
.init_db_and_coll(function_name!(), function_name!())
1169-
.await;
1170-
1171-
let insert_data = vec![
1172-
IndexModel::builder().keys(bson::doc! { "a": 1 }).build(),
1173-
IndexModel::builder()
1174-
.keys(bson::doc! { "b": 1, "c": 1 })
1175-
.build(),
1176-
IndexModel::builder()
1177-
.keys(bson::doc! { "d": 1 })
1178-
.options(IndexOptions::builder().unique(Some(true)).build())
1179-
.build(),
1180-
];
1181-
1182-
coll.create_indexes(insert_data.clone(), None)
1183-
.await
1184-
.expect("Test failed to create indexes");
1185-
1186-
let expected_names = vec![
1187-
"_id_".to_string(),
1188-
"a_1".to_string(),
1189-
"b_1_c_1".to_string(),
1190-
"d_1".to_string(),
1191-
];
1192-
1193-
let mut indexes = coll
1194-
.list_indexes(None)
1195-
.await
1196-
.expect("Test failed to list indexes");
1197-
1198-
let id = indexes.try_next().await.unwrap().unwrap();
1199-
assert_eq!(id.get_name().unwrap(), expected_names[0]);
1200-
assert!(!id.is_unique());
1201-
1202-
let a = indexes.try_next().await.unwrap().unwrap();
1203-
assert_eq!(a.get_name().unwrap(), expected_names[1]);
1204-
assert!(!a.is_unique());
1205-
1206-
let b_c = indexes.try_next().await.unwrap().unwrap();
1207-
assert_eq!(b_c.get_name().unwrap(), expected_names[2]);
1208-
assert!(!b_c.is_unique());
1209-
1210-
// Unique index.
1211-
let d = indexes.try_next().await.unwrap().unwrap();
1212-
assert_eq!(d.get_name().unwrap(), expected_names[3]);
1213-
assert!(d.is_unique());
1214-
1215-
assert!(indexes.try_next().await.unwrap().is_none());
1216-
1217-
let names = coll
1218-
.list_index_names()
1219-
.await
1220-
.expect("Test failed to list index names");
1221-
1222-
assert_eq!(names, expected_names);
1223-
}
1224-
1225-
// Test that dropping indexes works as expected.
1226-
#[cfg_attr(feature = "tokio-runtime", tokio::test)]
1227-
#[cfg_attr(feature = "async-std-runtime", async_std::test)]
1228-
#[function_name::named]
1229-
async fn index_management_drops() {
1230-
let _guard: RwLockReadGuard<()> = LOCK.run_concurrently().await;
1231-
let client = TestClient::new().await;
1232-
let coll = client
1233-
.init_db_and_coll(function_name!(), function_name!())
1234-
.await;
1235-
1236-
let result = coll
1237-
.create_indexes(
1238-
vec![
1239-
IndexModel::builder().keys(bson::doc! { "a": 1 }).build(),
1240-
IndexModel::builder().keys(bson::doc! { "b": 1 }).build(),
1241-
IndexModel::builder().keys(bson::doc! { "c": 1 }).build(),
1242-
],
1243-
None,
1244-
)
1245-
.await
1246-
.expect("Test failed to create multiple indexes");
1247-
1248-
assert_eq!(
1249-
result.index_names,
1250-
vec!["a_1".to_string(), "b_1".to_string(), "c_1".to_string()]
1251-
);
1252-
1253-
// Test dropping single index.
1254-
coll.drop_index("a_1", None)
1255-
.await
1256-
.expect("Test failed to drop index");
1257-
let names = coll
1258-
.list_index_names()
1259-
.await
1260-
.expect("Test failed to list index names");
1261-
assert_eq!(names, vec!["_id_", "b_1", "c_1"]);
1262-
1263-
// Test dropping several indexes.
1264-
coll.drop_indexes(None)
1265-
.await
1266-
.expect("Test failed to drop indexes");
1267-
let names = coll
1268-
.list_index_names()
1269-
.await
1270-
.expect("Test failed to list index names");
1271-
assert_eq!(names, vec!["_id_"]);
1272-
}
1273-
1274-
// Test that index management commands execute the expected database commands.
1275-
#[cfg_attr(feature = "tokio-runtime", tokio::test)]
1276-
#[cfg_attr(feature = "async-std-runtime", async_std::test)]
1277-
#[function_name::named]
1278-
async fn index_management_executes_commands() {
1279-
let _guard: RwLockReadGuard<()> = LOCK.run_concurrently().await;
1280-
let client = EventClient::new().await;
1281-
let coll = client
1282-
.init_db_and_coll(function_name!(), function_name!())
1283-
.await;
1284-
1285-
// Collection::create_index and Collection::create_indexes execute createIndexes.
1286-
assert_eq!(
1287-
client.get_command_started_events(&["createIndexes"]).len(),
1288-
0
1289-
);
1290-
coll.create_index(
1291-
IndexModel::builder().keys(bson::doc! { "a": 1 }).build(),
1292-
None,
1293-
)
1294-
.await
1295-
.expect("Create Index op failed");
1296-
assert_eq!(
1297-
client.get_command_started_events(&["createIndexes"]).len(),
1298-
1
1299-
);
1300-
coll.create_indexes(
1301-
vec![
1302-
IndexModel::builder().keys(bson::doc! { "b": 1 }).build(),
1303-
IndexModel::builder().keys(bson::doc! { "c": 1 }).build(),
1304-
],
1305-
None,
1306-
)
1307-
.await
1308-
.expect("Create Indexes op failed");
1309-
assert_eq!(
1310-
client.get_command_started_events(&["createIndexes"]).len(),
1311-
2
1312-
);
1313-
1314-
// Collection::list_indexes and Collection::list_index_names execute listIndexes.
1315-
assert_eq!(client.get_command_started_events(&["listIndexes"]).len(), 0);
1316-
coll.list_indexes(None).await.expect("List index op failed");
1317-
assert_eq!(client.get_command_started_events(&["listIndexes"]).len(), 1);
1318-
coll.list_index_names().await.expect("List index op failed");
1319-
assert_eq!(client.get_command_started_events(&["listIndexes"]).len(), 2);
1320-
1321-
// Collection::drop_index and Collection::drop_indexes execute dropIndexes.
1322-
assert_eq!(client.get_command_started_events(&["dropIndexes"]).len(), 0);
1323-
coll.drop_index("a_1", None)
1324-
.await
1325-
.expect("Drop index op failed");
1326-
assert_eq!(client.get_command_started_events(&["dropIndexes"]).len(), 1);
1327-
coll.drop_indexes(None)
1328-
.await
1329-
.expect("Drop indexes op failed");
1330-
assert_eq!(client.get_command_started_events(&["dropIndexes"]).len(), 2);
1331-
}

0 commit comments

Comments
 (0)