From 413e78d7be54b2f8430e021a8064ada9969368af Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Wed, 10 Jul 2024 13:59:18 +0900 Subject: [PATCH 1/7] refactor: rework tracing config + use tokio --- justfile | 2 +- scheduler/Cargo.lock | 47 +++++++++--------------- scheduler/Cargo.toml | 10 ++--- scheduler/crates/infra/Cargo.toml | 2 +- scheduler/src/main.rs | 7 ++-- scheduler/src/telemetry.rs | 61 +++++++++++++++++++------------ 6 files changed, 66 insertions(+), 63 deletions(-) diff --git a/justfile b/justfile index 35821fe7..3d813594 100644 --- a/justfile +++ b/justfile @@ -12,7 +12,7 @@ setup: _setup_db _setup_client_node # Setup database + execute migrations _setup_db: - docker-compose -f scheduler/integrations/docker-compose.yml up -d + docker compose -f scheduler/integrations/docker-compose.yml up -d cd scheduler/crates/infra && sqlx migrate run # Setup Javascript client - run `npm install` diff --git a/scheduler/Cargo.lock b/scheduler/Cargo.lock index 1dc43f34..38390df8 100644 --- a/scheduler/Cargo.lock +++ b/scheduler/Cargo.lock @@ -881,16 +881,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "gethostname" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e692e296bfac1d2533ef168d0b60ff5897b8b70a4009276834014dd8924cc028" -dependencies = [ - "libc", - "winapi", -] - [[package]] name = "getrandom" version = "0.2.15" @@ -955,6 +945,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + [[package]] name = "hex" version = "0.4.3" @@ -1352,9 +1348,8 @@ dependencies = [ "nettu_scheduler_infra", "nettu_scheduler_sdk", "openssl-probe", + "tokio", "tracing", - "tracing-bunyan-formatter", - "tracing-log", "tracing-subscriber", ] @@ -1522,6 +1517,16 @@ dependencies = [ "libm", ] +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "object" version = "0.32.2" @@ -2567,6 +2572,7 @@ dependencies = [ "bytes", "libc", "mio", + "num_cpus", "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", @@ -2662,23 +2668,6 @@ dependencies = [ "syn 2.0.68", ] -[[package]] -name = "tracing-bunyan-formatter" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63053c8ba268268d59c06b919d6c94fd968b3bd9995c5f59a03dea42fc351e70" -dependencies = [ - "chrono", - "gethostname", - "log", - "serde", - "serde_json", - "tracing", - "tracing-core", - "tracing-log", - "tracing-subscriber", -] - [[package]] name = "tracing-core" version = "0.1.32" diff --git a/scheduler/Cargo.toml b/scheduler/Cargo.toml index 1739ca64..210677a0 100644 --- a/scheduler/Cargo.toml +++ b/scheduler/Cargo.toml @@ -22,16 +22,16 @@ nettu_scheduler_api = { path = "./crates/api" } nettu_scheduler_domain = { path = "./crates/domain" } nettu_scheduler_infra = { path = "./crates/infra" } actix-web = "4.8" +tokio = { version = "1", features = ["full"] } tracing = "0.1.19" tracing-subscriber = { version = "0.2.12", features = [ - "registry", "env-filter", + "fmt", + "json", ] } -tracing-bunyan-formatter = "0.2.4" -tracing-log = "0.1.1" openssl-probe = "0.1.2" +chrono = "0.4.19" +chrono-tz = "0.5.3" [dev-dependencies] nettu_scheduler_sdk = { path = "./clients/rust" } -chrono = "0.4.19" -chrono-tz = "0.5.3" diff --git a/scheduler/crates/infra/Cargo.toml b/scheduler/crates/infra/Cargo.toml index 0d0ae440..09e454a2 100644 --- a/scheduler/crates/infra/Cargo.toml +++ b/scheduler/crates/infra/Cargo.toml @@ -15,7 +15,7 @@ async-trait = "0.1.42" chrono = { version = "0.4.19", features = ["serde"] } chrono-tz = { version = "0.5.3", features = ["serde"] } anyhow = "1.0.0" -tokio = { version = "1.10.0", features = ["macros"] } +tokio = { version = "1", features = ["full"] } tracing = "0.1.25" reqwest = { version = "0.11.4", features = ["json"] } uuid = { version = "1.1.2", features = ["serde"] } diff --git a/scheduler/src/main.rs b/scheduler/src/main.rs index eff3f9fb..b85cdfaf 100644 --- a/scheduler/src/main.rs +++ b/scheduler/src/main.rs @@ -2,14 +2,13 @@ mod telemetry; use nettu_scheduler_api::Application; use nettu_scheduler_infra::setup_context; -use telemetry::{get_subscriber, init_subscriber}; +use telemetry::init_subscriber; -#[actix_web::main] +#[tokio::main] async fn main() -> std::io::Result<()> { openssl_probe::init_ssl_cert_env_vars(); - let subscriber = get_subscriber("nettu_scheduler_server".into(), "info".into()); - init_subscriber(subscriber); + init_subscriber(); let context = setup_context().await; diff --git a/scheduler/src/telemetry.rs b/scheduler/src/telemetry.rs index 516a26be..54616b0f 100644 --- a/scheduler/src/telemetry.rs +++ b/scheduler/src/telemetry.rs @@ -1,31 +1,46 @@ -// Copied from: https://github.com/LukeMathWalker/zero-to-production/blob/main/src/telemetry.rs +use std::fmt; -use tracing::subscriber::set_global_default; -use tracing::Subscriber; -use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer}; -use tracing_log::LogTracer; -use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; +use chrono::{DateTime, Utc}; +use tracing_subscriber::{fmt::time::FormatTime, EnvFilter}; -/// Compose multiple layers into a `tracing`'s subscriber. -/// -/// # Implementation Notes -/// -/// We are using `impl Subscriber` as return type to avoid having to spell out the actual -/// type of the returned subscriber, which is indeed quite complex. -pub fn get_subscriber(name: String, env_filter: String) -> impl Subscriber + Sync + Send { - let env_filter = - EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(env_filter)); - let formatting_layer = BunyanFormattingLayer::new(name, std::io::stdout); - Registry::default() - .with(env_filter) - .with(JsonStorageLayer) - .with(formatting_layer) +/// Custom formatting for chrono timer +struct CustomChronoTimer { + format: String, +} + +impl CustomChronoTimer { + fn with_format(format: String) -> Self { + Self { format } + } +} + +impl FormatTime for CustomChronoTimer { + fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { + let now: DateTime = Utc::now(); + write!(w, "{}", now.format(&self.format)) + } } /// Register a subscriber as global default to process span data. /// /// It should only be called once! -pub fn init_subscriber(subscriber: impl Subscriber + Sync + Send) { - LogTracer::init().expect("Failed to set logger"); - set_global_default(subscriber).expect("Failed to set subscriber"); +pub fn init_subscriber() { + // Filter the spans that are shown based on the RUST_LOG env var or the default value. + let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); + + if cfg!(debug_assertions) { + tracing_subscriber::fmt() + .compact() + .with_env_filter(env_filter) + .init(); + } else { + tracing_subscriber::fmt() + .json() + .with_timer(CustomChronoTimer::with_format( + "%Y-%m-%dT%H:%M:%S%.3fZ".to_string(), + )) + .with_env_filter(env_filter) + .with_current_span(false) + .init(); + } } From 853f5553e847cb10499c978027c6f15207559bc0 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Wed, 10 Jul 2024 14:06:49 +0900 Subject: [PATCH 2/7] chore: add comments --- scheduler/src/main.rs | 2 ++ scheduler/src/telemetry.rs | 19 +++++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/scheduler/src/main.rs b/scheduler/src/main.rs index b85cdfaf..2be49bf1 100644 --- a/scheduler/src/main.rs +++ b/scheduler/src/main.rs @@ -6,8 +6,10 @@ use telemetry::init_subscriber; #[tokio::main] async fn main() -> std::io::Result<()> { + // Initialize the environment variables for SSL certificates openssl_probe::init_ssl_cert_env_vars(); + // Initialize the subscriber for logging init_subscriber(); let context = setup_context().await; diff --git a/scheduler/src/telemetry.rs b/scheduler/src/telemetry.rs index 54616b0f..e8444301 100644 --- a/scheduler/src/telemetry.rs +++ b/scheduler/src/telemetry.rs @@ -3,18 +3,20 @@ use std::fmt; use chrono::{DateTime, Utc}; use tracing_subscriber::{fmt::time::FormatTime, EnvFilter}; -/// Custom formatting for chrono timer -struct CustomChronoTimer { +/// Struct used to keep the format for having custom formatting of timestamps in the logs +struct TracingChronoTimer { format: String, } -impl CustomChronoTimer { +impl TracingChronoTimer { fn with_format(format: String) -> Self { Self { format } } } -impl FormatTime for CustomChronoTimer { +// Implement the `FormatTime` trait required by tracing_subscriber +// for the `TracingChronoTimer` struct +impl FormatTime for TracingChronoTimer { fn format_time(&self, w: &mut dyn fmt::Write) -> fmt::Result { let now: DateTime = Utc::now(); write!(w, "{}", now.format(&self.format)) @@ -25,18 +27,23 @@ impl FormatTime for CustomChronoTimer { /// /// It should only be called once! pub fn init_subscriber() { - // Filter the spans that are shown based on the RUST_LOG env var or the default value. + // Filter the spans that are shown based on the RUST_LOG env var or the default value ("info") let env_filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("info")); + // TODO: add the `env` on all logs + + // If the binary is compiled in debug mode, use the compact format for logs + // In other words, if we are in dev if cfg!(debug_assertions) { tracing_subscriber::fmt() .compact() .with_env_filter(env_filter) .init(); } else { + // Otherwise, use the JSON format for logs tracing_subscriber::fmt() .json() - .with_timer(CustomChronoTimer::with_format( + .with_timer(TracingChronoTimer::with_format( "%Y-%m-%dT%H:%M:%S%.3fZ".to_string(), )) .with_env_filter(env_filter) From 3e3a7d8d9542e17be5a9b8144444fbb71a98f072 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Tue, 16 Jul 2024 18:32:03 +0900 Subject: [PATCH 3/7] chore: revert tokio changes --- scheduler/Cargo.lock | 18 ------------------ scheduler/Cargo.toml | 1 - scheduler/crates/infra/Cargo.toml | 2 +- scheduler/src/main.rs | 2 +- 4 files changed, 2 insertions(+), 21 deletions(-) diff --git a/scheduler/Cargo.lock b/scheduler/Cargo.lock index 38390df8..0dbe69b1 100644 --- a/scheduler/Cargo.lock +++ b/scheduler/Cargo.lock @@ -945,12 +945,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - [[package]] name = "hex" version = "0.4.3" @@ -1348,7 +1342,6 @@ dependencies = [ "nettu_scheduler_infra", "nettu_scheduler_sdk", "openssl-probe", - "tokio", "tracing", "tracing-subscriber", ] @@ -1517,16 +1510,6 @@ dependencies = [ "libm", ] -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "object" version = "0.32.2" @@ -2572,7 +2555,6 @@ dependencies = [ "bytes", "libc", "mio", - "num_cpus", "parking_lot 0.12.3", "pin-project-lite", "signal-hook-registry", diff --git a/scheduler/Cargo.toml b/scheduler/Cargo.toml index 210677a0..298f8cfc 100644 --- a/scheduler/Cargo.toml +++ b/scheduler/Cargo.toml @@ -22,7 +22,6 @@ nettu_scheduler_api = { path = "./crates/api" } nettu_scheduler_domain = { path = "./crates/domain" } nettu_scheduler_infra = { path = "./crates/infra" } actix-web = "4.8" -tokio = { version = "1", features = ["full"] } tracing = "0.1.19" tracing-subscriber = { version = "0.2.12", features = [ "env-filter", diff --git a/scheduler/crates/infra/Cargo.toml b/scheduler/crates/infra/Cargo.toml index 09e454a2..a0aae3f0 100644 --- a/scheduler/crates/infra/Cargo.toml +++ b/scheduler/crates/infra/Cargo.toml @@ -15,7 +15,7 @@ async-trait = "0.1.42" chrono = { version = "0.4.19", features = ["serde"] } chrono-tz = { version = "0.5.3", features = ["serde"] } anyhow = "1.0.0" -tokio = { version = "1", features = ["full"] } +tokio = { version = "1", features = ["macros"] } tracing = "0.1.25" reqwest = { version = "0.11.4", features = ["json"] } uuid = { version = "1.1.2", features = ["serde"] } diff --git a/scheduler/src/main.rs b/scheduler/src/main.rs index 2be49bf1..019a9f4a 100644 --- a/scheduler/src/main.rs +++ b/scheduler/src/main.rs @@ -4,7 +4,7 @@ use nettu_scheduler_api::Application; use nettu_scheduler_infra::setup_context; use telemetry::init_subscriber; -#[tokio::main] +#[actix_web::main] async fn main() -> std::io::Result<()> { // Initialize the environment variables for SSL certificates openssl_probe::init_ssl_cert_env_vars(); From cc08ebdd6644853617140fea24114d88d009b389 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Wed, 17 Jul 2024 17:31:38 +0900 Subject: [PATCH 4/7] feat: use nextest --- .github/workflows/server-test.yml | 6 +++++- justfile | 5 +++-- scheduler/.config/nextest.toml | 8 ++++++++ scheduler/crates/api/src/event/get_upcoming_reminders.rs | 8 ++++---- 4 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 scheduler/.config/nextest.toml diff --git a/.github/workflows/server-test.yml b/.github/workflows/server-test.yml index 9de168e6..51cc7630 100644 --- a/.github/workflows/server-test.yml +++ b/.github/workflows/server-test.yml @@ -41,6 +41,10 @@ jobs: scheduler/target/ key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + # Install Nextest + - name: Install nextest + uses: taiki-e/install-action@nextest + - name: Run migrations run: | cd scheduler @@ -84,4 +88,4 @@ jobs: - name: Run server tests run: | cd scheduler - cargo test --all + cargo nextest run --workspace diff --git a/justfile b/justfile index 11605dd0..e77b044e 100644 --- a/justfile +++ b/justfile @@ -4,7 +4,8 @@ export DATABASE_URL := "postgresql://postgres:postgres@localhost:45432/nettusche install_all_prerequisite: cargo install sqlx-cli --no-default-features --features postgres || true cargo install cargo-outdated || true - cargo install cargo-udeps cargo-outdated || true + cargo install cargo-udeps || true + cargo install cargo-nextest || true # Setup @@ -25,7 +26,7 @@ dev: _setup_db # Test test: _setup_db - cd scheduler && cargo test --all + cd scheduler && cargo nextest run --workspace # Lint lint: _setup_db diff --git a/scheduler/.config/nextest.toml b/scheduler/.config/nextest.toml new file mode 100644 index 00000000..373c500c --- /dev/null +++ b/scheduler/.config/nextest.toml @@ -0,0 +1,8 @@ +# Test group for running some tests serially +[test-groups] +serial-integration = { max-threads = 1 } + +# Tests that contain `serial_` are run serially +[[profile.default.overrides]] +filter = 'test(serial_)' +test-group = 'serial-integration' diff --git a/scheduler/crates/api/src/event/get_upcoming_reminders.rs b/scheduler/crates/api/src/event/get_upcoming_reminders.rs index 08a39d32..37bfb3f5 100644 --- a/scheduler/crates/api/src/event/get_upcoming_reminders.rs +++ b/scheduler/crates/api/src/event/get_upcoming_reminders.rs @@ -188,7 +188,7 @@ mod tests { #[actix_web::main] #[serial_test::serial] #[test] - async fn get_upcoming_reminders() { + async fn serial_get_upcoming_reminders() { let mut ctx = setup_context().await; ctx.sys = Arc::new(StaticTimeSys1 {}); @@ -271,7 +271,7 @@ mod tests { #[actix_web::main] #[serial_test::serial] #[test] - async fn updating_event_also_updates_reminders() { + async fn serial_updating_event_also_updates_reminders() { let mut ctx = setup_context().await; ctx.sys = Arc::new(StaticTimeSys1 {}); @@ -334,7 +334,7 @@ mod tests { #[actix_web::main] #[serial_test::serial] #[test] - async fn deleting_event_reminder_setting_also_deletes_reminders() { + async fn serial_deleting_event_reminder_setting_also_deletes_reminders() { let mut ctx = setup_context().await; ctx.sys = Arc::new(StaticTimeSys1 {}); @@ -389,7 +389,7 @@ mod tests { #[actix_web::main] #[serial_test::serial] #[test] - async fn deleting_event_also_deletes_reminders() { + async fn serial_deleting_event_also_deletes_reminders() { let mut ctx = setup_context().await; ctx.sys = Arc::new(StaticTimeSys1 {}); From b2e82e9790033f5a287a02308a68321628a7ff30 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Wed, 17 Jul 2024 18:39:39 +0900 Subject: [PATCH 5/7] chore: run the tests on a temporary container --- justfile | 6 +++--- scripts/run_tests.sh | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 scripts/run_tests.sh diff --git a/justfile b/justfile index e77b044e..802e0fc8 100644 --- a/justfile +++ b/justfile @@ -24,9 +24,9 @@ _setup_client_node: dev: _setup_db cd scheduler && cargo run -# Test -test: _setup_db - cd scheduler && cargo nextest run --workspace +# Run the tests on a temporary DB container +test: + bash ./scripts/run_tests.sh # Lint lint: _setup_db diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh new file mode 100644 index 00000000..110187d2 --- /dev/null +++ b/scripts/run_tests.sh @@ -0,0 +1,31 @@ +#! /bin/bash + +# Search for a free port to bind the temporary PG container +BASE_PORT=1234 +INCREMENT=1 + +PORT=$BASE_PORT +IS_FREE=$(netstat -taln | grep $PORT) + +while [[ -n "$IS_FREE" ]]; do + PORT=$((PORT + INCREMENT)) + IS_FREE=$(netstat -taln | grep $PORT) +done + +# Generate a random name for the temporary PG container +RANDOM_NAME="pg_test_$(date +%s)" + +# Launch a PG container +docker run -d --name $RANDOM_NAME -p $PORT:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=scheduler postgres:13 + +# Set the DATABASE_URL environment variable +export DATABASE_URL="postgres://postgres:postgres@localhost:${PORT}/scheduler" + +# Run the migrations +cd scheduler/crates/infra && sqlx migrate run && cd ../../.. + +# Run the tests +cd scheduler && cargo nextest run --workspace && cd .. + +# Stop and remove the temporary PG container +docker rm -f $RANDOM_NAME From 2d3af0037bcf8bf6445924091dc27ed3303a0480 Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Thu, 18 Jul 2024 11:46:11 +0900 Subject: [PATCH 6/7] chore: add comment --- scripts/run_tests.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index 110187d2..af82cc4c 100644 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -1,5 +1,8 @@ #! /bin/bash +# Script to run all the (Rust) tests of the scheduler project +# It launches a temporary PostgreSQL container, runs the migrations, runs the tests and then stops and removes the container + # Search for a free port to bind the temporary PG container BASE_PORT=1234 INCREMENT=1 From 6989ad3265705260d3913de118428c54d7e9e07c Mon Sep 17 00:00:00 2001 From: Guillaume Deconinck Date: Thu, 18 Jul 2024 12:36:18 +0900 Subject: [PATCH 7/7] refactor: use ryuk to avoid leaving running containers behind --- scripts/run_tests.sh | 53 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index af82cc4c..03201af4 100644 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -3,6 +3,31 @@ # Script to run all the (Rust) tests of the scheduler project # It launches a temporary PostgreSQL container, runs the migrations, runs the tests and then stops and removes the container +# Function to clean up the containers +CLEANUP_CALLED=false +cleanup() { + if [ "$CLEANUP_CALLED" = true ]; then + return + fi + echo "Cleaning up..." + CLEANUP_CALLED=true + + if [ -n "$NC_PID" ] && kill -0 $NC_PID 2>/dev/null; then + kill $NC_PID >/dev/null 2>&1 + fi + + if [ "$(docker ps -q -f name=$RANDOM_NAME)" ]; then + docker stop $RANDOM_NAME >/dev/null 2>&1 + fi + + if [ "$(docker ps -q -f name=ryuk)" ]; then + docker stop ryuk >/dev/null 2>&1 + fi +} + +# Set up a trap to call the cleanup function on EXIT, SIGINT, and SIGTERM +trap cleanup EXIT SIGINT SIGTERM + # Search for a free port to bind the temporary PG container BASE_PORT=1234 INCREMENT=1 @@ -18,17 +43,35 @@ done # Generate a random name for the temporary PG container RANDOM_NAME="pg_test_$(date +%s)" +LABEL="nittei_testing=true" + +cd scheduler && cargo build --workspace + +# Launch the resource reaper (like testcontainers) +docker run -d --name ryuk --rm -v /var/run/docker.sock:/var/run/docker.sock -e RYUK_VERBOSE=true -e RYUK_PORT=8080 -p 8080:8080 testcontainers/ryuk:0.8.1 >/dev/null 2>&1 + +# Keep the connection open and send the label to Ryuk +TIMEOUT=60 +( + echo "label=${LABEL}" + # Keep the connection open to Ryuk and read the ACK response + while [ $((TIMEOUT--)) -gt 0 ]; do + sleep 1 + done +) | nc localhost 8080 & +>/dev/null 2>&1 +NC_PID=$! + # Launch a PG container -docker run -d --name $RANDOM_NAME -p $PORT:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=scheduler postgres:13 +docker run --rm -d -l ${LABEL} --name $RANDOM_NAME -p $PORT:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=scheduler postgres:13 >/dev/null 2>&1 # Set the DATABASE_URL environment variable export DATABASE_URL="postgres://postgres:postgres@localhost:${PORT}/scheduler" # Run the migrations -cd scheduler/crates/infra && sqlx migrate run && cd ../../.. +cd crates/infra && sqlx migrate run && cd ../.. # Run the tests -cd scheduler && cargo nextest run --workspace && cd .. +cargo nextest run --workspace && cd .. -# Stop and remove the temporary PG container -docker rm -f $RANDOM_NAME +# The cleanup function will be called automatically