tests work properly
This commit is contained in:
9
rust/prepare-test-instance.sh
Executable file
9
rust/prepare-test-instance.sh
Executable 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
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
sleep 100
|
cd $( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||||
|
|
||||||
set -o nounset
|
set -o nounset
|
||||||
|
|
||||||
port="${1}"
|
port="${1}"
|
||||||
|
|
||||||
db="$(mktemp)"
|
db="$(mktemp)"
|
||||||
|
|
||||||
export SQLX_OFFLINE=true
|
|
||||||
export DATABASE_URL="sqlite://${db}"
|
export DATABASE_URL="sqlite://${db}"
|
||||||
|
|
||||||
cargo run -- --port "${port}"
|
exec ./target/debug/packager --port "${port}"
|
||||||
|
|||||||
@@ -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;
|
pub struct TripTable;
|
||||||
|
|
||||||
impl TripTable {
|
impl TripTable {
|
||||||
@@ -66,10 +77,15 @@ impl TripTable {
|
|||||||
@for trip in trips {
|
@for trip in trips {
|
||||||
tr ."h-10" ."even:bg-gray-100" ."hover:bg-purple-100" ."h-full" {
|
tr ."h-10" ."even:bg-gray-100" ."hover:bg-purple-100" ."h-full" {
|
||||||
(TripTableRow::build(trip.id, &trip.name))
|
(TripTableRow::build(trip.id, &trip.name))
|
||||||
(TripTableRow::build(trip.id, trip.date_start))
|
(TripTableRow::build(trip.id, trip.date_start.to_string()))
|
||||||
(TripTableRow::build(trip.id, trip.date_end))
|
(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.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;
|
pub struct TripTableRow;
|
||||||
|
|
||||||
impl 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!(
|
html!(
|
||||||
td ."border" ."p-0" ."m-0" {
|
td ."border" ."p-0" ."m-0" {
|
||||||
a ."inline-block" ."p-2" ."m-0" ."w-full"
|
a ."inline-block" ."p-2" ."m-0" ."w-full"
|
||||||
@@ -441,7 +457,12 @@ impl TripInfo {
|
|||||||
))
|
))
|
||||||
tr .h-full {
|
tr .h-full {
|
||||||
td ."border" ."p-2" { "State" }
|
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 prev_state = trip.state.prev();
|
||||||
@let next_state = trip.state.next();
|
@let next_state = trip.state.next();
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,10 @@ use std::thread;
|
|||||||
use thirtyfour::common::capabilities::firefox::FirefoxPreferences;
|
use thirtyfour::common::capabilities::firefox::FirefoxPreferences;
|
||||||
use thirtyfour::{FirefoxCapabilities, WebDriver};
|
use thirtyfour::{FirefoxCapabilities, WebDriver};
|
||||||
|
|
||||||
|
use std::time;
|
||||||
|
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
use std::process::{Command, Stdio};
|
||||||
|
|
||||||
const PORT: u16 = 3001;
|
const PORT: u16 = 3001;
|
||||||
const BASEURL: &'static str = "http://localhost";
|
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 {
|
fn random_name() -> String {
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let length = { 1..=20 }.choose(&mut rng).unwrap();
|
let length = { 1..=20 }.choose(&mut rng).unwrap();
|
||||||
@@ -49,27 +60,105 @@ where
|
|||||||
R: Future<Output = Result<(), TestError>>,
|
R: Future<Output = Result<(), TestError>>,
|
||||||
{
|
{
|
||||||
let event_in_parent = Arc::new((Mutex::new(false), Condvar::new()));
|
let event_in_parent = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
|
|
||||||
let event_in_subprocess = Arc::clone(&event_in_parent);
|
let event_in_subprocess = Arc::clone(&event_in_parent);
|
||||||
let app = thread::spawn(move || {
|
|
||||||
use std::process::Command;
|
|
||||||
|
|
||||||
// panic!();
|
let prepared_event_in_parent = Arc::new((Mutex::new(false), Condvar::new()));
|
||||||
let script = concat!(env!("CARGO_MANIFEST_DIR"), "/run-test-instance.sh");
|
let prepared_event_in_subprocess = Arc::clone(&prepared_event_in_parent);
|
||||||
|
|
||||||
println!("starting script {script}");
|
let app = thread::spawn(move || -> Result<(), TestError> {
|
||||||
let mut handle = Command::new(script).arg(PORT.to_string()).spawn().unwrap();
|
{
|
||||||
|
let script = concat!(env!("CARGO_MANIFEST_DIR"), "/../prepare-test-instance.sh");
|
||||||
|
|
||||||
let (lock, cvar) = &*event_in_subprocess;
|
println!("[sub] starting prepare script {script}");
|
||||||
let mut done = lock.lock().unwrap();
|
let handle_prepare = Command::new(script)
|
||||||
while !*done {
|
.stdin(Stdio::null())
|
||||||
done = cvar.wait(done).unwrap();
|
// .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
|
// at worst, the child already exited, so we don't care about the
|
||||||
// return code
|
// 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 prefs = FirefoxPreferences::new();
|
||||||
let mut caps = FirefoxCapabilities::new();
|
let mut caps = FirefoxCapabilities::new();
|
||||||
caps.set_preferences(prefs)?;
|
caps.set_preferences(prefs)?;
|
||||||
@@ -79,20 +168,35 @@ where
|
|||||||
// cloning works for closing, so it's good enough
|
// cloning works for closing, so it's good enough
|
||||||
let driver_handle = driver.clone();
|
let driver_handle = driver.clone();
|
||||||
|
|
||||||
|
// call the actual function
|
||||||
|
println!("calling test function");
|
||||||
let result = inner(driver).await;
|
let result = inner(driver).await;
|
||||||
|
// let result: Result<(), TestError> = Ok(());
|
||||||
|
println!("test function done");
|
||||||
|
|
||||||
|
println!("deinitializing selenium driver");
|
||||||
driver_handle.quit().await?;
|
driver_handle.quit().await?;
|
||||||
|
|
||||||
// if the child panicked and cannot receive the event, we don't care and just
|
// this has to be done in a separate thread, otherwise the condvar handling
|
||||||
// exit
|
// does not work. it's not sure why.
|
||||||
let (lock, cvar) = &*event_in_parent;
|
thread::spawn(move || {
|
||||||
let mut done = lock.lock().unwrap();
|
// if the child panicked and cannot receive the event, we don't care and just
|
||||||
*done = true;
|
// continue to the exit
|
||||||
cvar.notify_one();
|
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(),
|
message: "app panicked".to_string(),
|
||||||
});
|
})??;
|
||||||
|
println!("all done");
|
||||||
Ok(result?)
|
Ok(result?)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +249,31 @@ async fn check_table(
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test() -> Result<(), TestError> {
|
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 {
|
run_test(|driver: WebDriver| async move {
|
||||||
for js_enabled in [true] {
|
for js_enabled in [true] {
|
||||||
driver.goto(url("/")).await?;
|
driver.goto(url("/")).await?;
|
||||||
|
|||||||
Reference in New Issue
Block a user