From 2df9602d56a22da312533afacd4e0f81418a91a6 Mon Sep 17 00:00:00 2001 From: Illia Polosukhin Date: Fri, 6 Mar 2026 05:59:01 +0000 Subject: [PATCH] fix(ci): fix three coverage workflow failures (#597) * fix(ci): fix three coverage workflow failures 1. Migration ordering: glob `V*.sql` sorted V10 before V1 (ASCII '0' < '_'). Use `sort -V` for correct numeric ordering. 2. Missing WASM channels: telegram_auth_integration tests need the Telegram WASM binary. Add wasm32-wasip2 target, cargo-component, and build-wasm-extensions.sh to both coverage and e2e-coverage jobs (matching test.yml). 3. E2E shell quoting: `cargo llvm-cov show-env` outputs shell-quoted values (KEY='value') but GITHUB_ENV expects unquoted KEY=value. Strip single quotes with sed before appending. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 * fix(ci): address PR review feedback on coverage workflow - Migration loop: use readarray + printf | sort -V instead of $(ls) to avoid word-splitting on filenames - cargo-component install: check if already installed first, don't mask failures with || true - show-env quote stripping: use targeted regex to strip only wrapping quotes (KEY='value' -> KEY=value) instead of removing all quotes [skip-regression-check] Co-Authored-By: Claude Opus 4.6 * fix: skip telegram_auth_integration tests when WASM module not built Replace panicking assert! with a require_telegram_wasm!() macro that gracefully skips tests when the Telegram WASM binary hasn't been compiled. This ensures the test suite passes across all configurations (with and without wasm32-wasip2 target), while still running the tests in CI where the WASM channels are built. [skip-regression-check] Co-Authored-By: Claude Opus 4.6 * fix: panic in CI when telegram WASM module missing, skip locally - require_telegram_wasm!() now checks the CI env var: panics in CI (so a broken WASM build step fails loudly) but skips locally - fs::read error now includes the file path for better diagnostics [skip-regression-check] Co-Authored-By: Claude Opus 4.6 --------- Co-authored-by: Claude Opus 4.6 --- .github/workflows/coverage.yml | 31 +++++++++++++++++++++---- tests/telegram_auth_integration.rs | 37 +++++++++++++++++++++++------- 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 7bacd26e..8489d69d 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -44,6 +44,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: components: llvm-tools-preview + targets: wasm32-wasip2 - uses: Swatinem/rust-cache@v2 with: @@ -52,11 +53,21 @@ jobs: - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov + - name: Install cargo-component + run: | + if ! command -v cargo-component >/dev/null 2>&1; then + cargo install cargo-component --locked + fi + + - name: Build WASM channels (for integration tests) + run: ./scripts/build-wasm-extensions.sh --channels + - name: Run database migrations if: matrix.has_postgres run: | set -euo pipefail - for f in migrations/V*.sql; do + readarray -t migration_files < <(printf '%s\n' migrations/V*.sql | sort -V) + for f in "${migration_files[@]}"; do echo "Applying $f..." psql -v ON_ERROR_STOP=1 -f "$f" done @@ -92,6 +103,7 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: components: llvm-tools-preview + targets: wasm32-wasip2 - uses: Swatinem/rust-cache@v2 with: @@ -100,12 +112,21 @@ jobs: - name: Install cargo-llvm-cov uses: taiki-e/install-action@cargo-llvm-cov + - name: Install cargo-component + run: | + if ! command -v cargo-component >/dev/null 2>&1; then + cargo install cargo-component --locked + fi + + - name: Build WASM channels + run: ./scripts/build-wasm-extensions.sh --channels + - name: Set up coverage instrumentation run: | - # Append ALL env vars from show-env (including CARGO_ENCODED_RUSTFLAGS, - # CARGO_INCREMENTAL, LLVM_PROFILE_FILE, etc.) so the build step - # compiles an instrumented binary regardless of cargo-llvm-cov version. - cargo llvm-cov show-env >> "$GITHUB_ENV" + # show-env outputs shell-quoted values (KEY='value') but GITHUB_ENV + # expects unquoted KEY=value. Strip only the wrapping single quotes + # from KEY='value' lines without altering any internal characters. + cargo llvm-cov show-env | sed -E "s/^([A-Za-z_][A-Za-z0-9_]*)='(.*)'$/\1=\2/" >> "$GITHUB_ENV" - name: Clean coverage workspace run: cargo llvm-cov clean --workspace diff --git a/tests/telegram_auth_integration.rs b/tests/telegram_auth_integration.rs index 34e0b396..01d246a6 100644 --- a/tests/telegram_auth_integration.rs +++ b/tests/telegram_auth_integration.rs @@ -18,6 +18,26 @@ use ironclaw::channels::wasm::{ }; use ironclaw::pairing::PairingStore; +/// Skip the test if the Telegram WASM module hasn't been built. +/// In CI (detected via the `CI` env var), panic instead of skipping so a +/// broken WASM build step doesn't silently produce green tests. +macro_rules! require_telegram_wasm { + () => { + if !telegram_wasm_path().exists() { + let msg = format!( + "Telegram WASM module not found at {:?}. \ + Build with: cd channels-src/telegram && cargo build --target wasm32-wasip2 --release", + telegram_wasm_path() + ); + if std::env::var("CI").is_ok() { + panic!("{}", msg); + } + eprintln!("Skipping test: {}", msg); + return; + } + }; +} + /// Path to the built Telegram WASM module fn telegram_wasm_path() -> std::path::PathBuf { std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")) @@ -34,14 +54,9 @@ fn create_test_runtime() -> Arc { async fn load_telegram_module( runtime: &Arc, ) -> Result, Box> { - let wasm_path = telegram_wasm_path(); - assert!( - wasm_path.exists(), - "Telegram WASM module not found at {:?}. Build it with: cd channels-src/telegram && cargo build --target wasm32-wasip2 --release", - wasm_path - ); - - let wasm_bytes = std::fs::read(&wasm_path)?; + let path = telegram_wasm_path(); + let wasm_bytes = std::fs::read(&path) + .map_err(|e| format!("Failed to read WASM module at {}: {}", path.display(), e))?; let module = runtime .prepare( @@ -107,6 +122,7 @@ fn build_telegram_update( #[tokio::test] async fn test_group_message_unauthorized_user_blocked_with_allowlist() { + require_telegram_wasm!(); let runtime = create_test_runtime(); // Config: owner_id=null, dm_policy="allowlist", allow_from=["authorized_user"] @@ -159,6 +175,7 @@ async fn test_group_message_unauthorized_user_blocked_with_allowlist() { #[tokio::test] async fn test_group_message_authorized_user_allowed() { + require_telegram_wasm!(); let runtime = create_test_runtime(); let config = serde_json::json!({ @@ -206,6 +223,7 @@ async fn test_group_message_authorized_user_allowed() { #[tokio::test] async fn test_group_message_with_owner_id_set() { + require_telegram_wasm!(); let runtime = create_test_runtime(); // Config: owner_id=123 (only this user can interact) @@ -251,6 +269,7 @@ async fn test_group_message_with_owner_id_set() { #[tokio::test] async fn test_private_message_without_owner_id_with_pairing_policy() { + require_telegram_wasm!(); let runtime = create_test_runtime(); let config = serde_json::json!({ @@ -291,6 +310,7 @@ async fn test_private_message_without_owner_id_with_pairing_policy() { #[tokio::test] async fn test_open_dm_policy_allows_all_users() { + require_telegram_wasm!(); let runtime = create_test_runtime(); let config = serde_json::json!({ @@ -335,6 +355,7 @@ async fn test_open_dm_policy_allows_all_users() { #[tokio::test] async fn test_bot_mention_detection_case_insensitive() { + require_telegram_wasm!(); let runtime = create_test_runtime(); let config = serde_json::json!({