package aw import ( "context" "encoding/json" "io" "net/http" "net/http/httptest" "testing" "time" ) func TestEnsureBucketPostsCreate(t *testing.T) { var gotPath string var gotBody map[string]string srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotPath = r.URL.Path if r.Method != http.MethodPost { t.Errorf("method = %q, want POST", r.Method) } b, _ := io.ReadAll(r.Body) _ = json.Unmarshal(b, &gotBody) w.WriteHeader(http.StatusOK) })) defer srv.Close() c := New(srv.URL) if err := c.EnsureBucket(context.Background(), "keel.events", "keel.event", "keel"); err != nil { t.Fatalf("EnsureBucket: %v", err) } if gotPath != "/api/0/buckets/keel.events" { t.Fatalf("path = %q", gotPath) } if gotBody["type"] != "keel.event" || gotBody["client"] != "keel" { t.Fatalf("body = %+v", gotBody) } } func TestEnsureBucketTreatsExistsAsOK(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotModified) // AW returns 304 when the bucket exists })) defer srv.Close() if err := New(srv.URL).EnsureBucket(context.Background(), "keel.events", "keel.event", "keel"); err != nil { t.Fatalf("existing bucket should be OK, got %v", err) } } func TestEnsureBucketErrorsOnServerError(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) })) defer srv.Close() if err := New(srv.URL).EnsureBucket(context.Background(), "keel.events", "keel.event", "keel"); err == nil { t.Fatal("expected error on 500") } } func TestInsertPostsEventArray(t *testing.T) { var gotPath string var gotEvents []map[string]any srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { gotPath = r.URL.Path if r.Method != http.MethodPost { t.Errorf("method = %q, want POST", r.Method) } b, _ := io.ReadAll(r.Body) _ = json.Unmarshal(b, &gotEvents) w.WriteHeader(http.StatusOK) })) defer srv.Close() c := New(srv.URL) ev := Event{Timestamp: time.Unix(1000, 0).UTC(), Data: map[string]any{"_kind": "proposal_made"}} if err := c.Insert(context.Background(), "keel.events", ev); err != nil { t.Fatalf("Insert: %v", err) } if gotPath != "/api/0/buckets/keel.events/events" { t.Fatalf("path = %q", gotPath) } if len(gotEvents) != 1 || gotEvents[0]["data"].(map[string]any)["_kind"] != "proposal_made" { t.Fatalf("events = %+v", gotEvents) } } func TestRecentDecodesNewestFirst(t *testing.T) { srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { t.Errorf("method = %q, want GET", r.Method) } if got := r.URL.Query().Get("limit"); got != "5" { t.Errorf("limit = %q, want 5", got) } _, _ = io.WriteString(w, `[ {"id":2,"timestamp":"2026-06-05T10:00:00+00:00","duration":0,"data":{"_kind":"proposal_made"}}, {"id":1,"timestamp":"2026-06-04T10:00:00+00:00","duration":0,"data":{"_kind":"action_taken"}} ]`) })) defer srv.Close() got, err := New(srv.URL).Recent(context.Background(), "keel.events", 5) if err != nil { t.Fatalf("Recent: %v", err) } if len(got) != 2 || got[0].Data["_kind"] != "proposal_made" { t.Fatalf("got = %+v", got) } }