nix: simplify tests
Signed-off-by: NotAShelf <raf@notashelf.dev> Change-Id: I02126573ee9573fd7a1e5a12e42dd02d6a6a6964
This commit is contained in:
parent
e7425e0abf
commit
d541b7ebbf
4 changed files with 85 additions and 82 deletions
|
|
@ -268,6 +268,14 @@ async fn evaluate_jobset(
|
||||||
evaluation jobset={} commit={}",
|
evaluation jobset={} commit={}",
|
||||||
build_count, jobset.name, commit_hash
|
build_count, jobset.name, commit_hash
|
||||||
);
|
);
|
||||||
|
if let Err(e) =
|
||||||
|
repo::jobsets::update_last_checked(pool, jobset.id).await
|
||||||
|
{
|
||||||
|
tracing::warn!(
|
||||||
|
jobset = %jobset.name,
|
||||||
|
"Failed to update last_checked_at: {e}"
|
||||||
|
);
|
||||||
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
info!(
|
info!(
|
||||||
|
|
|
||||||
|
|
@ -223,7 +223,7 @@ development.
|
||||||
| `cache` | `secret_key_file` | none | Signing key for binary cache |
|
| `cache` | `secret_key_file` | none | Signing key for binary cache |
|
||||||
| `signing` | `enabled` | `false` | Sign build outputs |
|
| `signing` | `enabled` | `false` | Sign build outputs |
|
||||||
| `signing` | `key_file` | none | Signing key file path |
|
| `signing` | `key_file` | none | Signing key file path |
|
||||||
| `notifications` | `run_command` | none | Command to run on build completion |
|
| `notifications` | `webhook_url` | none | HTTP endpoint to POST build status JSON |
|
||||||
| `notifications` | `github_token` | none | GitHub token for commit status updates |
|
| `notifications` | `github_token` | none | GitHub token for commit status updates |
|
||||||
| `notifications` | `gitea_url` | none | Gitea/Forgejo instance URL |
|
| `notifications` | `gitea_url` | none | Gitea/Forgejo instance URL |
|
||||||
| `notifications` | `gitea_token` | none | Gitea/Forgejo API token |
|
| `notifications` | `gitea_token` | none | Gitea/Forgejo API token |
|
||||||
|
|
|
||||||
|
|
@ -238,7 +238,7 @@
|
||||||
options = {
|
options = {
|
||||||
notificationType = mkOption {
|
notificationType = mkOption {
|
||||||
type = str;
|
type = str;
|
||||||
description = "Notification type: github_status, email, gitlab_status, gitea_status, run_command.";
|
description = "Notification type: github_status, email, gitlab_status, gitea_status, webhook.";
|
||||||
};
|
};
|
||||||
config = mkOption {
|
config = mkOption {
|
||||||
type = settingsType;
|
type = settingsType;
|
||||||
|
|
|
||||||
|
|
@ -293,17 +293,19 @@ pkgs.testers.nixosTest {
|
||||||
f"{ro_header}"
|
f"{ro_header}"
|
||||||
).strip()
|
).strip()
|
||||||
assert code == "403", f"Expected 403 for read-only input delete, got {code}"
|
assert code == "403", f"Expected 403 for read-only input delete, got {code}"
|
||||||
|
# Clean up: admin deletes the temp input so it doesn't affect future
|
||||||
|
# inputs_hash computations and evaluator cache lookups
|
||||||
|
machine.succeed(
|
||||||
|
"curl -sf -o /dev/null "
|
||||||
|
f"-X DELETE http://127.0.0.1:3000/api/v1/projects/{e2e_project_id}/jobsets/{e2e_jobset_id}/inputs/{tmp_input_id} "
|
||||||
|
f"{auth_header}"
|
||||||
|
)
|
||||||
|
|
||||||
# Notifications are dispatched after builds complete (already tested above).
|
with subtest("Build status is succeeded"):
|
||||||
# Verify run_command notifications work:
|
|
||||||
with subtest("Notification run_command is invoked on build completion"):
|
|
||||||
# This tests that the notification system dispatches properly.
|
|
||||||
# The actual run_command config is not set in this VM, so we just verify
|
|
||||||
# the build status was updated correctly after notification dispatch.
|
|
||||||
result = machine.succeed(
|
result = machine.succeed(
|
||||||
f"curl -sf http://127.0.0.1:3000/api/v1/builds/{e2e_build_id} | jq -r .status"
|
f"curl -sf http://127.0.0.1:3000/api/v1/builds/{e2e_build_id} | jq -r .status"
|
||||||
).strip()
|
).strip()
|
||||||
assert result == "succeeded", f"Expected succeeded after notification, got {result}"
|
assert result == "succeeded", f"Expected succeeded, got {result}"
|
||||||
|
|
||||||
with subtest("Channel auto-promotion after all builds complete"):
|
with subtest("Channel auto-promotion after all builds complete"):
|
||||||
# Create a channel tracking the E2E jobset
|
# Create a channel tracking the E2E jobset
|
||||||
|
|
@ -388,34 +390,43 @@ pkgs.testers.nixosTest {
|
||||||
timeout=10
|
timeout=10
|
||||||
)
|
)
|
||||||
|
|
||||||
with subtest("Notification run_command invoked on build completion"):
|
with subtest("Webhook notification fires on build completion"):
|
||||||
# Write a notification script
|
# Start a minimal HTTP server on the VM to receive the webhook POST.
|
||||||
machine.succeed("mkdir -p /var/lib/fc")
|
# Writes the request body to /tmp/webhook.json so we can inspect it.
|
||||||
machine.succeed("""
|
machine.succeed(
|
||||||
cat > /var/lib/fc/notify.sh << 'SCRIPT'
|
"cat > /tmp/webhook-server.py << 'PYEOF'\n"
|
||||||
#!/bin/sh
|
"import http.server, json\n"
|
||||||
echo "BUILD_STATUS=$FC_BUILD_STATUS" >> /var/lib/fc/notify-output
|
"class H(http.server.BaseHTTPRequestHandler):\n"
|
||||||
echo "BUILD_ID=$FC_BUILD_ID" >> /var/lib/fc/notify-output
|
" def do_POST(self):\n"
|
||||||
echo "BUILD_JOB=$FC_BUILD_JOB" >> /var/lib/fc/notify-output
|
" n = int(self.headers.get('Content-Length', 0))\n"
|
||||||
SCRIPT
|
" body = self.rfile.read(n)\n"
|
||||||
""")
|
" open('/tmp/webhook.json', 'wb').write(body)\n"
|
||||||
machine.succeed("chmod +x /var/lib/fc/notify.sh")
|
" self.send_response(200)\n"
|
||||||
machine.succeed("chown -R fc:fc /var/lib/fc")
|
" self.end_headers()\n"
|
||||||
|
" def log_message(self, *a): pass\n"
|
||||||
|
"http.server.HTTPServer(('127.0.0.1', 9998), H).serve_forever()\n"
|
||||||
|
"PYEOF\n"
|
||||||
|
)
|
||||||
|
machine.succeed("python3 /tmp/webhook-server.py &")
|
||||||
|
machine.wait_until_succeeds(
|
||||||
|
"curl -sf -X POST -H 'Content-Length: 2' -d '{}' http://127.0.0.1:9998/",
|
||||||
|
timeout=10
|
||||||
|
)
|
||||||
|
machine.succeed("rm -f /tmp/webhook.json")
|
||||||
|
|
||||||
# Enable notifications via systemd drop-in override (adds env var directly to service unit)
|
# Configure queue-runner to send webhook notifications
|
||||||
machine.succeed("mkdir -p /run/systemd/system/fc-queue-runner.service.d")
|
machine.succeed("mkdir -p /run/systemd/system/fc-queue-runner.service.d")
|
||||||
machine.succeed("""
|
machine.succeed(
|
||||||
cat > /run/systemd/system/fc-queue-runner.service.d/notify.conf << 'EOF'
|
"cat > /run/systemd/system/fc-queue-runner.service.d/webhook.conf << 'EOF'\n"
|
||||||
[Service]
|
"[Service]\n"
|
||||||
Environment=FC_NOTIFICATIONS__RUN_COMMAND=/var/lib/fc/notify.sh
|
"Environment=FC_NOTIFICATIONS__WEBHOOK_URL=http://127.0.0.1:9998/notify\n"
|
||||||
EOF
|
"EOF\n"
|
||||||
""")
|
)
|
||||||
machine.succeed("systemctl daemon-reload")
|
machine.succeed("systemctl daemon-reload")
|
||||||
machine.succeed("systemctl restart fc-queue-runner")
|
machine.succeed("systemctl restart fc-queue-runner")
|
||||||
machine.wait_for_unit("fc-queue-runner.service", timeout=30)
|
machine.wait_for_unit("fc-queue-runner.service", timeout=30)
|
||||||
|
|
||||||
# Create a new simple build to trigger notification
|
# Push a new commit to trigger a fresh evaluation and build
|
||||||
# Push a trivial change to trigger a new evaluation
|
|
||||||
machine.succeed(
|
machine.succeed(
|
||||||
"cd /tmp/test-flake-work && \\\n"
|
"cd /tmp/test-flake-work && \\\n"
|
||||||
"cat > flake.nix << 'FLAKE'\n"
|
"cat > flake.nix << 'FLAKE'\n"
|
||||||
|
|
@ -432,31 +443,16 @@ pkgs.testers.nixosTest {
|
||||||
"}\n"
|
"}\n"
|
||||||
"FLAKE\n"
|
"FLAKE\n"
|
||||||
)
|
)
|
||||||
machine.succeed("cd /tmp/test-flake-work && git add -A && git commit -m 'trigger notification test'")
|
machine.succeed("cd /tmp/test-flake-work && git add -A && git commit -m 'trigger webhook notification test'")
|
||||||
machine.succeed("cd /tmp/test-flake-work && git push origin HEAD:refs/heads/master")
|
machine.succeed("cd /tmp/test-flake-work && git push origin HEAD:refs/heads/master")
|
||||||
|
|
||||||
# Wait for the notify-test build to succeed
|
# Wait for the webhook to arrive (the build must complete first)
|
||||||
machine.wait_until_succeeds(
|
machine.wait_until_succeeds("test -e /tmp/webhook.json", timeout=120)
|
||||||
"curl -sf 'http://127.0.0.1:3000/api/v1/builds?job_name=notify-test' "
|
payload = json.loads(machine.succeed("cat /tmp/webhook.json"))
|
||||||
"| jq -e '.items[] | select(.status==\"succeeded\")'",
|
assert payload["build_status"] == "success", \
|
||||||
timeout=120
|
f"Expected build_status=success in webhook payload, got: {payload}"
|
||||||
)
|
assert "build_id" in payload, f"Missing build_id in webhook payload: {payload}"
|
||||||
|
assert "build_job" in payload, f"Missing build_job in webhook payload: {payload}"
|
||||||
# Get the build ID
|
|
||||||
notify_build_id = machine.succeed(
|
|
||||||
"curl -sf 'http://127.0.0.1:3000/api/v1/builds?job_name=notify-test' "
|
|
||||||
"| jq -r '.items[] | select(.status==\"succeeded\") | .id' | head -1"
|
|
||||||
).strip()
|
|
||||||
|
|
||||||
# Wait a bit for notification to dispatch
|
|
||||||
time.sleep(5)
|
|
||||||
|
|
||||||
# Verify the notification script was executed
|
|
||||||
machine.wait_for_file("/var/lib/fc/notify-output")
|
|
||||||
output = machine.succeed("cat /var/lib/fc/notify-output")
|
|
||||||
assert "BUILD_STATUS=success" in output, \
|
|
||||||
f"Expected BUILD_STATUS=success in notification output, got: {output}"
|
|
||||||
assert notify_build_id in output, f"Expected build ID {notify_build_id} in output, got: {output}"
|
|
||||||
|
|
||||||
with subtest("Generate signing key and configure signing"):
|
with subtest("Generate signing key and configure signing"):
|
||||||
# Generate a Nix signing key
|
# Generate a Nix signing key
|
||||||
|
|
@ -467,13 +463,13 @@ pkgs.testers.nixosTest {
|
||||||
|
|
||||||
# Enable signing via systemd drop-in override
|
# Enable signing via systemd drop-in override
|
||||||
machine.succeed("mkdir -p /run/systemd/system/fc-queue-runner.service.d")
|
machine.succeed("mkdir -p /run/systemd/system/fc-queue-runner.service.d")
|
||||||
machine.succeed("""
|
machine.succeed(
|
||||||
cat > /run/systemd/system/fc-queue-runner.service.d/signing.conf << 'EOF'
|
"cat > /run/systemd/system/fc-queue-runner.service.d/signing.conf << 'EOF'\n"
|
||||||
[Service]
|
"[Service]\n"
|
||||||
Environment=FC_SIGNING__ENABLED=true
|
"Environment=FC_SIGNING__ENABLED=true\n"
|
||||||
Environment=FC_SIGNING__KEY_FILE=/var/lib/fc/keys/signing-key
|
"Environment=FC_SIGNING__KEY_FILE=/var/lib/fc/keys/signing-key\n"
|
||||||
EOF
|
"EOF\n"
|
||||||
""")
|
)
|
||||||
machine.succeed("systemctl daemon-reload")
|
machine.succeed("systemctl daemon-reload")
|
||||||
machine.succeed("systemctl restart fc-queue-runner")
|
machine.succeed("systemctl restart fc-queue-runner")
|
||||||
machine.wait_for_unit("fc-queue-runner.service", timeout=30)
|
machine.wait_for_unit("fc-queue-runner.service", timeout=30)
|
||||||
|
|
@ -530,15 +526,15 @@ pkgs.testers.nixosTest {
|
||||||
with subtest("GC roots are created for build products"):
|
with subtest("GC roots are created for build products"):
|
||||||
# Enable GC via systemd drop-in override
|
# Enable GC via systemd drop-in override
|
||||||
machine.succeed("mkdir -p /run/systemd/system/fc-queue-runner.service.d")
|
machine.succeed("mkdir -p /run/systemd/system/fc-queue-runner.service.d")
|
||||||
machine.succeed("""
|
machine.succeed(
|
||||||
cat > /run/systemd/system/fc-queue-runner.service.d/gc.conf << 'EOF'
|
"cat > /run/systemd/system/fc-queue-runner.service.d/gc.conf << 'EOF'\n"
|
||||||
[Service]
|
"[Service]\n"
|
||||||
Environment=FC_GC__ENABLED=true
|
"Environment=FC_GC__ENABLED=true\n"
|
||||||
Environment=FC_GC__GC_ROOTS_DIR=/nix/var/nix/gcroots/per-user/fc
|
"Environment=FC_GC__GC_ROOTS_DIR=/nix/var/nix/gcroots/per-user/fc\n"
|
||||||
Environment=FC_GC__MAX_AGE_DAYS=30
|
"Environment=FC_GC__MAX_AGE_DAYS=30\n"
|
||||||
Environment=FC_GC__CLEANUP_INTERVAL=3600
|
"Environment=FC_GC__CLEANUP_INTERVAL=3600\n"
|
||||||
EOF
|
"EOF\n"
|
||||||
""")
|
)
|
||||||
machine.succeed("systemctl daemon-reload")
|
machine.succeed("systemctl daemon-reload")
|
||||||
machine.succeed("systemctl restart fc-queue-runner")
|
machine.succeed("systemctl restart fc-queue-runner")
|
||||||
machine.wait_for_unit("fc-queue-runner.service", timeout=30)
|
machine.wait_for_unit("fc-queue-runner.service", timeout=30)
|
||||||
|
|
@ -599,7 +595,6 @@ pkgs.testers.nixosTest {
|
||||||
)
|
)
|
||||||
|
|
||||||
# Wait for a symlink pointing to our build output to appear
|
# Wait for a symlink pointing to our build output to appear
|
||||||
import time
|
|
||||||
found = False
|
found = False
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
if wait_for_gc_root():
|
if wait_for_gc_root():
|
||||||
|
|
@ -612,16 +607,16 @@ pkgs.testers.nixosTest {
|
||||||
|
|
||||||
with subtest("Declarative .fc.toml in repo auto-creates jobset"):
|
with subtest("Declarative .fc.toml in repo auto-creates jobset"):
|
||||||
# Add .fc.toml to the test repo with a new jobset definition
|
# Add .fc.toml to the test repo with a new jobset definition
|
||||||
machine.succeed("""
|
machine.succeed(
|
||||||
cd /tmp/test-flake-work && \
|
"cd /tmp/test-flake-work && "
|
||||||
cat > .fc.toml << 'FCTOML'
|
"cat > .fc.toml << 'FCTOML'\n"
|
||||||
[[jobsets]]
|
"[[jobsets]]\n"
|
||||||
name = "declarative-checks"
|
'name = "declarative-checks"\n'
|
||||||
nix_expression = "checks"
|
'nix_expression = "checks"\n'
|
||||||
flake_mode = true
|
"flake_mode = true\n"
|
||||||
enabled = true
|
"enabled = true\n"
|
||||||
FCTOML
|
"FCTOML\n"
|
||||||
""")
|
)
|
||||||
machine.succeed("cd /tmp/test-flake-work && git add -A && git commit -m 'add declarative config'")
|
machine.succeed("cd /tmp/test-flake-work && git add -A && git commit -m 'add declarative config'")
|
||||||
machine.succeed("cd /tmp/test-flake-work && git push origin HEAD:refs/heads/master")
|
machine.succeed("cd /tmp/test-flake-work && git push origin HEAD:refs/heads/master")
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue