package api import ( "net/http" "net/http/httptest" "strings" "testing" "dana/internal/onec" ) func postEvent(a *API, key, body string) *httptest.ResponseRecorder { req := httptest.NewRequest(http.MethodPost, "/api/v1/onec/events", strings.NewReader(body)) if key != "" { req.Header.Set("X-Api-Key", key) } rec := httptest.NewRecorder() a.onecEvents(rec, req) return rec } func TestOnecEventsAuthAndValidation(t *testing.T) { a := &API{limiter: newRateLimiter(), onec: onec.New("http://127.0.0.1:1", "k", "X-Api-Key")} if rec := postEvent(a, "secret", `{"event":"schedule_changed"}`); rec.Code != http.StatusNotFound { t.Fatalf("вебхук без ключа в настройках должен быть выключен, получили %d", rec.Code) } a.WithOneCWebhook("secret") if rec := postEvent(a, "", `{"event":"schedule_changed"}`); rec.Code != http.StatusUnauthorized { t.Fatalf("без ключа: %d", rec.Code) } if rec := postEvent(a, "wrong", `{"event":"schedule_changed"}`); rec.Code != http.StatusUnauthorized { t.Fatalf("неверный ключ: %d", rec.Code) } if rec := postEvent(a, "secret", `{"event":"nope"}`); rec.Code != http.StatusBadRequest { t.Fatalf("неизвестное событие: %d", rec.Code) } if rec := postEvent(a, "secret", `{"event":"appointment_status","appointment_id":"A-1","status":"weird"}`); rec.Code != http.StatusBadRequest { t.Fatalf("неверный статус: %d", rec.Code) } if rec := postEvent(a, "secret", `{"event":"appointment_status","status":"cancelled"}`); rec.Code != http.StatusBadRequest { t.Fatalf("нет номера записи: %d", rec.Code) } if rec := postEvent(a, "secret", `not json`); rec.Code != http.StatusBadRequest { t.Fatalf("битый JSON: %d", rec.Code) } } func TestOnecEventsBruteForceLimit(t *testing.T) { a := &API{limiter: newRateLimiter(), onec: onec.New("http://127.0.0.1:1", "k", "X-Api-Key")} a.WithOneCWebhook("secret") var last int for i := 0; i < 25; i++ { last = postEvent(a, "guess", `{}`).Code } if last != http.StatusTooManyRequests { t.Fatalf("перебор ключа должен упираться в лимит, получили %d", last) } }