package integration_test import ( "encoding/json" "fmt" "net/http" "net/url" "testing" "time" ) func TestUserEntitlements(t *testing.T) { r, _ := setupAPIPool(t) tok := adminLogin(t, r, "admin", "change-me") _, code := doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/users/"+fakeUUID()+"/entitlements", nil, "") if code != http.StatusUnauthorized { t.Fatalf("expected 401, got %d", code) } testBearer = "" phone := fmt.Sprintf("1%010d", time.Now().UnixNano()%10_000_000_000) nick := "ent_" + phone[7:] env, key := doJSON(t, r, http.MethodPost, "/api/v1/auth/register", map[string]any{ "phone": phone, "password": "secret12", "nickname": nick, }, "") sess := decodeData[map[string]any](t, env.Data) testBearer = sess["token"].(string) t.Cleanup(func() { testBearer = "" }) env, key = doJSON(t, r, http.MethodPost, "/api/v1/profiles", map[string]any{ "relation": "self", "birth_date": "1990-01-01", "display_name": "权", }, key) profileID := decodeData[map[string]any](t, env.Data)["id"].(string) env, key = doJSON(t, r, http.MethodPost, "/api/v1/reports/portrait", map[string]any{ "profile_id": profileID, }, key) reportID := decodeData[map[string]any](t, env.Data)["id"].(string) env, key = doJSON(t, r, http.MethodPost, "/api/v1/orders", map[string]any{ "kind": "deep_access", "report_id": reportID, }, key) orderID := decodeData[map[string]any](t, env.Data)["order_id"].(string) _, key = doJSON(t, r, http.MethodPost, "/api/v1/orders/"+orderID+"/pay-mock", nil, key) env, code = doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/users?q="+url.QueryEscape(nick), nil, tok) if code != 200 { t.Fatalf("list users %d", code) } var list struct { Items []struct { ID string `json:"id"` } `json:"items"` } _ = json.Unmarshal(env.Data, &list) userID := list.Items[0].ID start := time.Now() env, code = doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/users/"+userID+"/entitlements", nil, tok) if code != 200 || env.Code != 0 { t.Fatalf("entitlements http=%d msg=%s", code, env.Message) } if time.Since(start) > 500*time.Millisecond { t.Fatalf("too slow %v", time.Since(start)) } var before struct { Flags struct { ViaMem bool `json:"report_detail_via_membership"` Count int `json:"deep_access_count"` } `json:"flags"` Deep []any `json:"deep_accesses"` } _ = json.Unmarshal(env.Data, &before) if before.Flags.Count < 1 || len(before.Deep) < 1 { t.Fatalf("expected deep_access: %#v", before) } if before.Flags.ViaMem { t.Fatal("expected membership inactive before grant") } _, code = doAdminJSON(t, r, http.MethodPost, "/api/v1/admin/users/"+userID+"/membership/grant", map[string]string{"plan": "month"}, tok) if code != 200 { t.Fatalf("grant %d", code) } env, code = doAdminJSON(t, r, http.MethodGet, "/api/v1/admin/users/"+userID+"/entitlements", nil, tok) if code != 200 { t.Fatalf("after grant %d", code) } var after struct { Flags struct { ViaMem bool `json:"report_detail_via_membership"` } `json:"flags"` Membership struct { Active bool `json:"active"` } `json:"membership"` } _ = json.Unmarshal(env.Data, &after) if !after.Flags.ViaMem || !after.Membership.Active { t.Fatalf("expected active membership entitlement: %#v", after) } _ = key }