use std::{fs::canonicalize, process::exit, time::Duration};
use cargo_shuttle::{Command, ProjectArgs, RunArgs, Shuttle, ShuttleArgs};
use portpicker::pick_unused_port;
use tokio::time::sleep;
async fn shuttle_run(working_directory: &str, external: bool) -> String {
let working_directory = match canonicalize(working_directory) {
Ok(wd) => wd,
Err(e) => {
println!(
"Did not find directory: {} !!! because {:?}",
working_directory, e
);
sleep(Duration::from_millis(500)).await;
canonicalize(working_directory).unwrap()
}
};
let port = pick_unused_port().unwrap();
let url = if !external {
format!("http://localhost:{port}")
} else {
format!("http://0.0.0.0:{port}")
};
let runner = Shuttle::new(cargo_shuttle::Binary::Shuttle, None)
.unwrap()
.run(
ShuttleArgs {
api_url: Some("http://shuttle.invalid:80".to_string()),
admin: false,
api_env: None,
project_args: ProjectArgs {
working_directory: working_directory.clone(),
name: None,
id: None,
},
offline: false,
debug: false,
output_mode: Default::default(),
cmd: Command::Run(RunArgs {
port,
external,
..Default::default()
}),
},
false,
);
tokio::spawn({
let working_directory = working_directory.clone();
async move {
sleep(Duration::from_secs(10 * 60)).await;
println!(
"run test for '{}' took too long. Did it fail to shutdown?",
working_directory.display()
);
exit(1);
}
});
let runner_handle = tokio::spawn(runner);
let mut counter = 0;
let client = reqwest::Client::new();
while client.get(url.clone()).send().await.is_err() {
if runner_handle.is_finished() {
println!(
"run test for '{}' exited early. Did it fail to compile/run?",
working_directory.clone().display()
);
exit(1);
}
if counter == 0 {
println!(
"waiting for '{}' to start up...",
working_directory.display()
);
}
counter = (counter + 1) % 10;
sleep(Duration::from_millis(500)).await;
}
url
}
#[tokio::test(flavor = "multi_thread")]
async fn axum_hello_world() {
let url = shuttle_run("../examples/axum/hello-world", false).await;
let request_text = reqwest::Client::new()
.get(url)
.send()
.await
.unwrap()
.text()
.await
.unwrap();
assert_eq!(request_text, "Hello, world!");
}
#[tokio::test(flavor = "multi_thread")]
async fn rocket_secrets() {
std::fs::copy(
"../examples/rocket/secrets/Secrets.toml.example",
"../examples/rocket/secrets/Secrets.toml",
)
.unwrap();
let url = shuttle_run("../examples/rocket/secrets", false).await;
let request_text = reqwest::Client::new()
.get(format!("{url}/secret"))
.send()
.await
.unwrap()
.text()
.await
.unwrap();
assert_eq!(request_text, "the contents of my API key");
}
mod needs_docker {
use super::*;
#[tokio::test(flavor = "multi_thread")]
async fn rocket_postgres() {
let url = shuttle_run("../examples/rocket/postgres", false).await;
let client = reqwest::Client::new();
let post_text = client
.post(format!("{url}/todo"))
.body("{\"note\": \"Deploy to shuttle\"}")
.send()
.await
.unwrap()
.text()
.await
.unwrap();
assert_eq!(post_text, "{\"id\":1,\"note\":\"Deploy to shuttle\"}");
let request_text = client
.get(format!("{url}/todo/1"))
.send()
.await
.unwrap()
.text()
.await
.unwrap();
assert_eq!(request_text, "{\"id\":1,\"note\":\"Deploy to shuttle\"}");
}
}