diff --git a/.github/workflows/knip.yml b/.github/workflows/knip.yml index ff782ed03d..0e8c55b1c5 100644 --- a/.github/workflows/knip.yml +++ b/.github/workflows/knip.yml @@ -26,7 +26,7 @@ jobs: cache: 'yarn' - name: Install dependencies - run: yarn install + run: yarn install --immutable - name: Run Knip run: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7df016c548..68202d94ae 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -41,14 +41,19 @@ jobs: cache-dependency-path: 'yarn.lock' cache: 'yarn' - name: Install root dependencies - run: yarn install + run: yarn install --immutable - name: Build dependencies run: make ci-build - name: Run unit tests run: make ci-unit - integration: + integration-shards: + name: Integration - Shard ${{ matrix.shard }} timeout-minutes: 16 runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + shard: [1, 2, 3, 4] steps: - name: Checkout uses: actions/checkout@v6 @@ -59,17 +64,46 @@ jobs: cache-dependency-path: 'yarn.lock' cache: 'yarn' - name: Install root dependencies - run: yarn install + run: yarn install --immutable - name: Expose GitHub Runtime uses: crazy-max/ghaction-github-runtime@v4 - name: Spin up docker services run: | docker buildx create --use --driver=docker-container - docker buildx bake -f ./docker-compose.ci.yml --set *.cache-to="type=gha" --set *.cache-from="type=gha" --load + docker buildx bake -f ./docker-compose.ci.yml --set *.cache-to="type=gha,mode=max,scope=ci-integration" --set *.cache-from="type=gha,scope=ci-integration" --load - name: Build dependencies run: make ci-build + # Integration tests boot a MockServer on fixed ports and share a single + # MongoDB/ClickHouse database, so they must stay serial (--runInBand) + # within a runner. We shard ACROSS runners instead: each shard is its own + # VM with its own Docker stack, and jest's --shard splits the test files + # so the shards run in parallel. --shard is forwarded through nx (args + # after `--` reach the underlying jest invocations). + # + # Runs inline (not `make ci-int`) so the compose project stays `hdx-ci` + # (matching the bake step above); make ci-int's `-p int-` is local + # multi-worktree isolation that CI doesn't need, and routing through it + # would reintroduce a project-name mismatch against bake. Teardown and + # log-archival are omitted intentionally — the runner is ephemeral and + # Actions streams stdout. - name: Run integration tests - run: make ci-int + run: | + docker compose -f ./docker-compose.ci.yml up -d --quiet-pull + npx nx run-many -t ci:int --parallel=false --output-style=stream -- --shard=${{ matrix.shard }}/${{ strategy.job-total }} + # Stable aggregator context: `integration` is green only when all four shards + # pass. Merge-queue / required-status checks target this single context, since + # the per-shard contexts (Integration - Shard N) are not stable check names. + integration: + needs: [integration-shards] + if: always() + runs-on: ubuntu-24.04 + timeout-minutes: 5 + steps: + - name: Verify all integration shards passed + if: needs.integration-shards.result != 'success' + run: | + echo "::error::One or more integration shards failed" + exit 1 otel-unit-test: timeout-minutes: 8 runs-on: ubuntu-24.04 @@ -264,7 +298,7 @@ jobs: cache: 'yarn' - name: Install dependencies - run: yarn install + run: yarn install --immutable - name: Build App run: yarn build:clickhouse diff --git a/AGENTS.md b/AGENTS.md index 17fa68b54f..6c9afa8393 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -113,11 +113,14 @@ yarn ci:unit # Run unit tests yarn dev:unit # Watch mode for unit tests ``` -**packages/api** (integration tests only): +**packages/api** (unit and integration tests): ```bash -make dev-int-build # Build dependencies (run once before tests) -make dev-int FILE= # Spins up Docker services and runs tests. +cd packages/api +yarn ci:unit # Run unit tests (no services needed) + +make dev-int-build # Build dependencies (run once before integration tests) +make dev-int FILE= # Spins up Docker services and runs integration tests. # Ctrl-C to stop and wait for all services to tear down. ``` diff --git a/packages/api/jest.config.js b/packages/api/jest.config.js index 8b6d0e10fb..d8d938caa1 100644 --- a/packages/api/jest.config.js +++ b/packages/api/jest.config.js @@ -17,6 +17,7 @@ module.exports = { verbose: true, rootDir: './src', testMatch: ['**/__tests__/**/*.test.ts?(x)'], + testPathIgnorePatterns: ['/node_modules/', '.*\\.int\\.test\\.tsx?$'], testTimeout: 30000, moduleNameMapper: { '@/(.*)$': '/$1', diff --git a/packages/api/jest.int.config.js b/packages/api/jest.int.config.js new file mode 100644 index 0000000000..add0482623 --- /dev/null +++ b/packages/api/jest.int.config.js @@ -0,0 +1,10 @@ +const base = require('./jest.config.js'); + +/** @type {import("jest").Config} **/ +module.exports = { + ...base, + testMatch: ['**/__tests__/**/*.int.test.ts?(x)'], + // Override the unit config's ignore list: it excludes `.int.test.ts`, which + // would otherwise hide every integration test from this suite. + testPathIgnorePatterns: ['/node_modules/'], +}; diff --git a/packages/api/package.json b/packages/api/package.json index 312a94c86e..c028ad6174 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -92,8 +92,10 @@ "lint": "npx eslint --quiet . --ext .ts", "lint:fix": "npx eslint . --ext .ts --fix", "ci:lint": "yarn lint && yarn tsc --noEmit && yarn lint:openapi", - "ci:int": "DOTENV_CONFIG_PATH=.env.test DOTENV_CONFIG_OVERRIDE=true jest --runInBand --ci --forceExit", - "dev:int": "DOTENV_CONFIG_PATH=.env.test DOTENV_CONFIG_OVERRIDE=true jest --runInBand --coverage --forceExit", + "ci:unit": "jest --ci --coverage", + "dev:unit": "jest --watch", + "ci:int": "DOTENV_CONFIG_PATH=.env.test DOTENV_CONFIG_OVERRIDE=true jest --config jest.int.config.js --runInBand --ci --forceExit --passWithNoTests", + "dev:int": "DOTENV_CONFIG_PATH=.env.test DOTENV_CONFIG_OVERRIDE=true jest --config jest.int.config.js --runInBand --coverage --forceExit", "dev:migrate-db-create": "ts-node node_modules/.bin/migrate-mongo create -f migrate-mongo-config.ts", "dev:migrate-db": "ts-node node_modules/.bin/migrate-mongo up -f migrate-mongo-config.ts", "dev:migrate-ch-create": "migrate create -ext sql -dir ./migrations/ch -seq", diff --git a/packages/api/src/clickhouse/__tests__/__snapshots__/renderChartConfig.test.ts.snap b/packages/api/src/clickhouse/__tests__/__snapshots__/renderChartConfig.int.test.ts.snap similarity index 100% rename from packages/api/src/clickhouse/__tests__/__snapshots__/renderChartConfig.test.ts.snap rename to packages/api/src/clickhouse/__tests__/__snapshots__/renderChartConfig.int.test.ts.snap diff --git a/packages/api/src/clickhouse/__tests__/renderChartConfig.test.ts b/packages/api/src/clickhouse/__tests__/renderChartConfig.int.test.ts similarity index 100% rename from packages/api/src/clickhouse/__tests__/renderChartConfig.test.ts rename to packages/api/src/clickhouse/__tests__/renderChartConfig.int.test.ts diff --git a/packages/api/src/controllers/__tests__/alertHistory.test.ts b/packages/api/src/controllers/__tests__/alertHistory.int.test.ts similarity index 100% rename from packages/api/src/controllers/__tests__/alertHistory.test.ts rename to packages/api/src/controllers/__tests__/alertHistory.int.test.ts diff --git a/packages/api/src/controllers/__tests__/sources.test.ts b/packages/api/src/controllers/__tests__/sources.int.test.ts similarity index 100% rename from packages/api/src/controllers/__tests__/sources.test.ts rename to packages/api/src/controllers/__tests__/sources.int.test.ts diff --git a/packages/api/src/controllers/__tests__/team.test.ts b/packages/api/src/controllers/__tests__/team.int.test.ts similarity index 100% rename from packages/api/src/controllers/__tests__/team.test.ts rename to packages/api/src/controllers/__tests__/team.int.test.ts diff --git a/packages/api/src/mcp/__tests__/alerts.test.ts b/packages/api/src/mcp/__tests__/alerts.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/alerts.test.ts rename to packages/api/src/mcp/__tests__/alerts.int.test.ts diff --git a/packages/api/src/mcp/__tests__/dashboards/deleteDashboard.test.ts b/packages/api/src/mcp/__tests__/dashboards/deleteDashboard.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/dashboards/deleteDashboard.test.ts rename to packages/api/src/mcp/__tests__/dashboards/deleteDashboard.int.test.ts diff --git a/packages/api/src/mcp/__tests__/dashboards/getDashboard.test.ts b/packages/api/src/mcp/__tests__/dashboards/getDashboard.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/dashboards/getDashboard.test.ts rename to packages/api/src/mcp/__tests__/dashboards/getDashboard.int.test.ts diff --git a/packages/api/src/mcp/__tests__/dashboards/getDashboardTile.test.ts b/packages/api/src/mcp/__tests__/dashboards/getDashboardTile.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/dashboards/getDashboardTile.test.ts rename to packages/api/src/mcp/__tests__/dashboards/getDashboardTile.int.test.ts diff --git a/packages/api/src/mcp/__tests__/dashboards/patchDashboard.test.ts b/packages/api/src/mcp/__tests__/dashboards/patchDashboard.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/dashboards/patchDashboard.test.ts rename to packages/api/src/mcp/__tests__/dashboards/patchDashboard.int.test.ts diff --git a/packages/api/src/mcp/__tests__/dashboards/queryTile.test.ts b/packages/api/src/mcp/__tests__/dashboards/queryTile.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/dashboards/queryTile.test.ts rename to packages/api/src/mcp/__tests__/dashboards/queryTile.int.test.ts diff --git a/packages/api/src/mcp/__tests__/dashboards/saveDashboard.test.ts b/packages/api/src/mcp/__tests__/dashboards/saveDashboard.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/dashboards/saveDashboard.test.ts rename to packages/api/src/mcp/__tests__/dashboards/saveDashboard.int.test.ts diff --git a/packages/api/src/mcp/__tests__/dashboards/searchDashboards.test.ts b/packages/api/src/mcp/__tests__/dashboards/searchDashboards.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/dashboards/searchDashboards.test.ts rename to packages/api/src/mcp/__tests__/dashboards/searchDashboards.int.test.ts diff --git a/packages/api/src/mcp/__tests__/deltasTool.test.ts b/packages/api/src/mcp/__tests__/deltasTool.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/deltasTool.test.ts rename to packages/api/src/mcp/__tests__/deltasTool.int.test.ts diff --git a/packages/api/src/mcp/__tests__/queryTool.test.ts b/packages/api/src/mcp/__tests__/queryTool.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/queryTool.test.ts rename to packages/api/src/mcp/__tests__/queryTool.int.test.ts diff --git a/packages/api/src/mcp/__tests__/savedSearches.test.ts b/packages/api/src/mcp/__tests__/savedSearches.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/savedSearches.test.ts rename to packages/api/src/mcp/__tests__/savedSearches.int.test.ts diff --git a/packages/api/src/mcp/__tests__/sources.test.ts b/packages/api/src/mcp/__tests__/sources.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/sources.test.ts rename to packages/api/src/mcp/__tests__/sources.int.test.ts diff --git a/packages/api/src/mcp/__tests__/trace.test.ts b/packages/api/src/mcp/__tests__/trace.int.test.ts similarity index 100% rename from packages/api/src/mcp/__tests__/trace.test.ts rename to packages/api/src/mcp/__tests__/trace.int.test.ts diff --git a/packages/api/src/models/__tests__/index.test.ts b/packages/api/src/models/__tests__/index.int.test.ts similarity index 100% rename from packages/api/src/models/__tests__/index.test.ts rename to packages/api/src/models/__tests__/index.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/alerts.test.ts b/packages/api/src/routers/api/__tests__/alerts.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/alerts.test.ts rename to packages/api/src/routers/api/__tests__/alerts.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/connections.test.ts b/packages/api/src/routers/api/__tests__/connections.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/connections.test.ts rename to packages/api/src/routers/api/__tests__/connections.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/dashboard.test.ts b/packages/api/src/routers/api/__tests__/dashboard.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/dashboard.test.ts rename to packages/api/src/routers/api/__tests__/dashboard.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/favorites.test.ts b/packages/api/src/routers/api/__tests__/favorites.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/favorites.test.ts rename to packages/api/src/routers/api/__tests__/favorites.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/pinnedFilters.test.ts b/packages/api/src/routers/api/__tests__/pinnedFilters.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/pinnedFilters.test.ts rename to packages/api/src/routers/api/__tests__/pinnedFilters.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/prometheus.integration.test.ts b/packages/api/src/routers/api/__tests__/prometheus.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/prometheus.integration.test.ts rename to packages/api/src/routers/api/__tests__/prometheus.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/savedSearch.test.ts b/packages/api/src/routers/api/__tests__/savedSearch.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/savedSearch.test.ts rename to packages/api/src/routers/api/__tests__/savedSearch.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/sources.test.ts b/packages/api/src/routers/api/__tests__/sources.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/sources.test.ts rename to packages/api/src/routers/api/__tests__/sources.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/team.test.ts b/packages/api/src/routers/api/__tests__/team.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/team.test.ts rename to packages/api/src/routers/api/__tests__/team.int.test.ts diff --git a/packages/api/src/routers/api/__tests__/webhooks.test.ts b/packages/api/src/routers/api/__tests__/webhooks.int.test.ts similarity index 100% rename from packages/api/src/routers/api/__tests__/webhooks.test.ts rename to packages/api/src/routers/api/__tests__/webhooks.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/alerts.test.ts b/packages/api/src/routers/external-api/__tests__/alerts.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/alerts.test.ts rename to packages/api/src/routers/external-api/__tests__/alerts.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/charts.test.ts b/packages/api/src/routers/external-api/__tests__/charts.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/charts.test.ts rename to packages/api/src/routers/external-api/__tests__/charts.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/connections.test.ts b/packages/api/src/routers/external-api/__tests__/connections.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/connections.test.ts rename to packages/api/src/routers/external-api/__tests__/connections.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/dashboards.test.ts b/packages/api/src/routers/external-api/__tests__/dashboards.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/dashboards.test.ts rename to packages/api/src/routers/external-api/__tests__/dashboards.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/savedSearches-crud.test.ts b/packages/api/src/routers/external-api/__tests__/savedSearches-crud.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/savedSearches-crud.test.ts rename to packages/api/src/routers/external-api/__tests__/savedSearches-crud.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/search.test.ts b/packages/api/src/routers/external-api/__tests__/search.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/search.test.ts rename to packages/api/src/routers/external-api/__tests__/search.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/sources-crud.test.ts b/packages/api/src/routers/external-api/__tests__/sources-crud.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/sources-crud.test.ts rename to packages/api/src/routers/external-api/__tests__/sources-crud.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/sources.test.ts b/packages/api/src/routers/external-api/__tests__/sources.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/sources.test.ts rename to packages/api/src/routers/external-api/__tests__/sources.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/team.test.ts b/packages/api/src/routers/external-api/__tests__/team.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/team.test.ts rename to packages/api/src/routers/external-api/__tests__/team.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/v2.test.ts b/packages/api/src/routers/external-api/__tests__/v2.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/v2.test.ts rename to packages/api/src/routers/external-api/__tests__/v2.int.test.ts diff --git a/packages/api/src/routers/external-api/__tests__/webhooks.test.ts b/packages/api/src/routers/external-api/__tests__/webhooks.int.test.ts similarity index 100% rename from packages/api/src/routers/external-api/__tests__/webhooks.test.ts rename to packages/api/src/routers/external-api/__tests__/webhooks.int.test.ts diff --git a/packages/api/src/tasks/checkAlerts/__tests__/__snapshots__/renderAlertTemplate.test.ts.snap b/packages/api/src/tasks/checkAlerts/__tests__/__snapshots__/renderAlertTemplate.int.test.ts.snap similarity index 100% rename from packages/api/src/tasks/checkAlerts/__tests__/__snapshots__/renderAlertTemplate.test.ts.snap rename to packages/api/src/tasks/checkAlerts/__tests__/__snapshots__/renderAlertTemplate.int.test.ts.snap diff --git a/packages/api/src/tasks/checkAlerts/__tests__/checkAlerts.test.ts b/packages/api/src/tasks/checkAlerts/__tests__/checkAlerts.int.test.ts similarity index 100% rename from packages/api/src/tasks/checkAlerts/__tests__/checkAlerts.test.ts rename to packages/api/src/tasks/checkAlerts/__tests__/checkAlerts.int.test.ts diff --git a/packages/api/src/tasks/checkAlerts/__tests__/renderAlertTemplate.test.ts b/packages/api/src/tasks/checkAlerts/__tests__/renderAlertTemplate.int.test.ts similarity index 100% rename from packages/api/src/tasks/checkAlerts/__tests__/renderAlertTemplate.test.ts rename to packages/api/src/tasks/checkAlerts/__tests__/renderAlertTemplate.int.test.ts diff --git a/packages/api/src/tasks/checkAlerts/__tests__/singleInvocationAlert.test.ts b/packages/api/src/tasks/checkAlerts/__tests__/singleInvocationAlert.int.test.ts similarity index 100% rename from packages/api/src/tasks/checkAlerts/__tests__/singleInvocationAlert.test.ts rename to packages/api/src/tasks/checkAlerts/__tests__/singleInvocationAlert.int.test.ts diff --git a/packages/api/src/tasks/checkAlerts/providers/__tests__/default.test.ts b/packages/api/src/tasks/checkAlerts/providers/__tests__/default.int.test.ts similarity index 100% rename from packages/api/src/tasks/checkAlerts/providers/__tests__/default.test.ts rename to packages/api/src/tasks/checkAlerts/providers/__tests__/default.int.test.ts diff --git a/packages/api/src/tasks/provisionDashboards/__tests__/provisionDashboards.test.ts b/packages/api/src/tasks/provisionDashboards/__tests__/provisionDashboards.int.test.ts similarity index 100% rename from packages/api/src/tasks/provisionDashboards/__tests__/provisionDashboards.test.ts rename to packages/api/src/tasks/provisionDashboards/__tests__/provisionDashboards.int.test.ts diff --git a/packages/common-utils/package.json b/packages/common-utils/package.json index 92d7006597..358731acc4 100644 --- a/packages/common-utils/package.json +++ b/packages/common-utils/package.json @@ -46,9 +46,9 @@ "lint": "npx eslint --quiet . --ext .ts", "lint:fix": "npx eslint . --ext .ts --fix", "ci:lint": "yarn lint && yarn tsc --noEmit", - "ci:unit": "jest --runInBand --ci --coverage", - "dev:unit": "jest --watchAll --runInBand", - "ci:int": "DOTENV_CONFIG_PATH=.env.test jest --config jest.int.config.js --runInBand --ci --coverage", + "ci:unit": "jest --ci --coverage", + "dev:unit": "jest --watchAll", + "ci:int": "DOTENV_CONFIG_PATH=.env.test jest --config jest.int.config.js --runInBand --ci --coverage --passWithNoTests", "dev:int": "DOTENV_CONFIG_PATH=.env.test jest --config jest.int.config.js --watchAll --runInBand" } }