tests work properly

This commit is contained in:
2023-08-29 21:34:00 +02:00
parent 8f04947e9f
commit d22ca255e1
4 changed files with 187 additions and 28 deletions

9
rust/prepare-test-instance.sh Executable file
View File

@@ -0,0 +1,9 @@
#!/usr/bin/env bash
cd $( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
set -o nounset
export SQLX_OFFLINE=true
exec cargo build

View File

@@ -1,13 +1,13 @@
#!/usr/bin/env bash
sleep 100
cd $( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
set -o nounset
port="${1}"
db="$(mktemp)"
export SQLX_OFFLINE=true
export DATABASE_URL="sqlite://${db}"
cargo run -- --port "${port}"
exec ./target/debug/packager --port "${port}"

View File

@@ -39,6 +39,17 @@ impl From<InputType> for &'static str {
}
}
fn trip_state_icon(state: &TripState) -> &'static str {
match state {
TripState::Init => "mdi-magic-staff",
TripState::Planning => "mdi-text-box-outline",
TripState::Planned => "mdi-clock-outline",
TripState::Active => "mdi-play",
TripState::Review => "mdi-magnify",
TripState::Done => "mdi-check",
}
}
pub struct TripTable;
impl TripTable {
@@ -66,10 +77,15 @@ impl TripTable {
@for trip in trips {
tr ."h-10" ."even:bg-gray-100" ."hover:bg-purple-100" ."h-full" {
(TripTableRow::build(trip.id, &trip.name))
(TripTableRow::build(trip.id, trip.date_start))
(TripTableRow::build(trip.id, trip.date_end))
(TripTableRow::build(trip.id, trip.date_start.to_string()))
(TripTableRow::build(trip.id, trip.date_end.to_string()))
(TripTableRow::build(trip.id, (trip.date_end - trip.date_start).whole_days()))
(TripTableRow::build(trip.id, trip.state))
(TripTableRow::build(trip.id, html!(
span .flex .flex-row .items-center {
span ."mdi" .(trip_state_icon(&trip.state)) ."text-xl" ."mr-2" {}
span { (trip.state) }
}
)))
}
}
}
@@ -81,7 +97,7 @@ impl TripTable {
pub struct TripTableRow;
impl TripTableRow {
pub fn build(trip_id: Uuid, value: impl std::fmt::Display) -> Markup {
pub fn build(trip_id: Uuid, value: impl maud::Render) -> Markup {
html!(
td ."border" ."p-0" ."m-0" {
a ."inline-block" ."p-2" ."m-0" ."w-full"
@@ -441,7 +457,12 @@ impl TripInfo {
))
tr .h-full {
td ."border" ."p-2" { "State" }
td ."border" ."p-2" { (trip.state) }
td ."border" {
span .flex .flex-row .items-center .justify-start ."gap-2" {
span ."mdi" .(trip_state_icon(&trip.state)) ."text-2xl" ."pl-2" {}
span ."pr-2" ."py-2" { (trip.state) }
}
}
@let prev_state = trip.state.prev();
@let next_state = trip.state.next();

View File

@@ -6,7 +6,10 @@ use std::thread;
use thirtyfour::common::capabilities::firefox::FirefoxPreferences;
use thirtyfour::{FirefoxCapabilities, WebDriver};
use std::time;
use std::future::Future;
use std::process::{Command, Stdio};
const PORT: u16 = 3001;
const BASEURL: &'static str = "http://localhost";
@@ -31,6 +34,14 @@ impl From<WebDriverError> for TestError {
}
}
impl From<std::io::Error> for TestError {
fn from(error: std::io::Error) -> Self {
Self::AppError {
message: error.to_string(),
}
}
}
fn random_name() -> String {
let mut rng = rand::thread_rng();
let length = { 1..=20 }.choose(&mut rng).unwrap();
@@ -49,27 +60,105 @@ where
R: Future<Output = Result<(), TestError>>,
{
let event_in_parent = Arc::new((Mutex::new(false), Condvar::new()));
let event_in_subprocess = Arc::clone(&event_in_parent);
let app = thread::spawn(move || {
use std::process::Command;
// panic!();
let script = concat!(env!("CARGO_MANIFEST_DIR"), "/run-test-instance.sh");
let prepared_event_in_parent = Arc::new((Mutex::new(false), Condvar::new()));
let prepared_event_in_subprocess = Arc::clone(&prepared_event_in_parent);
println!("starting script {script}");
let mut handle = Command::new(script).arg(PORT.to_string()).spawn().unwrap();
let app = thread::spawn(move || -> Result<(), TestError> {
{
let script = concat!(env!("CARGO_MANIFEST_DIR"), "/../prepare-test-instance.sh");
let (lock, cvar) = &*event_in_subprocess;
let mut done = lock.lock().unwrap();
while !*done {
done = cvar.wait(done).unwrap();
println!("[sub] starting prepare script {script}");
let handle_prepare = Command::new(script)
.stdin(Stdio::null())
// .stdout(Stdio::null())
// .stderr(Stdio::null())
.output()?;
assert!(handle_prepare.status.success());
println!("[sub] preparation ok");
}
let mut handle_gecko = {
let script = concat!(env!("CARGO_MANIFEST_DIR"), "/../run-test-instance.sh");
println!("[sub] starting script {script}");
let handle = Command::new("geckodriver")
.stdin(Stdio::null())
// .stdout(Stdio::null())
// .stderr(Stdio::null())
.spawn()?;
println!("[sub] geckodriver started");
handle
};
{
println!("[sub] sending prepared event");
let (lock, cvar) = &*prepared_event_in_subprocess;
let mut prepared = lock.lock().unwrap();
*prepared = true;
cvar.notify_all();
println!("[sub] sent prepared event");
}
let mut handle_app = {
let script = concat!(env!("CARGO_MANIFEST_DIR"), "/../run-test-instance.sh");
println!("[sub] starting script {script}");
let handle = Command::new(script)
.arg(PORT.to_string())
.stdin(Stdio::null())
// .stdout(Stdio::null())
// .stderr(Stdio::null())
.spawn()?;
println!("[sub] app started");
handle
};
{
let (lock, cvar) = &*event_in_subprocess;
let mut done = lock.lock().unwrap();
while !*done {
println!("[sub] waiting for done event");
done = cvar.wait(done).unwrap();
}
println!("[sub] done received");
}
// at worst, the child already exited, so we don't care about the
// return code
let _ = handle.kill();
println!("[sub] killing app subprocess");
let _ = handle_app.kill()?;
handle_app.wait()?;
println!("[sub] killed app subprocess");
println!("[sub] killing gecko subprocess");
let _ = handle_gecko.kill()?;
handle_gecko.wait()?;
println!("[sub] killed gecko subprocess");
println!("[sub] done");
Ok(())
});
thread::spawn(move || {
let (lock, cvar) = &*prepared_event_in_parent;
let mut prepared = lock.lock().unwrap();
while !*prepared {
println!("waiting for prepared event");
prepared = cvar.wait(prepared).unwrap();
}
println!("prepared received");
})
.join()
.unwrap();
println!("preparations done, starting tests in 1s");
thread::sleep(time::Duration::from_secs(1));
let prefs = FirefoxPreferences::new();
let mut caps = FirefoxCapabilities::new();
caps.set_preferences(prefs)?;
@@ -79,20 +168,35 @@ where
// cloning works for closing, so it's good enough
let driver_handle = driver.clone();
// call the actual function
println!("calling test function");
let result = inner(driver).await;
// let result: Result<(), TestError> = Ok(());
println!("test function done");
println!("deinitializing selenium driver");
driver_handle.quit().await?;
// if the child panicked and cannot receive the event, we don't care and just
// exit
let (lock, cvar) = &*event_in_parent;
let mut done = lock.lock().unwrap();
*done = true;
cvar.notify_one();
// this has to be done in a separate thread, otherwise the condvar handling
// does not work. it's not sure why.
thread::spawn(move || {
// if the child panicked and cannot receive the event, we don't care and just
// continue to the exit
println!("sending done event");
let (lock, cvar) = &*event_in_parent;
let mut done = lock.lock().unwrap();
*done = true;
cvar.notify_all();
println!("sent done event");
})
.join()
.unwrap();
let _ = app.join().map_err(|_| TestError::AppError {
println!("waiting for subprocess");
app.join().map_err(|_| TestError::AppError {
message: "app panicked".to_string(),
});
})??;
println!("all done");
Ok(result?)
}
@@ -145,6 +249,31 @@ async fn check_table(
#[tokio::test]
async fn test() -> Result<(), TestError> {
let mut handle = {
let script = concat!(env!("CARGO_MANIFEST_DIR"), "/../run-test-instance.sh");
println!("[sub] starting script {script}");
let handle = Command::new(script)
.arg(PORT.to_string())
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()?;
println!("[sub] started");
handle
};
// at worst, the child already exited, so we don't care about the
// return code
println!("[sub] killing subprocess");
let _ = handle.kill().expect("failed to kill child");
handle.wait().unwrap();
println!("[sub] killed subprocess");
println!("[sub] done");
// return Ok(());
run_test(|driver: WebDriver| async move {
for js_enabled in [true] {
driver.goto(url("/")).await?;