From c54b9a1e051c856ba770deee9e76afdf2f226d44 Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Fri, 23 Oct 2026 10:41:00 -0400 Subject: [PATCH 1/2] Make the VM smoke test check startup job results --- nix/test/smoke.nix | 56 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/nix/test/smoke.nix b/nix/test/smoke.nix index 855aa370..cbda5cb4 100644 --- a/nix/test/smoke.nix +++ b/nix/test/smoke.nix @@ -9,7 +9,7 @@ # - systemd services start and stay running # - The server responds to basic HTTP requests # - Database migrations run successfully -# - The job executor starts without errors +# - Startup matrix jobs complete successfully { pkgs, lib, @@ -28,11 +28,13 @@ else stateDir = "/var/lib/registry-server"; repoFixturesDir = "${stateDir}/repo-fixtures"; dhallTypes = "${pkgs.registry-server}/bin/types"; + mockUnits = lib.mapAttrsToList (name: _: "wiremock-${name}.service") testConfig.wiremockConfigs; in pkgs.testers.nixosTest { name = "registry-smoke"; testScript = '' + import json import time # Start the registry VM @@ -47,14 +49,27 @@ else timeout=30 ) - # Verify we get a valid JSON response (the jobs endpoint responds) - result = registry.succeed( - "curl -s http://localhost:${envVars.SERVER_PORT}/api/v1/jobs" - ) - - # The server may create matrix jobs on startup for new compilers, so we just verify - # the response is valid JSON (starts with '[') - assert result.strip().startswith("["), f"Expected JSON array, got: {result}" + # The fixture Prelude lacks the newest test compiler (0.15.11), so startup + # must enqueue both dependency-free packages and process their dependants. + # Include completed jobs: otherwise a failed job disappears from the list. + expected = {("prelude", "6.0.1", "0.15.11"), ("type-equality", "4.0.1", "0.15.11")} + deadline = time.monotonic() + 120 + while True: + jobs = json.loads(registry.succeed( + "curl --fail --silent http://localhost:${envVars.SERVER_PORT}/api/v1/jobs?include_completed=true" + )) + assert isinstance(jobs, list), f"Expected jobs array, got: {jobs}" + failed = [job for job in jobs if job.get("finishedAt") and not job["success"]] + assert not failed, f"Startup jobs failed: {json.dumps(failed, indent=2)}" + matrix = { + (job["packageName"], job["packageVersion"], job["compilerVersion"]) + for job in jobs if job["jobType"] == "matrix" + } + if expected <= matrix and all(job.get("finishedAt") and job["success"] for job in jobs): + break + assert time.monotonic() < deadline, f"Startup jobs did not complete: {json.dumps(jobs, indent=2)}" + time.sleep(1) + print(f"✓ All {len(jobs)} startup jobs succeeded: {json.dumps(jobs)}") # Verify the database was created and migrations ran registry.succeed("test -f ${stateDir}/db/registry.sqlite3") @@ -69,9 +84,6 @@ else ) registry.succeed("test -f ${dhallTypes}/v1/Manifest.dhall") - # Give the job executor a moment to start and potentially fail - time.sleep(2) - # Check that the job executor started successfully and didn't fail logs = registry.succeed("journalctl -u server.service --no-pager") assert "Job executor failed:" not in logs, f"Job executor failed on startup. Logs:\n{logs}" @@ -83,8 +95,28 @@ else nodes.registry = { imports = [ (rootPath + "/nix/registry-server.nix") + { + systemd.services = lib.mapAttrs' ( + name: cfg: + lib.nameValuePair "wiremock-${name}" { + serviceConfig.ExecStart = "${pkgs.wiremock}/bin/wiremock --port ${toString cfg.port} --root-dir ${cfg.rootDir} --disable-banner"; + postStart = '' + until ${pkgs.curl}/bin/curl --fail --silent http://localhost:${toString cfg.port}/__admin > /dev/null; do + sleep 0.5 + done + ''; + } + ) testConfig.wiremockConfigs; + } ]; + # The S3 SDK uses virtual-hosted bucket URLs, as in the integration test. + networking.hosts."127.0.0.1" = [ "purescript-registry.localhost" ]; + systemd.services.server = { + requires = mockUnits; + after = mockUnits; + }; + # Apply the git mock overlay on top of the standard overlays nixpkgs.overlays = overlays ++ [ testConfig.testOverlay ]; From cda1da0578004c4fc0c8cc2c4dde258f38c4644a Mon Sep 17 00:00:00 2001 From: Thomas Honeyman Date: Fri, 23 Oct 2026 11:06:11 -0400 Subject: [PATCH 2/2] Keep the VM smoke test focused on deployment --- nix/test/smoke.nix | 66 ++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 44 deletions(-) diff --git a/nix/test/smoke.nix b/nix/test/smoke.nix index cbda5cb4..c5eaf904 100644 --- a/nix/test/smoke.nix +++ b/nix/test/smoke.nix @@ -9,7 +9,7 @@ # - systemd services start and stay running # - The server responds to basic HTTP requests # - Database migrations run successfully -# - Startup matrix jobs complete successfully +# - The job executor starts without errors { pkgs, lib, @@ -28,13 +28,11 @@ else stateDir = "/var/lib/registry-server"; repoFixturesDir = "${stateDir}/repo-fixtures"; dhallTypes = "${pkgs.registry-server}/bin/types"; - mockUnits = lib.mapAttrsToList (name: _: "wiremock-${name}.service") testConfig.wiremockConfigs; in pkgs.testers.nixosTest { name = "registry-smoke"; testScript = '' - import json import time # Start the registry VM @@ -49,27 +47,13 @@ else timeout=30 ) - # The fixture Prelude lacks the newest test compiler (0.15.11), so startup - # must enqueue both dependency-free packages and process their dependants. - # Include completed jobs: otherwise a failed job disappears from the list. - expected = {("prelude", "6.0.1", "0.15.11"), ("type-equality", "4.0.1", "0.15.11")} - deadline = time.monotonic() + 120 - while True: - jobs = json.loads(registry.succeed( - "curl --fail --silent http://localhost:${envVars.SERVER_PORT}/api/v1/jobs?include_completed=true" - )) - assert isinstance(jobs, list), f"Expected jobs array, got: {jobs}" - failed = [job for job in jobs if job.get("finishedAt") and not job["success"]] - assert not failed, f"Startup jobs failed: {json.dumps(failed, indent=2)}" - matrix = { - (job["packageName"], job["packageVersion"], job["compilerVersion"]) - for job in jobs if job["jobType"] == "matrix" - } - if expected <= matrix and all(job.get("finishedAt") and job["success"] for job in jobs): - break - assert time.monotonic() < deadline, f"Startup jobs did not complete: {json.dumps(jobs, indent=2)}" - time.sleep(1) - print(f"✓ All {len(jobs)} startup jobs succeeded: {json.dumps(jobs)}") + # Verify we get a valid JSON response (the jobs endpoint responds) + result = registry.succeed( + "curl -s http://localhost:${envVars.SERVER_PORT}/api/v1/jobs" + ) + + # Verify the response is valid JSON (starts with '['). + assert result.strip().startswith("["), f"Expected JSON array, got: {result}" # Verify the database was created and migrations ran registry.succeed("test -f ${stateDir}/db/registry.sqlite3") @@ -84,6 +68,9 @@ else ) registry.succeed("test -f ${dhallTypes}/v1/Manifest.dhall") + # Give the job executor a moment to start and potentially fail + time.sleep(2) + # Check that the job executor started successfully and didn't fail logs = registry.succeed("journalctl -u server.service --no-pager") assert "Job executor failed:" not in logs, f"Job executor failed on startup. Logs:\n{logs}" @@ -95,28 +82,8 @@ else nodes.registry = { imports = [ (rootPath + "/nix/registry-server.nix") - { - systemd.services = lib.mapAttrs' ( - name: cfg: - lib.nameValuePair "wiremock-${name}" { - serviceConfig.ExecStart = "${pkgs.wiremock}/bin/wiremock --port ${toString cfg.port} --root-dir ${cfg.rootDir} --disable-banner"; - postStart = '' - until ${pkgs.curl}/bin/curl --fail --silent http://localhost:${toString cfg.port}/__admin > /dev/null; do - sleep 0.5 - done - ''; - } - ) testConfig.wiremockConfigs; - } ]; - # The S3 SDK uses virtual-hosted bucket URLs, as in the integration test. - networking.hosts."127.0.0.1" = [ "purescript-registry.localhost" ]; - systemd.services.server = { - requires = mockUnits; - after = mockUnits; - }; - # Apply the git mock overlay on top of the standard overlays nixpkgs.overlays = overlays ++ [ testConfig.testOverlay ]; @@ -139,6 +106,17 @@ else mkdir -p ${stateDir} echo 'DHALL_TYPES=/defunct/types' > ${stateDir}/.env ${testConfig.setupGitFixtures}/bin/setup-git-fixtures ${repoFixturesDir} + + # Smoke tests cover deployment, not compiler rollouts. Record the test + # compilers in this copy of Prelude without changing integration fixtures. + compilers=$(${(pkgs.extend testConfig.testOverlay).registry-purs-versions}/bin/purs-versions) + prelude=${repoFixturesDir}/purescript/registry/metadata/prelude.json + ${pkgs.jq}/bin/jq --arg compilers "$compilers" \ + '.published[].compilers = ($compilers | split(" "))' "$prelude" > "$prelude.tmp" + mv "$prelude.tmp" "$prelude" + ${pkgs.git}/bin/git -C ${repoFixturesDir}/purescript/registry \ + -c user.name=pacchettibotti -c user.email=pacchettibotti@purescript.org \ + commit -am "Record test compilers for smoke test" ''; };