package integration_test import ( "encoding/json" "net/http" "testing" "time" ) func TestRedemptionCodes(t *testing.T) { r, _ := setupAPIPool(t) tok := adminLogin(t, r, "admin", "change-me") _, code := doAdminJSON(t, r, http.MethodPost, "/api/v1/admin/redemption-batches", map[string]any{"label": "t", "plan_code": "month", "quantity": 2}, "") if code != http.StatusUnauthorized { t.Fatalf("expected 401, got %d", code) } start := time.Now() env, code := doAdminJSON(t, r, http.MethodPost, "/api/v1/admin/redemption-batches", map[string]any{"label": "ops-test", "plan_code": "month", "quantity": 3}, tok) if code != 200 { t.Fatalf("create batch http=%d msg=%s", code, env.Message) } var created struct { Batch struct { ID string `json:"id"` } `json:"batch"` Codes []struct { ID string `json:"id"` Code string `json:"code"` Status string `json:"status"` } `json:"codes"` } _ = json.Unmarshal(env.Data, &created) if len(created.Codes) != 3 { t.Fatalf("want 3 codes, got %#v", created.Codes) } raw := created.Codes[0].Code disableID := created.Codes[2].ID _, code = doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/redemption-batches", nil, tok) if code != 200 || time.Since(start) > 500*time.Millisecond { t.Fatalf("list batches http=%d dur=%v", code, time.Since(start)) } _, code = doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/redemption-batches/"+created.Batch.ID+"/codes", nil, tok) if code != 200 { t.Fatalf("list codes %d", code) } key := mustRegister(t, r) _, _, httpCode := doJSONExpect(t, r, http.MethodPost, "/api/v1/membership/redeem", map[string]string{"code": raw}, key, 0) if httpCode != 200 { t.Fatalf("redeem http=%d", httpCode) } _, _, httpCode = doJSONExpect(t, r, http.MethodPost, "/api/v1/membership/redeem", map[string]string{"code": raw}, key, 40000) if httpCode != http.StatusBadRequest { t.Fatalf("expected HTTP 400 re-redeem, got %d", httpCode) } _, code = doAdminJSON(t, r, http.MethodPost, "/api/v1/admin/redemption-codes/"+disableID+"/disable", nil, tok) if code != 200 { t.Fatalf("disable %d", code) } _, _, httpCode = doJSONExpect(t, r, http.MethodPost, "/api/v1/membership/redeem", map[string]string{"code": created.Codes[2].Code}, key, 40000) if httpCode != http.StatusBadRequest { t.Fatalf("expected HTTP 400 disabled, got %d", httpCode) } env, code = doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/audit-logs", nil, tok) if code != 200 { t.Fatalf("audit %d", code) } var audit struct { Items []struct { Action string `json:"action"` } `json:"items"` } _ = json.Unmarshal(env.Data, &audit) found := false for _, it := range audit.Items { if it.Action == "redemption.batch.create" { found = true break } } if !found { t.Fatal("missing redemption.batch.create audit") } if code := deviceGET(t, r, "/api/v1/membership/me", "dev_orphan_"+time.Now().Format("150405"), ""); code != http.StatusUnauthorized { t.Fatalf("expected 401 unregistered membership, got %d", code) } }