|
8 | 8 | "net/http" |
9 | 9 | "net/http/httptest" |
10 | 10 | "testing" |
| 11 | + "time" |
11 | 12 |
|
12 | 13 | "github.com/google/uuid" |
13 | 14 | "github.com/stretchr/testify/assert" |
@@ -83,6 +84,14 @@ func (m *MockStore) GetAllProfiles() ([]provider.Profile, error) { |
83 | 84 | return args.Get(0).([]provider.Profile), args.Error(1) |
84 | 85 | } |
85 | 86 |
|
| 87 | +func (m *MockStore) GetAllHealthStatuses() ([]provider.ProviderHealthSummary, error) { |
| 88 | + args := m.Called() |
| 89 | + if args.Get(0) == nil { |
| 90 | + return nil, args.Error(1) |
| 91 | + } |
| 92 | + return args.Get(0).([]provider.ProviderHealthSummary), args.Error(1) |
| 93 | +} |
| 94 | + |
86 | 95 | func (m *MockStore) GetMetadata() (map[string]map[string]interface{}, error) { |
87 | 96 | args := m.Called() |
88 | 97 | if args.Get(0) == nil { |
@@ -278,3 +287,74 @@ func TestPatchProvider_AuditRedactsSecrets(t *testing.T) { |
278 | 287 | return true |
279 | 288 | }), mock.AnythingOfType("*http.Request")) |
280 | 289 | } |
| 290 | + |
| 291 | +func TestHealth_Success(t *testing.T) { |
| 292 | + mockStore := new(MockStore) |
| 293 | + handler := NewProvidersHandler(mockStore, nil) |
| 294 | + |
| 295 | + now := time.Now() |
| 296 | + msg := "token_url returned 503" |
| 297 | + summaries := []provider.ProviderHealthSummary{ |
| 298 | + { |
| 299 | + ID: uuid.New(), |
| 300 | + Name: "google", |
| 301 | + HealthStatus: "healthy", |
| 302 | + LastHealthCheckAt: &now, |
| 303 | + HealthMessage: nil, |
| 304 | + }, |
| 305 | + { |
| 306 | + ID: uuid.New(), |
| 307 | + Name: "stripe", |
| 308 | + HealthStatus: "unhealthy", |
| 309 | + LastHealthCheckAt: &now, |
| 310 | + HealthMessage: &msg, |
| 311 | + }, |
| 312 | + } |
| 313 | + |
| 314 | + mockStore.On("GetAllHealthStatuses").Return(summaries, nil).Once() |
| 315 | + |
| 316 | + req := httptest.NewRequest("GET", "/providers/health", nil) |
| 317 | + rr := httptest.NewRecorder() |
| 318 | + |
| 319 | + handler.Health(rr, req) |
| 320 | + |
| 321 | + assert.Equal(t, http.StatusOK, rr.Code) |
| 322 | + assert.Contains(t, rr.Body.String(), `"health_status":"healthy"`) |
| 323 | + assert.Contains(t, rr.Body.String(), `"health_status":"unhealthy"`) |
| 324 | + assert.Contains(t, rr.Body.String(), `"health_message":"token_url returned 503"`) |
| 325 | + assert.Contains(t, rr.Body.String(), "google") |
| 326 | + assert.Contains(t, rr.Body.String(), "stripe") |
| 327 | + mockStore.AssertExpectations(t) |
| 328 | +} |
| 329 | + |
| 330 | +func TestHealth_EmptyList(t *testing.T) { |
| 331 | + mockStore := new(MockStore) |
| 332 | + handler := NewProvidersHandler(mockStore, nil) |
| 333 | + |
| 334 | + mockStore.On("GetAllHealthStatuses").Return([]provider.ProviderHealthSummary{}, nil).Once() |
| 335 | + |
| 336 | + req := httptest.NewRequest("GET", "/providers/health", nil) |
| 337 | + rr := httptest.NewRecorder() |
| 338 | + |
| 339 | + handler.Health(rr, req) |
| 340 | + |
| 341 | + assert.Equal(t, http.StatusOK, rr.Code) |
| 342 | + assert.Equal(t, "[]", rr.Body.String()) |
| 343 | + mockStore.AssertExpectations(t) |
| 344 | +} |
| 345 | + |
| 346 | +func TestHealth_StoreError(t *testing.T) { |
| 347 | + mockStore := new(MockStore) |
| 348 | + handler := NewProvidersHandler(mockStore, nil) |
| 349 | + |
| 350 | + mockStore.On("GetAllHealthStatuses").Return(nil, errors.New("connection refused")).Once() |
| 351 | + |
| 352 | + req := httptest.NewRequest("GET", "/providers/health", nil) |
| 353 | + rr := httptest.NewRecorder() |
| 354 | + |
| 355 | + handler.Health(rr, req) |
| 356 | + |
| 357 | + assert.Equal(t, http.StatusInternalServerError, rr.Code) |
| 358 | + assert.Contains(t, rr.Body.String(), "health_failed") |
| 359 | + mockStore.AssertExpectations(t) |
| 360 | +} |
0 commit comments