fix(deploy): probe the demo pod on a path that is served #1796
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Tests | |
| on: | |
| pull_request: | |
| push: | |
| branches: [main] | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: tests-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| unit: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: "10.0" | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "24" | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Cache NuGet | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.nuget/packages | |
| key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'Directory.Packages.props') }} | |
| # No job here builds nocturne.sln — CI runs named projects only (see Test below) — so this | |
| # is the only thing gating solution membership, and it has to hold in both directions. | |
| # scripts/Shared is the deliberate omission: scripts/ consumes it through `#:project`. | |
| - name: Solution and project tree agree | |
| run: | | |
| tracked=$(git -c core.quotePath=false ls-files '*.csproj' | sort) | |
| listed=$(dotnet sln nocturne.sln list | { grep -E '\.csproj[[:space:]]*$' || true; } | sed 's|\\|/|g; s|[[:space:]]*$||' | sort) | |
| if [ -z "$tracked" ] || [ -z "$listed" ]; then | |
| echo "Nothing to compare: git found $(printf '%s' "$tracked" | grep -c .) csproj, nocturne.sln listed $(printf '%s' "$listed" | grep -c .)" | |
| exit 1 | |
| fi | |
| absent=$(comm -23 <(echo "$tracked") <(echo "$listed") | { grep -vx 'scripts/Shared/Shared.csproj' || true; }) | |
| dangling=$(comm -13 <(echo "$tracked") <(echo "$listed")) | |
| if [ -n "$absent" ]; then | |
| echo "Missing from nocturne.sln:" | |
| echo "$absent" | |
| fi | |
| if [ -n "$dangling" ]; then | |
| echo "Listed in nocturne.sln but not a tracked file:" | |
| echo "$dangling" | |
| fi | |
| [ -z "$absent$dangling" ] | |
| # Entering Nocturne.E2E.Tests starts the whole Aspire stack, so it must stay uncollected | |
| # unless RunE2E is set; a csproj edit that re-arms it would wedge every unfiltered run. | |
| - name: E2E suite stays opt-in | |
| run: | | |
| collected=$(dotnet msbuild tests/E2E/Nocturne.E2E.Tests/Nocturne.E2E.Tests.csproj \ | |
| -getProperty:IsTestProject -p:GenerateNSwagClient=false) | |
| if [ "$collected" != "false" ]; then | |
| echo "IsTestProject is '$collected', expected 'false' without -p:RunE2E=true" | |
| exit 1 | |
| fi | |
| - name: Test | |
| run: | | |
| # Build per-project to avoid Windows-only projects (Desktop, Widgets) | |
| for proj in tests/Unit/*/; do | |
| csproj=$(find "$proj" -maxdepth 1 -name "*.csproj" | head -1) | |
| [ -z "$csproj" ] && continue | |
| dotnet test "$csproj" \ | |
| --filter "Category!=Integration&Category!=E2E" \ | |
| --logger "trx;LogFileName=unit.trx" \ | |
| -p:GenerateNSwagClient=false \ | |
| || exit 1 | |
| done | |
| - uses: actions/upload-artifact@v4 | |
| if: failure() | |
| with: | |
| name: unit-trx | |
| path: "**/*.trx" | |
| # The alert-engine golden corpus (tests/Parity/AlertEngineCorpus) is the normative | |
| # spec for the Rust port of the leaf/node evaluation engine. While the C# engine is | |
| # authoritative, any behavioural change to the evaluators/tracker must regenerate the | |
| # corpus deliberately — this job fails if the committed corpus no longer matches what | |
| # the engine produces. | |
| alert-corpus-check: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: "10.0" | |
| - name: Cache NuGet | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.nuget/packages | |
| key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'Directory.Packages.props') }} | |
| - name: Verify alert engine corpus is current | |
| run: | | |
| dotnet run --project tests/Parity/Nocturne.Alerts.ParityCorpus.Generator \ | |
| -p:GenerateNSwagClient=false -- --check | |
| # Rust alert engine FFI: lints + tests the crates workspace, builds the | |
| # nocturne_alerts cdylib, then runs the three-way parity suite (C# engine vs | |
| # committed corpus vs Rust engine over the C ABI). NOCTURNE_ALERTS_REQUIRE_NATIVE | |
| # turns silent skips (native lib not found) into a hard failure so the parity | |
| # theories can never quietly stop running here. | |
| alerts-ffi-parity: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 25 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: "10.0" | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy, rustfmt | |
| - name: Cache cargo | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| crates/target | |
| # Sources, not just the lockfile: actions/cache restores crates/target with | |
| # mtimes newer than the checked-out sources, and cargo's path-package fingerprint | |
| # is mtime-based, so a lockfile-only key lets a source change reuse a stale build. | |
| key: cargo-${{ runner.os }}-${{ hashFiles('crates/Cargo.lock', 'crates/**/*.rs', 'crates/**/Cargo.toml') }} | |
| - name: Cache NuGet | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.nuget/packages | |
| key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'Directory.Packages.props') }} | |
| - name: Rust tests, clippy, fmt | |
| working-directory: crates | |
| run: | | |
| cargo test --workspace | |
| cargo clippy --workspace --all-targets -- -D warnings | |
| cargo fmt --check | |
| - name: Build nocturne_alerts cdylib | |
| working-directory: crates | |
| run: cargo build --release -p nocturne-alerts-ffi | |
| - name: Three-way parity tests (C# engine vs corpus vs Rust FFI) | |
| env: | |
| NOCTURNE_ALERTS_NATIVE_DIR: ${{ github.workspace }}/crates/target/release | |
| NOCTURNE_ALERTS_REQUIRE_NATIVE: "1" | |
| run: | | |
| dotnet test tests/Unit/Nocturne.Alerts.Native.Tests/Nocturne.Alerts.Native.Tests.csproj \ | |
| --logger "trx;LogFileName=alerts-ffi-parity.trx" \ | |
| -p:GenerateNSwagClient=false \ | |
| || exit 1 | |
| # Engine-seam tests (IAlertEvaluationEngine): corpus parity for both the managed and | |
| # rust-backed seam adapters, cross-engine timer continuity, shadow-mode divergence | |
| # logging, and Alerts:Engine flag selection. The rust-backed theories require the | |
| # cdylib built above; NOCTURNE_ALERTS_REQUIRE_NATIVE turns silent skips into failures. | |
| - name: Engine seam tests (managed + rust adapters, shadow, flag) | |
| env: | |
| NOCTURNE_ALERTS_NATIVE_DIR: ${{ github.workspace }}/crates/target/release | |
| NOCTURNE_ALERTS_REQUIRE_NATIVE: "1" | |
| Alerts__Engine: rust | |
| run: | | |
| dotnet test tests/Unit/Nocturne.API.Tests/Nocturne.API.Tests.csproj \ | |
| --filter "FullyQualifiedName~Services.Alerts.Engines" \ | |
| --logger "trx;LogFileName=alerts-engine-seam.trx" \ | |
| -p:GenerateNSwagClient=false \ | |
| || exit 1 | |
| - uses: actions/upload-artifact@v4 | |
| if: failure() | |
| with: | |
| name: alerts-ffi-parity-trx | |
| path: "**/*.trx" | |
| # Database integration tests: bare-Postgres Testcontainers (no Aspire), so they | |
| # run reliably on GitHub-hosted runners where Docker is available. Other | |
| # integration projects stay deferred until their fixtures/references are fixed. | |
| # Typechecks the Svelte library packages that have no build step and no generated API | |
| # client, and runs the pure-node vitest suites, so this needs nothing but pnpm. | |
| # @nocturne/app and @nocturne/portal are excluded because their checks depend on the | |
| # NSwag/Zod codegen and belong with the .NET build. | |
| # | |
| # Only glucose-chart and coach are listed. @nocturne/ui and @nocturne/cms still run | |
| # svelte-check-native, which silently discovers zero files on Linux (see the note on their | |
| # `check` scripts) — and once pointed at a checker that does read their sources they report | |
| # ~880 and ~838 errors respectively. That debt has to be triaged before either can be gated. | |
| web-typecheck: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| defaults: | |
| run: | |
| working-directory: src/Web | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: pnpm/action-setup@v4 | |
| with: | |
| # src/Web's lockfile is v11 format, so pnpm 9 (what the unit job pins) cannot read it | |
| # with --frozen-lockfile. Same pin the image build uses in docker-publish.yml. | |
| version: "11.5.0" | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "24" | |
| cache: pnpm | |
| cache-dependency-path: src/Web/pnpm-lock.yaml | |
| - run: pnpm install --frozen-lockfile | |
| - name: Typecheck library packages | |
| run: | | |
| pnpm --filter @nightscout/glucose-chart --filter @nocturne/coach run check | |
| - name: Bot unit tests | |
| run: pnpm --filter @nocturne/bot run test | |
| - name: Documentation screenshots | |
| run: | | |
| pnpm --filter @nocturne/screenshots run check | |
| pnpm --filter @nocturne/screenshots run validate | |
| pnpm --filter @nocturne/screenshots run check-refs | |
| pnpm --filter @nocturne/screenshots run check-embeds | |
| integration-db: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-dotnet@v4 | |
| with: | |
| dotnet-version: "10.0" | |
| - name: Cache NuGet | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.nuget/packages | |
| key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'Directory.Packages.props') }} | |
| - name: Integration tests (Infrastructure.Data — RLS + DataProtection) | |
| run: | | |
| dotnet test tests/Integration/Nocturne.Infrastructure.Data.Tests/Nocturne.Infrastructure.Data.Tests.csproj \ | |
| --filter "Category!=E2E" \ | |
| --logger "trx;LogFileName=integration-db.trx" \ | |
| -p:GenerateNSwagClient=false \ | |
| || exit 1 | |
| - uses: actions/upload-artifact@v4 | |
| if: failure() | |
| with: | |
| name: integration-db-trx | |
| path: "**/*.trx" | |
| # E2E tests deferred: Aspire.Hosting.Testing hangs on GitHub Actions runners — | |
| # DCP resource orchestration never completes. Tests pass locally. Revisit when | |
| # Aspire CI support matures or move to a self-hosted runner. |