agent-style workers
This commit is contained in:
138
crates/api/tests/agent_tests.rs
Normal file
138
crates/api/tests/agent_tests.rs
Normal file
@@ -0,0 +1,138 @@
|
||||
//! Integration tests for agent binary distribution endpoints
|
||||
//!
|
||||
//! The agent endpoints (`/api/v1/agent/binary` and `/api/v1/agent/info`) are
|
||||
//! intentionally unauthenticated — the agent needs to download its binary
|
||||
//! before it has JWT credentials. An optional `bootstrap_token` can restrict
|
||||
//! access, but that is validated inside the handler, not via RequireAuth
|
||||
//! middleware.
|
||||
//!
|
||||
//! The test configuration (`config.test.yaml`) does NOT include an `agent`
|
||||
//! section, so both endpoints return 503 Service Unavailable. This is the
|
||||
//! correct behaviour: the endpoints are reachable (no 401/404 from middleware)
|
||||
//! but the feature is not configured.
|
||||
|
||||
use axum::http::StatusCode;
|
||||
|
||||
#[allow(dead_code)]
|
||||
mod helpers;
|
||||
use helpers::TestContext;
|
||||
|
||||
// ── /api/v1/agent/info ──────────────────────────────────────────────
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "integration test — requires database"]
|
||||
async fn test_agent_info_not_configured() {
|
||||
let ctx = TestContext::new()
|
||||
.await
|
||||
.expect("Failed to create test context");
|
||||
|
||||
let response = ctx
|
||||
.get("/api/v1/agent/info", None)
|
||||
.await
|
||||
.expect("Failed to make request");
|
||||
|
||||
// Agent config is not set in config.test.yaml, so the handler returns 503.
|
||||
assert_eq!(response.status(), StatusCode::SERVICE_UNAVAILABLE);
|
||||
|
||||
let body: serde_json::Value = response.json().await.expect("Failed to parse JSON");
|
||||
assert_eq!(body["error"], "Not configured");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "integration test — requires database"]
|
||||
async fn test_agent_info_no_auth_required() {
|
||||
// Verify that the endpoint is reachable WITHOUT any JWT token.
|
||||
// If RequireAuth middleware were applied, this would return 401.
|
||||
// Instead we expect 503 (not configured) — proving the endpoint
|
||||
// is publicly accessible.
|
||||
let ctx = TestContext::new()
|
||||
.await
|
||||
.expect("Failed to create test context");
|
||||
|
||||
let response = ctx
|
||||
.get("/api/v1/agent/info", None)
|
||||
.await
|
||||
.expect("Failed to make request");
|
||||
|
||||
// Must NOT be 401 Unauthorized — the endpoint has no auth middleware.
|
||||
assert_ne!(
|
||||
response.status(),
|
||||
StatusCode::UNAUTHORIZED,
|
||||
"agent/info should not require authentication"
|
||||
);
|
||||
// Should be 503 because agent config is absent.
|
||||
assert_eq!(response.status(), StatusCode::SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
// ── /api/v1/agent/binary ────────────────────────────────────────────
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "integration test — requires database"]
|
||||
async fn test_agent_binary_not_configured() {
|
||||
let ctx = TestContext::new()
|
||||
.await
|
||||
.expect("Failed to create test context");
|
||||
|
||||
let response = ctx
|
||||
.get("/api/v1/agent/binary", None)
|
||||
.await
|
||||
.expect("Failed to make request");
|
||||
|
||||
// Agent config is not set in config.test.yaml, so the handler returns 503.
|
||||
assert_eq!(response.status(), StatusCode::SERVICE_UNAVAILABLE);
|
||||
|
||||
let body: serde_json::Value = response.json().await.expect("Failed to parse JSON");
|
||||
assert_eq!(body["error"], "Not configured");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "integration test — requires database"]
|
||||
async fn test_agent_binary_no_auth_required() {
|
||||
// Same reasoning as test_agent_info_no_auth_required: the binary
|
||||
// download endpoint must be publicly accessible (no RequireAuth).
|
||||
// When no bootstrap_token is configured, any caller can reach the
|
||||
// handler. We still get 503 because the agent feature itself is
|
||||
// not configured in the test environment.
|
||||
let ctx = TestContext::new()
|
||||
.await
|
||||
.expect("Failed to create test context");
|
||||
|
||||
let response = ctx
|
||||
.get("/api/v1/agent/binary", None)
|
||||
.await
|
||||
.expect("Failed to make request");
|
||||
|
||||
// Must NOT be 401 Unauthorized — the endpoint has no auth middleware.
|
||||
assert_ne!(
|
||||
response.status(),
|
||||
StatusCode::UNAUTHORIZED,
|
||||
"agent/binary should not require authentication when no bootstrap_token is configured"
|
||||
);
|
||||
// Should be 503 because agent config is absent.
|
||||
assert_eq!(response.status(), StatusCode::SERVICE_UNAVAILABLE);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore = "integration test — requires database"]
|
||||
async fn test_agent_binary_invalid_arch() {
|
||||
// Architecture validation (`validate_arch`) rejects unsupported values
|
||||
// with 400 Bad Request. However, in the handler the execution order is:
|
||||
// 1. validate_token (passes — no bootstrap_token configured)
|
||||
// 2. check agent config (fails with 503 — not configured)
|
||||
// 3. validate_arch (never reached)
|
||||
//
|
||||
// So even with an invalid arch like "mips", we get 503 from the config
|
||||
// check before the arch is ever validated. The arch validation is covered
|
||||
// by unit tests in routes/agent.rs instead.
|
||||
let ctx = TestContext::new()
|
||||
.await
|
||||
.expect("Failed to create test context");
|
||||
|
||||
let response = ctx
|
||||
.get("/api/v1/agent/binary?arch=mips", None)
|
||||
.await
|
||||
.expect("Failed to make request");
|
||||
|
||||
// 503 from the agent-config-not-set check, NOT 400 from arch validation.
|
||||
assert_eq!(response.status(), StatusCode::SERVICE_UNAVAILABLE);
|
||||
}
|
||||
Reference in New Issue
Block a user