package grpcserver import ( "testing" pbv1 "git3.techno-world.net/lrosales/broad-announce/gen/go/broadannounce/v1" "git3.techno-world.net/lrosales/broad-announce/internal/pipeline" "google.golang.org/grpc/metadata" ) func TestAuthenticate(t *testing.T) { sources := map[string]pipeline.SourceConfig{ "acme-001:prom-prod": { CompanyID: "acme-001", SourceID: "prom-prod", HMACSecret: []byte("s3cret"), RateLimitPerSec: 1000, }, } tests := []struct { name string apiKey string wantErr bool wantSrcID string }{ {name: "valid key", apiKey: "acme-001:prom-prod:s3cret", wantErr: false, wantSrcID: "prom-prod"}, {name: "wrong secret", apiKey: "acme-001:prom-prod:wrong", wantErr: true}, {name: "unknown source", apiKey: "acme-001:unknown:s3cret", wantErr: true}, {name: "malformed key", apiKey: "acme-001", wantErr: true}, {name: "empty key", apiKey: "", wantErr: true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := metadata.NewIncomingContext(t.Context(), metadata.MD{ "authorization": []string{"Bearer " + tt.apiKey}, }) src, err := authenticate(ctx, sources) if tt.wantErr { if err == nil { t.Errorf("authenticate() = %v, want error", src) } return } if err != nil { t.Errorf("authenticate() error = %v, want nil", err) return } if src.SourceID != tt.wantSrcID { t.Errorf("authenticate() sourceID = %v, want %v", src.SourceID, tt.wantSrcID) } }) } } func TestErrorCode(t *testing.T) { tests := []struct { reason string want pbv1.Error_Code }{ {"unknown_source", pbv1.Error_UNAUTHENTICATED}, {"bad_signature", pbv1.Error_UNAUTHENTICATED}, {"rate_limited_source", pbv1.Error_RATE_LIMITED}, {"rate_limited_company", pbv1.Error_RATE_LIMITED}, {"invalid", pbv1.Error_INVALID}, {"invalid_json", pbv1.Error_INVALID}, {"quarantined", pbv1.Error_INVALID}, {"circuit_open", pbv1.Error_INTERNAL}, {"broker_unavailable", pbv1.Error_INTERNAL}, {"marshal_failed", pbv1.Error_INTERNAL}, {"unknown_foo", pbv1.Error_UNKNOWN}, } for _, tt := range tests { t.Run(tt.reason, func(t *testing.T) { if got := errorCode(tt.reason); got != tt.want { t.Errorf("errorCode(%q) = %v, want %v", tt.reason, got, tt.want) } }) } } func TestParseRetryAfter(t *testing.T) { tests := []struct { input string want int ok bool }{ {"123", 123, true}, {"0", 0, true}, {"5s", 5, true}, {"", 0, false}, {"abc", 0, false}, } for _, tt := range tests { t.Run(tt.input, func(t *testing.T) { n, ok := parseRetryAfter(tt.input) if n != tt.want || ok != tt.ok { t.Errorf("parseRetryAfter(%q) = (%d, %v), want (%d, %v)", tt.input, n, ok, tt.want, tt.ok) } }) } } func TestAlertToJSON(t *testing.T) { alert := &pbv1.Alert{ CompanyId: "acme-001", SourceId: "prom-prod", Severity: "critical", Category: "monitoring", Title: "CPU spike", Body: "CPU usage above 90%", DedupeKey: "cpu-spike-001", ClientTsMs: 1712000000000, Data: map[string]string{"host": "prod-01", "value": "95"}, } body, err := alertToJSON(alert) if err != nil { t.Fatalf("alertToJSON() error = %v", err) } bodyStr := string(body) for _, want := range []string{ `"company_id":"acme-001"`, `"source_id":"prom-prod"`, `"severity":"critical"`, `"category":"monitoring"`, `"title":"CPU spike"`, `"dedupe_key":"cpu-spike-001"`, `"client_ts_ms":1712000000000`, } { if !contains(bodyStr, want) { t.Errorf("alertToJSON() body missing %q:\n%s", want, body) } } } func contains(s, substr string) bool { for i := 0; i <= len(s)-len(substr); i++ { if s[i:i+len(substr)] == substr { return true } } return false } func TestServerImplementsIngestServer(t *testing.T) { var _ pbv1.IngestServer = (*Server)(nil) }