From 6a113659c850aa2a2fac139fa8f08c200c52da89 Mon Sep 17 00:00:00 2001 From: moilanik Date: Sat, 20 Jun 2026 14:26:08 +0300 Subject: [PATCH] isoja testimuutoksia --- .gitea/workflows/example-cucumber-tests.yml | 2 +- tests/check-version.bats | 1 + tests/dispatch-workflow.bats | 14 +++---- .../step_definitions/commit-status.steps.js | 10 +---- .../features/step_definitions/common.steps.js | 9 ++--- .../step_definitions/test-execution.steps.js | 24 ++++-------- tests/helpers/mock-api.sh | 39 +++++++++++-------- tests/helpers/mock-server.py | 7 ---- tests/publish-git-pages.bats | 7 +--- tests/report-status.bats | 6 +-- 10 files changed, 50 insertions(+), 69 deletions(-) diff --git a/.gitea/workflows/example-cucumber-tests.yml b/.gitea/workflows/example-cucumber-tests.yml index 9f467ae..a9ab2d6 100644 --- a/.gitea/workflows/example-cucumber-tests.yml +++ b/.gitea/workflows/example-cucumber-tests.yml @@ -8,7 +8,7 @@ on: cucumber-node-image: required: false type: string - default: gitea.app.keskikuja.site/niko/ci-cucumber:latest + default: gitea.app.keskikuja.site/niko/ci-cucumber:with-python secrets: GITEA_TOKEN: required: true diff --git a/tests/check-version.bats b/tests/check-version.bats index b34472d..f27f4cd 100644 --- a/tests/check-version.bats +++ b/tests/check-version.bats @@ -5,6 +5,7 @@ source "$BATS_TEST_DIRNAME/helpers/mock-api.sh" setup() { export GITEA_TOKEN=test-token export GIT_TAG_PREFIX="" + export SERVER_URL="http://localhost:18080" export REPO="niko/test" export SHA="abc123" rm -rf /tmp/build-ctx diff --git a/tests/dispatch-workflow.bats b/tests/dispatch-workflow.bats index dec53f5..3f271de 100644 --- a/tests/dispatch-workflow.bats +++ b/tests/dispatch-workflow.bats @@ -19,7 +19,7 @@ teardown() { {"code":200,"body":{"id":1,"status":"completed","conclusion":"success"}} ]' mock_start - run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "$GITEA_API_URL" "test-token-abc123" + run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123" [ "$status" -eq 0 ] } @@ -31,7 +31,7 @@ teardown() { {"code":200,"body":{"id":1,"status":"completed","conclusion":"failure"}} ]' mock_start - run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "$GITEA_API_URL" "test-token-abc123" + run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123" [ "$status" -eq 1 ] } @@ -43,7 +43,7 @@ teardown() { {"code":200,"body":{"id":1,"status":"completed","conclusion":"cancelled"}} ]' mock_start - run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "$GITEA_API_URL" "test-token-abc123" + run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123" [ "$status" -eq 1 ] } @@ -61,7 +61,7 @@ teardown() { {"code":200,"body":{"id":1,"status":"running"}} ]' mock_start - run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "$GITEA_API_URL" "test-token-abc123" "0.001" + run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123" "0.001" [ "$status" -eq 124 ] } @@ -70,7 +70,7 @@ teardown() { {"code":500} ]' mock_start - run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "$GITEA_API_URL" "test-token-abc123" + run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123" [ "$status" -eq 1 ] } @@ -81,7 +81,7 @@ teardown() { {"code":200,"body":{"id":1,"status":"completed","conclusion":"success"}} ]' mock_start - run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "$GITEA_API_URL" "test-token-abc123" + run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "http://localhost:18080" "test-token-abc123" [ "$status" -eq 0 ] path=$(mock_get_first_request_path) [[ "$path" == *"/api/v1/repos/test-owner/test-repo/actions/workflows/test.yml/dispatches"* ]] @@ -126,7 +126,7 @@ teardown() { {"code":200,"body":{"workflow_runs":[]}} ]' mock_start - run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{}' "$GITEA_API_URL" "test-token-abc123" + run bash scripts/dispatch-workflow.sh "test-owner/test-repo" "test.yml" "main" '{}' "http://localhost:18080" "test-token-abc123" [ "$status" -eq 1 ] [[ "$output" == *"ERROR"* ]] } diff --git a/tests/features/step_definitions/commit-status.steps.js b/tests/features/step_definitions/commit-status.steps.js index 4df2e3a..3cbe24a 100644 --- a/tests/features/step_definitions/commit-status.steps.js +++ b/tests/features/step_definitions/commit-status.steps.js @@ -27,8 +27,7 @@ function bashQuiet(cmd) { } function runReportStatus(args) { - const apiUrl = process.env.GITEA_API_URL || 'http://localhost:18080'; - return bash(`export GITEA_API_URL="${apiUrl}" GITEA_TOKEN="test-token-abc123" GIT_PAGES_URL="https://reports.example.com" GITHUB_REPOSITORY="test-owner/test-repo" GITHUB_SHA="abc123def456789012345678901234567890abcd" GITHUB_RUN_ID="42"; bash "${REPORT_SCRIPT}" ${args}`); + return bash(`export GITEA_API_URL="http://localhost:18080" GITEA_TOKEN="test-token-abc123" GIT_PAGES_URL="https://reports.example.com" GITHUB_REPOSITORY="test-owner/test-repo" GITHUB_SHA="abc123def456789012345678901234567890abcd" GITHUB_RUN_ID="42"; bash "${REPORT_SCRIPT}" ${args}`); } function getMockBody() { @@ -111,12 +110,7 @@ Then('the source commit shows the deployment status alongside the build status', When('a build step tries to report status but the build system is unavailable', function () { bashQuiet(`source "${MOCK_SCRIPT}" && mock_stop`); execSync('sleep 0.3', { stdio: 'ignore' }); - const out = execSync(`bash -o pipefail -c 'source "${MOCK_SCRIPT}" && mock_set_response 500 && mock_start >&2 && echo "$GITEA_API_URL"'`, { - cwd: PROJECT_ROOT, - encoding: 'utf-8', - stdio: ['pipe', 'pipe', 'pipe'], - }); - process.env.GITEA_API_URL = out.trim(); + bashQuiet(`source "${MOCK_SCRIPT}" && mock_set_response 500 && mock_start`); const r = runReportStatus('success "Should fail"'); this.reportStatusFailed = (r.status !== 0); }); diff --git a/tests/features/step_definitions/common.steps.js b/tests/features/step_definitions/common.steps.js index 6460bd7..6c665a8 100644 --- a/tests/features/step_definitions/common.steps.js +++ b/tests/features/step_definitions/common.steps.js @@ -6,16 +6,15 @@ const PROJECT_ROOT = path.resolve(__dirname, '..', '..', '..'); const MOCK_SCRIPT = path.join(PROJECT_ROOT, 'tests', 'helpers', 'mock-api.sh'); Before({ tags: '@mock' }, function () { - const out = execSync(`bash -o pipefail -c 'source "${MOCK_SCRIPT}" && mock_start >&2 && echo "$GITEA_API_URL"'`, { + const out = execSync(`bash -c 'source "${MOCK_SCRIPT}" && mock_start && sleep 1 && curl -s -o /dev/null -w "%{http_code}" --max-time 3 http://localhost:18080/api/v1/repos/health/check'`, { cwd: PROJECT_ROOT, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], }); - const apiUrl = out.trim(); - if (!apiUrl.startsWith('http')) { - throw new Error(`Mock server failed to start (no API URL: ${apiUrl})`); + const trimmed = out.trim(); + if (!trimmed.startsWith('2') && !trimmed.startsWith('4')) { + throw new Error(`Mock server failed to start (HTTP ${trimmed})`); } - process.env.GITEA_API_URL = apiUrl; }); After({ tags: '@mock' }, function () { diff --git a/tests/features/step_definitions/test-execution.steps.js b/tests/features/step_definitions/test-execution.steps.js index 100af60..8657eb7 100644 --- a/tests/features/step_definitions/test-execution.steps.js +++ b/tests/features/step_definitions/test-execution.steps.js @@ -21,15 +21,9 @@ function bash(cmd) { } } -function getFreePort() { - const out = execSync(`python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()"`, { encoding: 'utf-8' }); - return parseInt(out.trim(), 10); -} - function setupMock(seqJson) { - const port = getFreePort(); - process.env.MOCK_PORT = String(port); - process.env.GITEA_API_URL = `http://localhost:${port}`; + execSync('lsof -ti :18080 2>/dev/null | xargs -r kill -9 2>/dev/null || true', { stdio: 'ignore' }); + execSync('sleep 0.4', { stdio: 'ignore' }); const seqFile = path.join(os.tmpdir(), `cucumber_seq_${Date.now()}.json`); fs.writeFileSync(seqFile, seqJson); @@ -40,16 +34,17 @@ function setupMock(seqJson) { const configFile = path.join(os.tmpdir(), `cucumber_cfg_${Date.now()}.txt`); fs.writeFileSync(configFile, `SEQUENCE\n${seqJson}\n${idxFile}`); - const proc = spawn('python3', [MOCK_SERVER, String(port), configFile, reqFile], { + const proc = spawn('python3', [MOCK_SERVER, '18080', configFile, reqFile], { cwd: PROJECT_ROOT, detached: true, stdio: 'ignore', }); proc.unref(); + this._mockProc = proc; for (let i = 0; i < 20; i++) { try { - execSync(`nc -z localhost ${port}`, { stdio: 'ignore' }); + execSync('curl -s --max-time 1 http://localhost:18080/', { stdio: 'ignore' }); fs.writeFileSync(idxFile, '0'); return; } catch (_) {} @@ -74,8 +69,7 @@ When('a test workflow is dispatched to a test project', function () { { code: 200, body: { workflow_runs: [{ id: 1, status: 'running' }] } }, { code: 200, body: { id: 1, status: 'completed', conclusion: 'success' } }, ])); - const url = process.env.GITEA_API_URL; - const r = runDispatch(`"test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "${url}" "test-token-abc123"`); + const r = runDispatch('"test-owner/test-repo" "test.yml" "main" \'{"version":"1.2.3"}\' "http://localhost:18080" "test-token-abc123"'); this.dispatchResult = r.status; }); @@ -93,8 +87,7 @@ When('a test workflow is dispatched and the tests fail', function () { { code: 200, body: { workflow_runs: [{ id: 1, status: 'running' }] } }, { code: 200, body: { id: 1, status: 'completed', conclusion: 'failure' } }, ])); - const url = process.env.GITEA_API_URL; - const r = runDispatch(`"test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "${url}" "test-token-abc123"`); + const r = runDispatch('"test-owner/test-repo" "test.yml" "main" \'{"version":"1.2.3"}\' "http://localhost:18080" "test-token-abc123"'); this.dispatchResult = r.status; }); @@ -110,8 +103,7 @@ When('a test workflow is dispatched but does not finish within the allowed time' { code: 200, body: { id: 1, status: 'running' } }, { code: 200, body: { id: 1, status: 'running' } }, ])); - const url = process.env.GITEA_API_URL; - const r = runDispatch(`"test-owner/test-repo" "test.yml" "main" '{"version":"1.2.3"}' "${url}" "test-token-abc123" "0.001"`); + const r = runDispatch('"test-owner/test-repo" "test.yml" "main" \'{"version":"1.2.3"}\' "http://localhost:18080" "test-token-abc123" "0.001"'); this.dispatchResult = r.status; }); diff --git a/tests/helpers/mock-api.sh b/tests/helpers/mock-api.sh index f7db2cd..e6ad4b5 100644 --- a/tests/helpers/mock-api.sh +++ b/tests/helpers/mock-api.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -MOCK_PORT="" +MOCK_PORT=18080 MOCK_PID="" MOCK_REQUEST_FILE="" MOCK_RESPONSE_CODE=201 @@ -9,20 +9,29 @@ MOCK_STATE_FILE="/tmp/mock_api_state" MOCK_SEQUENCE_FILE="" MOCK_CONFIG_FILE="" -_free_port() { - python3 -c "import socket; s=socket.socket(); s.bind(('',0)); print(s.getsockname()[1]); s.close()" +_kill_port() { + local pids + pids=$(lsof -ti ":$MOCK_PORT" 2>/dev/null) || true + if [ -n "$pids" ]; then + kill -9 $pids 2>/dev/null || true + sleep 0.5 + fi +} + +_wait_port_free() { + local i=0 + while lsof -ti ":$MOCK_PORT" >/dev/null 2>&1 && [ $i -lt 50 ]; do + sleep 0.1 + i=$((i + 1)) + done } _wait_port_ready() { local i=0 - while [ $i -lt 30 ]; do - if nc -z localhost "$MOCK_PORT" 2>/dev/null; then - return 0 - fi - sleep 0.1 + while ! lsof -ti ":$MOCK_PORT" >/dev/null 2>&1 && [ $i -lt 30 ]; do + sleep 0.2 i=$((i + 1)) done - return 1 } mock_set_sequence() { @@ -36,12 +45,6 @@ mock_clear_sequence() { } mock_start() { - MOCK_PORT=$(_free_port) - export MOCK_PORT - MOCK_URL="http://localhost:${MOCK_PORT}" - export SERVER_URL="$MOCK_URL" - export GITEA_API_URL="$MOCK_URL" - MOCK_RESPONSE_CODE="${MOCK_RESPONSE_CODE:-201}" MOCK_REQUEST_FILE=$(mktemp) echo "$MOCK_REQUEST_FILE" > "$MOCK_STATE_FILE" @@ -56,15 +59,19 @@ mock_start() { echo "$MOCK_RESPONSE_CODE" >> "$MOCK_CONFIG_FILE" fi + _kill_port + _wait_port_free + nohup python3 "$(dirname "${BASH_SOURCE[0]}")/mock-server.py" "$MOCK_PORT" "$MOCK_CONFIG_FILE" "$MOCK_REQUEST_FILE" \ /dev/null 2>&1 & - disown MOCK_PID=$! _wait_port_ready } mock_stop() { [ -n "${MOCK_PID:-}" ] && kill -9 "$MOCK_PID" 2>/dev/null || true + _kill_port + _wait_port_free [ -n "${MOCK_REQUEST_FILE:-}" ] && rm -f "${MOCK_REQUEST_FILE}" 2>/dev/null || true [ -n "${MOCK_SEQUENCE_FILE:-}" ] && rm -f "${MOCK_SEQUENCE_FILE}" 2>/dev/null || true [ -n "${MOCK_SEQUENCE_FILE:-}" ] && rm -f "${MOCK_SEQUENCE_FILE}.idx" 2>/dev/null || true diff --git a/tests/helpers/mock-server.py b/tests/helpers/mock-server.py index 94b6547..57249d6 100644 --- a/tests/helpers/mock-server.py +++ b/tests/helpers/mock-server.py @@ -1,13 +1,6 @@ #!/usr/bin/env python3 import http.server, json, sys, os, threading -# Daemonize: detach from parent process group -if os.fork() > 0: - sys.exit(0) -os.setsid() -if os.fork() > 0: - sys.exit(0) - PORT = int(sys.argv[1]) CONFIG = sys.argv[2] REQ_FILE = sys.argv[3] diff --git a/tests/publish-git-pages.bats b/tests/publish-git-pages.bats index 9723622..1e62214 100644 --- a/tests/publish-git-pages.bats +++ b/tests/publish-git-pages.bats @@ -63,10 +63,9 @@ teardown() { {"code":200,"body":"published"} ]' mock_start - export GIT_PAGES_URL="http://localhost:${MOCK_PORT}" run bash scripts/publish-git-pages.sh "unit-tests" [ "$status" -eq 0 ] - [[ "$output" == "${GIT_PAGES_URL}/test-owner/test-repo/reports/abc123de" ]] + [[ "$output" == "http://localhost:18080/test-owner/test-repo/reports/abc123de" ]] } @test "publish with suite subpath" { @@ -76,10 +75,9 @@ teardown() { {"code":200,"body":"published"} ]' mock_start - export GIT_PAGES_URL="http://localhost:${MOCK_PORT}" run bash scripts/publish-git-pages.sh "sub/suite" [ "$status" -eq 0 ] - [[ "$output" == "${GIT_PAGES_URL}/test-owner/test-repo/reports/abc123de" ]] + [[ "$output" == "http://localhost:18080/test-owner/test-repo/reports/abc123de" ]] } @test "git-pages returns HTTP 500 → exit 1" { @@ -87,7 +85,6 @@ teardown() { {"code":500,"body":"internal error"} ]' mock_start - export GIT_PAGES_URL="http://localhost:${MOCK_PORT}" run bash scripts/publish-git-pages.sh "unit-tests" [ "$status" -eq 1 ] [[ "$output" == *"500"* ]] diff --git a/tests/report-status.bats b/tests/report-status.bats index c29a5d2..786c731 100644 --- a/tests/report-status.bats +++ b/tests/report-status.bats @@ -23,8 +23,7 @@ teardown() { body=$(mock_get_request_body) [[ "$body" == *'"state":"pending"'* ]] [[ "$body" == *'"description":"Building project"'* ]] - expected_url="${GITEA_API_URL}/test-owner/test-repo/actions/runs/42" - [[ "$body" == *"\"target_url\":\"${expected_url}\""* ]] + [[ "$body" == *'"target_url":"http://localhost:18080/test-owner/test-repo/actions/runs/42"'* ]] method=$(mock_get_request_method) [[ "$method" == "POST" ]] } @@ -45,8 +44,7 @@ teardown() { [ "$status" -eq 0 ] body=$(mock_get_request_body) [[ "$body" == *'"state":"failure"'* ]] - expected_url="${GITEA_API_URL}/test-owner/test-repo/actions/runs/42" - [[ "$body" == *"\"target_url\":\"${expected_url}\""* ]] + [[ "$body" == *'"target_url":"http://localhost:18080/test-owner/test-repo/actions/runs/42"'* ]] } @test "default key when not provided" {