package httpapi import ( "encoding/json" "net/http" "net/http/httptest" "testing" "time" "mfd-monitor-agent/internal/status" ) const testToken = "test-token" // withToken 为请求 URL 附加鉴权查询参数。 func withToken(path string) string { return path + "?token=" + testToken } // TestStatusReturnsCachedSnapshot 验证 /status 读取提供者缓存。 func TestStatusReturnsCachedSnapshot(t *testing.T) { provider := StaticProvider{Snapshot: status.HostStatus{ Agent: status.AgentInfo{Version: "test", SnapshotAt: time.Now(), SnapshotStatus: "ok"}, Host: status.HostInfo{Hostname: "host-a"}, }, OK: true} server := New(provider, testToken) req := httptest.NewRequest(http.MethodGet, withToken("/status"), nil) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status code = %d", rec.Code) } var got status.HostStatus if err := json.NewDecoder(rec.Body).Decode(&got); err != nil { t.Fatal(err) } if got.Host.Hostname != "host-a" { t.Fatalf("hostname = %q", got.Host.Hostname) } } // TestHealthReportsSnapshotMetadata 验证 /health 返回快照元数据。 func TestHealthReportsSnapshotMetadata(t *testing.T) { provider := StaticProvider{Snapshot: status.HostStatus{ Agent: status.AgentInfo{Version: "test", SnapshotAt: time.Unix(10, 0), SnapshotStatus: "partial"}, }, OK: true} server := New(provider, testToken) req := httptest.NewRequest(http.MethodGet, withToken("/health"), nil) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) if rec.Code != http.StatusOK { t.Fatalf("status code = %d", rec.Code) } var got map[string]any if err := json.NewDecoder(rec.Body).Decode(&got); err != nil { t.Fatal(err) } if got["snapshot_status"] != "partial" { t.Fatalf("health = %+v", got) } } // TestStatusReturnsServiceUnavailableBeforeSnapshot 验证 /status 不会在请求时实时采集。 func TestStatusReturnsServiceUnavailableBeforeSnapshot(t *testing.T) { server := New(StaticProvider{OK: false}, testToken) req := httptest.NewRequest(http.MethodGet, withToken("/status"), nil) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) if rec.Code != http.StatusServiceUnavailable { t.Fatalf("status code = %d", rec.Code) } } // TestHealthReturnsStartingBeforeSnapshot 验证 /health 在启动阶段暴露 starting 状态。 func TestHealthReturnsStartingBeforeSnapshot(t *testing.T) { server := New(StaticProvider{OK: false}, testToken) req := httptest.NewRequest(http.MethodGet, withToken("/health"), nil) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) if rec.Code != http.StatusServiceUnavailable { t.Fatalf("status code = %d", rec.Code) } var got map[string]string if err := json.NewDecoder(rec.Body).Decode(&got); err != nil { t.Fatal(err) } if got["status"] != "starting" { t.Fatalf("status = %q", got["status"]) } } // TestStatusRejectsNonGET 验证 /status 仅接受 GET 请求。 func TestStatusRejectsNonGET(t *testing.T) { server := New(StaticProvider{OK: true}, testToken) req := httptest.NewRequest(http.MethodPost, withToken("/status"), nil) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) if rec.Code != http.StatusMethodNotAllowed { t.Fatalf("status code = %d", rec.Code) } } // TestHealthRejectsNonGET 验证 /health 仅接受 GET 请求。 func TestHealthRejectsNonGET(t *testing.T) { server := New(StaticProvider{OK: true}, testToken) req := httptest.NewRequest(http.MethodPost, withToken("/health"), nil) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) if rec.Code != http.StatusMethodNotAllowed { t.Fatalf("status code = %d", rec.Code) } } // TestMissingTokenReturnsUnauthorized 验证缺少 token 时返回 401。 func TestMissingTokenReturnsUnauthorized(t *testing.T) { server := New(StaticProvider{OK: true}, testToken) req := httptest.NewRequest(http.MethodGet, "/status", nil) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) if rec.Code != http.StatusUnauthorized { t.Fatalf("status code = %d", rec.Code) } } // TestWrongTokenReturnsUnauthorized 验证错误 token 时返回 401。 func TestWrongTokenReturnsUnauthorized(t *testing.T) { server := New(StaticProvider{OK: true}, testToken) req := httptest.NewRequest(http.MethodGet, "/status?token=wrong", nil) rec := httptest.NewRecorder() server.ServeHTTP(rec, req) if rec.Code != http.StatusUnauthorized { t.Fatalf("status code = %d", rec.Code) } }