package handler import ( "context" "net/http" "net/http/httptest" "testing" "time" "github.com/company/ai-ops/internal/domain/model" "github.com/company/ai-ops/internal/service" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) type mockMetricRepo struct{ mock.Mock } func (m *mockMetricRepo) GetRealtime(ctx context.Context) (*model.RealtimeMetrics, error) { args := m.Called(ctx) return args.Get(0).(*model.RealtimeMetrics), args.Error(1) } func (m *mockMetricRepo) Query(ctx context.Context, req model.MetricQueryRequest) ([]model.MetricPoint, error) { args := m.Called(ctx, req) return args.Get(0).([]model.MetricPoint), args.Error(1) } func (m *mockMetricRepo) GetLatest(ctx context.Context, source, name string) (*model.MetricPoint, error) { args := m.Called(ctx, source, name) return args.Get(0).(*model.MetricPoint), args.Error(1) } type mockAlertRepo struct{ mock.Mock } func (m *mockAlertRepo) GetOpenCount(ctx context.Context) (*model.AlertCount, error) { args := m.Called(ctx) return args.Get(0).(*model.AlertCount), args.Error(1) } func (m *mockAlertRepo) ListRules(ctx context.Context) ([]model.AlertRule, error) { args := m.Called(ctx) return args.Get(0).([]model.AlertRule), args.Error(1) } func (m *mockAlertRepo) GetRuleByID(ctx context.Context, id string) (*model.AlertRule, error) { args := m.Called(ctx, id) return args.Get(0).(*model.AlertRule), args.Error(1) } func (m *mockAlertRepo) CreateRule(ctx context.Context, rule *model.AlertRule) error { args := m.Called(ctx, rule) return args.Error(0) } func (m *mockAlertRepo) UpdateRule(ctx context.Context, rule *model.AlertRule) error { args := m.Called(ctx, rule) return args.Error(0) } func (m *mockAlertRepo) DeleteRule(ctx context.Context, id string) error { args := m.Called(ctx, id) return args.Error(0) } func (m *mockAlertRepo) ListEvents(ctx context.Context, status string, page, pageSize int) ([]model.AlertEvent, int, error) { args := m.Called(ctx, status, page, pageSize) return args.Get(0).([]model.AlertEvent), args.Int(1), args.Error(2) } func (m *mockAlertRepo) CreateEvent(ctx context.Context, event *model.AlertEvent) error { args := m.Called(ctx, event) return args.Error(0) } func (m *mockAlertRepo) CreateEventWithAggregation(ctx context.Context, event *model.AlertEvent, window time.Duration, threshold int) (*model.AlertEvent, error) { args := m.Called(ctx, event, window, threshold) return args.Get(0).(*model.AlertEvent), args.Error(1) } func (m *mockAlertRepo) UpdateEventStatus(ctx context.Context, id, status string) error { args := m.Called(ctx, id, status) return args.Error(0) } func (m *mockAlertRepo) EscalateEvent(ctx context.Context, id, newLevel string) error { args := m.Called(ctx, id, newLevel) return args.Error(0) } func TestMetricHandler_GetRealtime(t *testing.T) { mr := new(mockMetricRepo) ar := new(mockAlertRepo) svc := service.NewMetricService(mr, ar) h := NewMetricHandler(svc) expected := &model.RealtimeMetrics{QPS: 100, AvgLatency: 50, P99Latency: 100, ErrorRate: 0.01} mr.On("GetRealtime", mock.Anything).Return(expected, nil) req := httptest.NewRequest("GET", "/api/v1/ai-ops/metrics/realtime", nil) w := httptest.NewRecorder() h.GetRealtime(w, req) assert.Equal(t, http.StatusOK, w.Code) assert.Contains(t, w.Body.String(), `"qps":100`) }