use std::fs::File;
use std::io::Read;
use std::path::Path;
use std::path::PathBuf;
use std::time::Duration;
use clienter::HttpHeaders;
use rand::seq::SliceRandom;
use tracing::debug;
use tracing::Span;
pub fn test_helper_data_dir() -> PathBuf {
const TEST_DATA_DIR_NAME: &str = "test_data/";
let mut path = PathBuf::new();
path.push(TEST_DATA_DIR_NAME);
path
}
pub fn load_test_proof_servers() -> Vec<String> {
let mut server_list_path = test_helper_data_dir();
server_list_path.push(Path::new("proof_servers").with_extension("txt"));
let Ok(mut input_file) = File::open(server_list_path.clone()) else {
debug!(
"cannot find proof-server list '{}' -- file might not exist",
server_list_path.display()
);
return vec![];
};
let mut file_contents = vec![];
if input_file.read_to_end(&mut file_contents).is_err() {
debug!("cannot read file '{}'", server_list_path.display());
return vec![];
}
let Ok(file_as_string) = String::from_utf8(file_contents) else {
debug!(
"cannot parse file '{}' -- is it valid utf8?",
server_list_path.display()
);
return vec![];
};
file_as_string.lines().map(|s| s.to_string()).collect()
}
pub fn try_load_file_from_disk(path: &Path) -> Option<Vec<u8>> {
let Ok(mut input_file) = File::open(path) else {
debug!("cannot open file '{}' -- might not exist", path.display());
return None;
};
let mut file_contents = vec![];
if input_file.read_to_end(&mut file_contents).is_err() {
debug!("cannot read file '{}'", path.display());
return None;
}
Some(file_contents)
}
pub fn try_fetch_from_server(
filename: String,
server: String,
headers: HttpHeaders,
) -> Option<Vec<u8>> {
let filename_ = filename.clone();
let server_ = server.clone();
let handle = std::thread::spawn(move || {
let server__ = &server_;
let filename__ = &filename_;
let url = format!("{server__}{filename__}");
debug!("requesting: <{url}>");
let uri: clienter::Uri = url.into();
let mut http_client = clienter::HttpClient::new();
http_client.timeout = Some(Duration::from_millis(1600));
http_client.headers = headers;
let request = http_client.request(clienter::HttpMethod::GET, uri);
let Ok(mut response) = http_client.send(&request) else {
println!("server '{server__}' failed for file '{filename__}'; trying next ...",);
return None;
};
let body = if response.status.is_success() {
response.body()
} else {
Ok(vec![])
};
Some((response.status, body))
});
let Some((status_code, body)) = handle.join().unwrap() else {
eprintln!("Could not connect to server {server}.");
return None;
};
if !status_code.is_success() {
eprintln!("{server} responded with {status_code}");
return None;
}
println!("{server} responded with successful HTTP status code");
let Ok(file_contents) = body else {
eprintln!("error reading file '{filename}' from server '{server}'");
return None;
};
Some(file_contents)
}
pub fn headers_for_proof_server_request() -> clienter::HttpHeaders {
const TEST_NAME_HTTP_HEADER_KEY: &str = "Test-Name";
fn get_test_name_from_tracing() -> String {
match Span::current().metadata().map(|x| x.name()) {
Some(test_name) => test_name.to_owned(),
None => "unknown".to_owned(),
}
}
fn attempt_to_get_test_name() -> String {
let thread = std::thread::current();
match thread.name() {
Some(test_name) => {
if test_name.eq("tokio-runtime-worker") {
get_test_name_from_tracing()
} else {
test_name.to_owned()
}
}
None => get_test_name_from_tracing(),
}
}
let mut headers = clienter::HttpHeaders::default();
headers.insert(
TEST_NAME_HTTP_HEADER_KEY.to_string(),
attempt_to_get_test_name(),
);
headers
}
pub fn try_fetch_file(filename: String) -> Option<(Vec<u8>, String)> {
let headers = headers_for_proof_server_request();
let mut servers = load_test_proof_servers();
servers.shuffle(&mut rand::rng());
for server in servers {
let body = try_fetch_from_server(filename.clone(), server.clone(), headers.clone());
if let Some(body) = body {
return Some((body, server));
}
}
println!("No known servers serve file `{}`", filename);
None
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
#[test]
fn test_load_servers() {
let servers = load_test_proof_servers();
for server in servers {
println!("read server: {}", server);
}
}
}