Skip to content

RUST-332 Return an error for replica set name mismatch #648

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 16, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/sdam/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use semver::VersionReq;
use tokio::sync::{RwLockReadGuard, RwLockWriteGuard};

use crate::{
error::ErrorKind,
error::{Error, ErrorKind},
hello::{LEGACY_HELLO_COMMAND_NAME, LEGACY_HELLO_COMMAND_NAME_LOWERCASE},
runtime,
test::{
Expand Down Expand Up @@ -462,3 +462,32 @@ async fn hello_ok_true() {
.expect("subsequent heartbeats should use hello");
}
}

#[cfg_attr(feature = "tokio-runtime", tokio::test)]
#[cfg_attr(feature = "async-std-runtime", async_std::test)]
async fn repl_set_name_mismatch() -> crate::error::Result<()> {
let _guard = LOCK.run_concurrently().await;

let client = TestClient::new().await;
if !client.is_replica_set() {
log_uncaptured("skipping repl_set_name_mismatch due to non-replica set topology");
return Ok(());
}

let mut options = CLIENT_OPTIONS.clone();
options.hosts.drain(1..);
options.direct_connection = Some(true);
options.repl_set_name = Some("invalid".to_string());
let client = Client::with_options(options)?;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be a Client rather than a TestClient because the latter executes a few operations with unwrap()s, which fail and crash before the test can check anything.

let result = client.list_database_names(None, None).await;
assert!(
match result {
Err(Error { ref kind, .. }) => matches!(**kind, ErrorKind::ServerSelection { .. }),
_ => false,
},
"Unexpected result {:?}",
result
);

Ok(())
}
29 changes: 25 additions & 4 deletions src/sdam/topology.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,13 +472,34 @@ impl TopologyWorker {
}

/// Update the topology using the provided `ServerDescription`.
async fn update_server(&mut self, sd: ServerDescription) -> bool {
let server_type = sd.server_type;
let server_address = sd.address.clone();

async fn update_server(&mut self, mut sd: ServerDescription) -> bool {
let mut latest_state = self.borrow_latest_state().clone();
let old_description = latest_state.description.clone();

if let Some(expected_name) = &self.options.repl_set_name {
let got_name = sd.set_name();
if latest_state.description.topology_type() == TopologyType::Single
&& got_name.as_ref().map(|opt| opt.as_ref()) != Ok(Some(expected_name))
{
let got_display = match got_name {
Ok(Some(s)) => format!("{:?}", s),
Ok(None) => "<none>".to_string(),
Err(s) => format!("<error: {}>", s),
};
// Mark server as unknown.
sd = ServerDescription::new(
sd.address,
Some(Err(format!(
"Connection string replicaSet name {:?} does not match actual name {}",
expected_name, got_display,
))),
);
}
}

let server_type = sd.server_type;
let server_address = sd.address.clone();

// TODO: RUST-1270 change this method to not return a result.
let _ = latest_state.description.update(sd);

Expand Down