use anyhow::Result;
use instant::Duration;
use std::{
fs::{create_dir_all, remove_dir_all, remove_file},
path::Path,
process::Command,
};
use tokio::{process, task, time::sleep};
use crate::_util::wait_for_localhost_port;
pub fn cleanup() {
if Path::new("tests/js/node_modules").exists() {
remove_dir_all("tests/js/node_modules").expect("Unable to run rm to delete node_modules");
}
if Path::new("tests/js/work").exists() {
remove_dir_all("tests/js/work").expect("Unable to run rm to delete work");
}
if Path::new("tests/js/package-lock.json").exists() {
remove_file("tests/js/package-lock.json")
.expect("Unable to run rm to delete package-lock.json");
}
}
pub fn install() {
let status = Command::new("npm")
.current_dir("tests/js")
.args(["install"])
.status()
.expect("Unable to run npm install");
assert_eq!(
Some(0),
status.code(),
"npm install did not run successfully. Do you have npm installed and a network connection?"
);
}
pub fn prepare_test_set(test_set: &str) -> (String, String, String) {
let path_result = format!("tests/js/work/{test_set}/result.txt");
let path_writer = format!("tests/js/work/{test_set}/writer");
let path_reader = format!("tests/js/work/{test_set}/reader");
create_dir_all(&path_writer).expect("Unable to create work writer directory");
create_dir_all(&path_reader).expect("Unable to create work reader directory");
(path_result, path_writer, path_reader)
}
pub struct JavascriptServer {
handle: Option<task::JoinHandle<()>>,
}
impl JavascriptServer {
pub fn new() -> JavascriptServer {
JavascriptServer { handle: None }
}
pub async fn run(
&mut self,
is_writer: bool,
port: u32,
data_count: usize,
data_size: usize,
data_char: char,
test_set: String,
) {
self.handle = Some(task::spawn(async move {
let mut retries = 3;
let mut code: Option<i32> = None;
while code.is_none() && retries > 0 {
let status = process::Command::new("node")
.current_dir("tests/js")
.args([
"interop.js",
"server",
if is_writer { "writer" } else { "reader" },
&port.to_string(),
&data_count.to_string(),
&data_size.to_string(),
&data_char.to_string(),
&test_set,
])
.kill_on_drop(true)
.status()
.await
.expect("Unable to execute node");
code = status.code();
if code.is_none() {
sleep(Duration::from_millis(100)).await;
retries -= 1;
}
}
assert_eq!(
Some(0),
code,
"node server did not exit successfully, is_writer={is_writer}, port={port}, data_count={data_count}, data_size={data_size}, data_char={data_char}, test_set={test_set}",
);
}));
wait_for_localhost_port(port).await;
}
}
pub async fn js_start_server(
is_writer: bool,
port: u32,
data_count: usize,
data_size: usize,
data_char: char,
test_set: String,
) -> Result<JavascriptServer> {
let mut server = JavascriptServer::new();
server
.run(is_writer, port, data_count, data_size, data_char, test_set)
.await;
Ok(server)
}
pub async fn js_run_client(
is_writer: bool,
port: u32,
data_count: usize,
data_size: usize,
data_char: char,
test_set: &str,
) {
let status = process::Command::new("node")
.current_dir("tests/js")
.args([
"interop.js",
"client",
if is_writer { "writer" } else { "reader" },
&port.to_string(),
&data_count.to_string(),
&data_size.to_string(),
&data_char.to_string(),
test_set,
])
.kill_on_drop(true)
.status()
.await
.expect("Unable to execute node");
assert_eq!(
Some(0),
status.code(),
"node client did not run successfully, \
is_writer={is_writer}, \
port={port}, \
data_count={data_count}, \
data_size={data_size}, \
data_char={data_char}, \
test_set={test_set}"
);
}