[cli/server] Add tests for signal handling (#2481)

This commit is contained in:
Salvador Girones Gil 2023-08-21 14:58:53 +02:00 committed by GitHub
parent 2bb078b7dc
commit 2deab8429c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 101 additions and 0 deletions

View file

@ -414,3 +414,93 @@ fn validate_failed_due_to_invalid_surql_files_syntax() {
assert!(common::run_in_dir("validate", &temp_dir).output().is_err()); assert!(common::run_in_dir("validate", &temp_dir).output().is_err());
} }
#[test(tokio::test)]
async fn test_server_graceful_shutdown() {
let (_, mut server) = common::start_server(StartServerArguments {
auth: false,
tls: false,
wait_is_ready: true,
tick_interval: ONE_SEC,
})
.await
.unwrap();
info!("* Send SIGINT signal");
server.send_signal(nix::sys::signal::Signal::SIGINT).expect("Failed to send SIGINT to server");
info!("* Waiting for server to exit gracefully ...");
tokio::select! {
_ = async {
loop {
if let Ok(Some(exit)) = server.status() {
assert!(exit.success(), "Server shutted down successfully");
break;
}
tokio::time::sleep(time::Duration::from_secs(1)).await;
}
} => {},
// Timeout after 5 seconds
_ = tokio::time::sleep(time::Duration::from_secs(5)) => {
panic!("Server didn't exit after receiving SIGINT");
}
}
}
#[test(tokio::test)]
async fn test_server_second_signal_handling() {
let (addr, mut server) = common::start_server(StartServerArguments {
auth: false,
tls: false,
wait_is_ready: true,
tick_interval: ONE_SEC,
})
.await
.unwrap();
// Create a long-lived WS connection so the server don't shutdown gracefully
let mut socket = common::connect_ws(&addr).await.expect("Failed to connect to server");
let json = serde_json::json!({
"id": "1",
"method": "query",
"params": ["SLEEP 30s;"],
});
common::ws_send_msg(&mut socket, serde_json::to_string(&json).unwrap())
.await
.expect("Failed to send WS message");
info!("* Send first SIGINT signal");
server.send_signal(nix::sys::signal::Signal::SIGINT).expect("Failed to send SIGINT to server");
tokio::select! {
_ = async {
loop {
if let Ok(Some(exit)) = server.status() {
panic!("Server unexpectedly exited after receiving first SIGINT: {:?}", exit);
}
tokio::time::sleep(time::Duration::from_secs(1)).await;
}
} => {},
// Timeout after 5 seconds
_ = tokio::time::sleep(time::Duration::from_secs(5)) => ()
}
info!("* Send second SIGINT signal");
server.send_signal(nix::sys::signal::Signal::SIGINT).expect("Failed to send SIGINT to server");
tokio::select! {
_ = async {
loop {
if let Ok(Some(exit)) = server.status() {
assert!(exit.success(), "Server shutted down successfully");
break;
}
tokio::time::sleep(time::Duration::from_secs(1)).await;
}
} => {},
// Timeout after 5 seconds
_ = tokio::time::sleep(time::Duration::from_secs(5)) => {
panic!("Server didn't exit after receiving two SIGINT signals");
}
}
}

View file

@ -43,6 +43,17 @@ impl Child {
self self
} }
pub fn send_signal(&self, signal: nix::sys::signal::Signal) -> nix::Result<()> {
nix::sys::signal::kill(
nix::unistd::Pid::from_raw(self.inner.as_ref().unwrap().id() as i32),
signal,
)
}
pub fn status(&mut self) -> std::io::Result<Option<std::process::ExitStatus>> {
self.inner.as_mut().unwrap().try_wait()
}
/// Read the child's stdout concatenated with its stderr. Returns Ok if the child /// Read the child's stdout concatenated with its stderr. Returns Ok if the child
/// returns successfully, Err otherwise. /// returns successfully, Err otherwise.
pub fn output(mut self) -> Result<String, String> { pub fn output(mut self) -> Result<String, String> {