From db30a45782fc99fc33656a58e148bbb08213efa9 Mon Sep 17 00:00:00 2001 From: neon <18559658+neonsolstice@users.noreply.github.com> Date: Mon, 30 Mar 2026 01:18:32 -0600 Subject: [PATCH] test(scanner): bootstrap scanner E2E test infrastructure --- .github/workflows/e2e-scanner-file-ops.yml | 77 + .github/workflows/e2e-scanner.yml | 75 + DEVELOPMENT.md | 30 + .../components/LibraryCreatorScanner.vue | 12 +- .../library/composables/useLibraryCreator.ts | 2 +- package.json | 3 + packages/types/src/library.ts | 20 +- scripts/db/prepare-e2e.sh | 13 + scripts/test/scanner-e2e.sh | 21 + scripts/test/scanner-file-ops-e2e.sh | 21 + server/package.json | 7 +- server/src/db/migrations/0000_baseline.sql | 2 +- .../src/db/migrations/meta/0000_snapshot.json | 4 +- server/src/db/migrations/meta/_journal.json | 2 +- server/src/db/schema/libraries.ts | 2 +- .../modules/library/dto/create-library.dto.ts | 2 +- .../modules/library/dto/update-library.dto.ts | 2 +- .../src/modules/library/library.dto.test.ts | 2 + server/src/modules/library/library.service.ts | 30 +- .../scanner/file-event-processor.service.ts | 116 +- .../scanner/file-watcher.service.test.ts | 42 +- .../modules/scanner/file-watcher.service.ts | 128 +- server/src/modules/scanner/lib/walk.test.ts | 9 + server/src/modules/scanner/lib/walk.ts | 5 +- .../src/modules/scanner/scanner.repository.ts | 110 +- .../modules/scanner/scanner.service.test.ts | 266 ++- server/src/modules/scanner/scanner.service.ts | 295 ++- server/src/scripts/db-prepare-e2e.ts | 103 ++ server/test/e2e/scanner-fixture-builder.ts | 48 + server/test/e2e/scanner-harness.ts | 235 +++ server/test/scanner-file-ops.e2e-spec.ts | 1633 +++++++++++++++++ server/test/scanner.e2e-spec.ts | 474 +++++ test-results/server/scanner-e2e-junit.xml | 75 + .../server/scanner-e2e-scenarios.json | 218 +++ .../server/scanner-file-ops-e2e-junit.xml | 83 + .../scanner-file-ops-e2e-scenarios.json | 243 +++ 36 files changed, 4288 insertions(+), 122 deletions(-) create mode 100644 .github/workflows/e2e-scanner-file-ops.yml create mode 100644 .github/workflows/e2e-scanner.yml create mode 100644 scripts/db/prepare-e2e.sh create mode 100644 scripts/test/scanner-e2e.sh create mode 100644 scripts/test/scanner-file-ops-e2e.sh create mode 100644 server/src/scripts/db-prepare-e2e.ts create mode 100644 server/test/e2e/scanner-fixture-builder.ts create mode 100644 server/test/e2e/scanner-harness.ts create mode 100644 server/test/scanner-file-ops.e2e-spec.ts create mode 100644 server/test/scanner.e2e-spec.ts create mode 100644 test-results/server/scanner-e2e-junit.xml create mode 100644 test-results/server/scanner-e2e-scenarios.json create mode 100644 test-results/server/scanner-file-ops-e2e-junit.xml create mode 100644 test-results/server/scanner-file-ops-e2e-scenarios.json diff --git a/.github/workflows/e2e-scanner-file-ops.yml b/.github/workflows/e2e-scanner-file-ops.yml new file mode 100644 index 000000000..609cf7529 --- /dev/null +++ b/.github/workflows/e2e-scanner-file-ops.yml @@ -0,0 +1,77 @@ +name: Scanner File Ops E2E +run-name: ${{ format('Scanner File Ops E2E - {0}', github.ref_name) }} + +on: + workflow_dispatch: + schedule: + - cron: "0 4 * * *" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + checks: write + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + NODE_VERSION: "24" + PNPM_VERSION: "10" + E2E_DATABASE_URL: postgres://projectx:projectx@localhost:5432/projectx_e2e + NODE_ENV: test + JWT_SECRET: scanner-e2e-secret-1234 + JWT_EXPIRES_IN: 15m + JWT_REFRESH_EXPIRES_IN: 7d + BOOKS_PATH: ../local/data + APP_URL: http://localhost:5173 + +jobs: + scanner-file-ops-e2e: + name: Scanner File Ops E2E + runs-on: ubuntu-latest + timeout-minutes: 60 + services: + postgres: + image: pgvector/pgvector:pg16 + env: + POSTGRES_USER: projectx + POSTGRES_PASSWORD: projectx + POSTGRES_DB: projectx + ports: + - 5432:5432 + options: >- + --health-cmd="pg_isready -U projectx" + --health-interval=5s + --health-timeout=5s + --health-retries=20 + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Set up Node.js and pnpm + uses: ./.github/actions/setup-node-pnpm + with: + node-version: ${{ env.NODE_VERSION }} + pnpm-version: ${{ env.PNPM_VERSION }} + + - name: Run scanner file ops e2e suite + shell: bash + run: pnpm run test:e2e:scanner:file-ops + + - name: Publish test report annotations + if: always() + uses: EnricoMi/publish-unit-test-result-action@c950f6fb443cb5af20a377fd0dfaa78838901040 # v2 + with: + check_name: Server Scanner File Ops E2E + files: test-results/server/scanner-file-ops-e2e-junit.xml + fail_on: nothing + comment_mode: off + + - name: Upload scanner file ops e2e artifacts + if: always() + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + with: + name: scanner-file-ops-e2e-report + path: test-results/server + retention-days: 7 diff --git a/.github/workflows/e2e-scanner.yml b/.github/workflows/e2e-scanner.yml new file mode 100644 index 000000000..aa44cc73a --- /dev/null +++ b/.github/workflows/e2e-scanner.yml @@ -0,0 +1,75 @@ +name: Scanner E2E +run-name: ${{ format('Scanner E2E - {0}', github.ref_name) }} + +on: + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + checks: write + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + NODE_VERSION: "24" + PNPM_VERSION: "10" + E2E_DATABASE_URL: postgres://projectx:projectx@localhost:5432/projectx_e2e + NODE_ENV: test + JWT_SECRET: scanner-e2e-secret-1234 + JWT_EXPIRES_IN: 15m + JWT_REFRESH_EXPIRES_IN: 7d + BOOKS_PATH: ../local/data + APP_URL: http://localhost:5173 + +jobs: + scanner-e2e: + name: Scanner E2E + runs-on: ubuntu-latest + timeout-minutes: 45 + services: + postgres: + image: pgvector/pgvector:pg16 + env: + POSTGRES_USER: projectx + POSTGRES_PASSWORD: projectx + POSTGRES_DB: projectx + ports: + - 5432:5432 + options: >- + --health-cmd="pg_isready -U projectx" + --health-interval=5s + --health-timeout=5s + --health-retries=20 + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + + - name: Set up Node.js and pnpm + uses: ./.github/actions/setup-node-pnpm + with: + node-version: ${{ env.NODE_VERSION }} + pnpm-version: ${{ env.PNPM_VERSION }} + + - name: Run scanner e2e suite + shell: bash + run: pnpm run test:e2e:scanner + + - name: Publish test report annotations + if: always() + uses: EnricoMi/publish-unit-test-result-action@c950f6fb443cb5af20a377fd0dfaa78838901040 # v2 + with: + check_name: Server Scanner E2E + files: test-results/server/scanner-e2e-junit.xml + fail_on: nothing + comment_mode: off + + - name: Upload scanner e2e artifacts + if: always() + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + with: + name: scanner-e2e-report + path: test-results/server + retention-days: 7 diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 21211005f..3a2d81faa 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -115,6 +115,8 @@ pnpm run test # all tests (server + client) pnpm run test:server # server unit tests only pnpm run test:client # client unit tests only pnpm run test:e2e:smoke # e2e smoke suite (requires running DB) +pnpm run test:e2e:scanner # scanner e2e suite (uses dedicated projectx_e2e DB) +pnpm run test:e2e:scanner:file-ops # scanner file operation e2e suite ``` Watch mode while working on a specific area: @@ -123,6 +125,34 @@ Watch mode while working on a specific area: cd server && pnpm test:watch ``` +### Scanner e2e details + +- `pnpm run test:e2e:scanner` prepares and migrates a dedicated e2e database (`projectx_e2e`) on each run. +- Local runs auto-start PostgreSQL with `docker-compose.dev.yml` if needed. +- Results are written to `test-results/server/`: + - `scanner-e2e-junit.xml` + - `scanner-e2e-scenarios.json` + +### Scanner file operation e2e details + +- `pnpm run test:e2e:scanner:file-ops` prepares and migrates the same dedicated e2e database (`projectx_e2e`) before running. +- Local runs auto-start PostgreSQL with `docker-compose.dev.yml` if needed. +- Results are written to `test-results/server/`: + - `scanner-file-ops-e2e-junit.xml` + - `scanner-file-ops-e2e-scenarios.json` + +### Scanner e2e in CI (manual) + +- Open GitHub Actions and run the **Scanner E2E** workflow manually (`workflow_dispatch`). +- The workflow runs the full scanner scenario matrix against a service-container Postgres instance. +- It uploads `test-results/server/` as an artifact and publishes JUnit annotations. + +### Scanner file operation e2e in CI + +- Open GitHub Actions and run the **Scanner File Ops E2E** workflow manually (`workflow_dispatch`) or wait for the nightly run. +- The workflow runs the full file operation matrix against a service-container Postgres instance. +- It uploads `test-results/server/` as an artifact and publishes JUnit annotations. + --- ## Code Quality diff --git a/client/src/features/library/components/LibraryCreatorScanner.vue b/client/src/features/library/components/LibraryCreatorScanner.vue index b794d58f8..c5c8a5ba3 100644 --- a/client/src/features/library/components/LibraryCreatorScanner.vue +++ b/client/src/features/library/components/LibraryCreatorScanner.vue @@ -74,15 +74,19 @@ function onPatternKeydown(e: KeyboardEvent) {