618 lines
17 KiB
Go
618 lines
17 KiB
Go
package api
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/mish/dealspace/lib"
|
|
)
|
|
|
|
// testServerSetup creates a test server with all dependencies
|
|
func testServerSetup(t *testing.T) (*httptest.Server, *lib.DB, *lib.Config, func()) {
|
|
t.Helper()
|
|
|
|
tmpFile, err := os.CreateTemp("", "dealspace-org-test-*.db")
|
|
if err != nil {
|
|
t.Fatalf("create temp file: %v", err)
|
|
}
|
|
tmpFile.Close()
|
|
|
|
db, err := lib.OpenDB(tmpFile.Name(), "../migrations/001_initial.sql")
|
|
if err != nil {
|
|
os.Remove(tmpFile.Name())
|
|
t.Fatalf("OpenDB: %v", err)
|
|
}
|
|
|
|
masterKey := make([]byte, 32)
|
|
for i := range masterKey {
|
|
masterKey[i] = byte(i)
|
|
}
|
|
jwtSecret := []byte("test-jwt-secret-32-bytes-long!!")
|
|
|
|
cfg := &lib.Config{
|
|
MasterKey: masterKey,
|
|
JWTSecret: jwtSecret,
|
|
Env: "development",
|
|
BackdoorCode: "220402",
|
|
}
|
|
|
|
tmpDir, err := os.MkdirTemp("", "dealspace-store-org-test")
|
|
if err != nil {
|
|
db.Close()
|
|
os.Remove(tmpFile.Name())
|
|
t.Fatal(err)
|
|
}
|
|
store, _ := lib.NewLocalStore(tmpDir)
|
|
|
|
router := NewRouter(db, cfg, store, nil, nil)
|
|
server := httptest.NewServer(router)
|
|
|
|
cleanup := func() {
|
|
server.Close()
|
|
db.Close()
|
|
os.Remove(tmpFile.Name())
|
|
os.RemoveAll(tmpDir)
|
|
}
|
|
|
|
return server, db, cfg, cleanup
|
|
}
|
|
|
|
// createUserWithRole creates a user and grants them a role on a project
|
|
func createUserWithRole(t *testing.T, db *lib.DB, email, role, projectID string) string {
|
|
t.Helper()
|
|
now := time.Now().UnixMilli()
|
|
userID := uuid.New().String()
|
|
user := &lib.User{
|
|
UserID: userID,
|
|
Email: email,
|
|
Name: "Test User",
|
|
Password: "",
|
|
Active: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
if err := lib.UserCreate(db, user); err != nil {
|
|
t.Fatalf("UserCreate: %v", err)
|
|
}
|
|
|
|
if role != "" && projectID != "" {
|
|
ops := "r"
|
|
switch role {
|
|
case lib.RoleSuperAdmin, lib.RoleIBAdmin:
|
|
ops = "rwdm"
|
|
case lib.RoleIBMember:
|
|
ops = "rwdm"
|
|
case lib.RoleSellerAdmin, lib.RoleSellerMember:
|
|
ops = "rwd"
|
|
}
|
|
|
|
lib.AccessGrant(db, &lib.Access{
|
|
ID: uuid.New().String(),
|
|
ProjectID: projectID,
|
|
UserID: userID,
|
|
Role: role,
|
|
Ops: ops,
|
|
CanGrant: role == lib.RoleIBAdmin || role == lib.RoleSuperAdmin,
|
|
GrantedBy: "system",
|
|
GrantedAt: now,
|
|
})
|
|
}
|
|
|
|
return userID
|
|
}
|
|
|
|
// createSuperAdmin creates a super admin user
|
|
func createSuperAdmin(t *testing.T, db *lib.DB, email string) string {
|
|
t.Helper()
|
|
now := time.Now().UnixMilli()
|
|
userID := uuid.New().String()
|
|
user := &lib.User{
|
|
UserID: userID,
|
|
Email: email,
|
|
Name: "Super Admin",
|
|
Password: "",
|
|
Active: true,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
}
|
|
if err := lib.UserCreate(db, user); err != nil {
|
|
t.Fatalf("UserCreate: %v", err)
|
|
}
|
|
|
|
lib.AccessGrant(db, &lib.Access{
|
|
ID: uuid.New().String(),
|
|
ProjectID: "global",
|
|
UserID: userID,
|
|
Role: lib.RoleSuperAdmin,
|
|
Ops: "rwdm",
|
|
CanGrant: true,
|
|
GrantedBy: "system",
|
|
GrantedAt: now,
|
|
})
|
|
|
|
return userID
|
|
}
|
|
|
|
// getToken gets a token for a user via backdoor auth
|
|
func getToken(t *testing.T, client *http.Client, serverURL, email string) string {
|
|
t.Helper()
|
|
|
|
// Challenge
|
|
body, _ := json.Marshal(map[string]string{"email": email})
|
|
resp, err := client.Post(serverURL+"/api/auth/challenge", "application/json", bytes.NewReader(body))
|
|
if err != nil {
|
|
t.Fatalf("challenge failed: %v", err)
|
|
}
|
|
resp.Body.Close()
|
|
|
|
// Verify with backdoor
|
|
body, _ = json.Marshal(map[string]string{"email": email, "code": "220402"})
|
|
resp, err = client.Post(serverURL+"/api/auth/verify", "application/json", bytes.NewReader(body))
|
|
if err != nil {
|
|
t.Fatalf("verify failed: %v", err)
|
|
}
|
|
var verifyResp map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&verifyResp)
|
|
resp.Body.Close()
|
|
|
|
token, ok := verifyResp["token"].(string)
|
|
if !ok || token == "" {
|
|
t.Fatalf("no token in verify response: %v", verifyResp)
|
|
}
|
|
return token
|
|
}
|
|
|
|
func TestCreateOrg(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
// Create an IB admin user (can create orgs)
|
|
projectID := uuid.New().String()
|
|
createUserWithRole(t, db, "ibadmin@test.com", lib.RoleIBAdmin, projectID)
|
|
token := getToken(t, client, server.URL, "ibadmin@test.com")
|
|
|
|
// Create org with valid payload
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Acme Corporation",
|
|
"domains": []string{"acme.com", "acme-corp.com"},
|
|
"role": "seller",
|
|
"website": "https://acme.com",
|
|
"description": "A company that makes everything",
|
|
"contact_name": "Wile E. Coyote",
|
|
"contact_email": "wile@acme.com",
|
|
})
|
|
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("create org request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusCreated {
|
|
var errResp map[string]string
|
|
json.NewDecoder(resp.Body).Decode(&errResp)
|
|
t.Fatalf("expected 201, got %d: %v", resp.StatusCode, errResp)
|
|
}
|
|
|
|
var createResp map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&createResp)
|
|
|
|
if createResp["entry_id"] == nil || createResp["entry_id"] == "" {
|
|
t.Error("response should contain entry_id")
|
|
}
|
|
if createResp["name"] != "Acme Corporation" {
|
|
t.Errorf("name mismatch: got %v", createResp["name"])
|
|
}
|
|
if createResp["role"] != "seller" {
|
|
t.Errorf("role mismatch: got %v", createResp["role"])
|
|
}
|
|
|
|
domains, ok := createResp["domains"].([]interface{})
|
|
if !ok || len(domains) != 2 {
|
|
t.Errorf("domains should have 2 entries, got %v", createResp["domains"])
|
|
}
|
|
}
|
|
|
|
func TestCreateOrgEmptyDomains(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
projectID := uuid.New().String()
|
|
createUserWithRole(t, db, "ibadmin2@test.com", lib.RoleIBAdmin, projectID)
|
|
token := getToken(t, client, server.URL, "ibadmin2@test.com")
|
|
|
|
// Try to create org with empty domains array
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Bad Org",
|
|
"domains": []string{},
|
|
"role": "buyer",
|
|
})
|
|
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Errorf("expected 400 for empty domains, got %d", resp.StatusCode)
|
|
}
|
|
|
|
var errResp map[string]string
|
|
json.NewDecoder(resp.Body).Decode(&errResp)
|
|
if errResp["code"] != "missing_fields" {
|
|
t.Errorf("expected missing_fields error code, got %s", errResp["code"])
|
|
}
|
|
}
|
|
|
|
func TestCreateOrgMissingDomains(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
projectID := uuid.New().String()
|
|
createUserWithRole(t, db, "ibadmin3@test.com", lib.RoleIBAdmin, projectID)
|
|
token := getToken(t, client, server.URL, "ibadmin3@test.com")
|
|
|
|
// Try to create org without domains field at all
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Missing Domains Org",
|
|
"role": "seller",
|
|
})
|
|
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Errorf("expected 400 for missing domains, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestCreateOrgEmptyDomainString(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
projectID := uuid.New().String()
|
|
createUserWithRole(t, db, "ibadmin4@test.com", lib.RoleIBAdmin, projectID)
|
|
token := getToken(t, client, server.URL, "ibadmin4@test.com")
|
|
|
|
// Try to create org with empty string in domains
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Empty String Domain Org",
|
|
"domains": []string{"valid.com", ""},
|
|
"role": "seller",
|
|
})
|
|
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Errorf("expected 400 for empty domain string, got %d", resp.StatusCode)
|
|
}
|
|
|
|
var errResp map[string]string
|
|
json.NewDecoder(resp.Body).Decode(&errResp)
|
|
if errResp["code"] != "invalid_domains" {
|
|
t.Errorf("expected invalid_domains error code, got %s", errResp["code"])
|
|
}
|
|
}
|
|
|
|
func TestListOrgs(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
// Create IB admin to create orgs
|
|
projectID := uuid.New().String()
|
|
createUserWithRole(t, db, "ibadmin5@test.com", lib.RoleIBAdmin, projectID)
|
|
ibToken := getToken(t, client, server.URL, "ibadmin5@test.com")
|
|
|
|
// Create two orgs
|
|
for i, name := range []string{"Org Alpha", "Org Beta"} {
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": name,
|
|
"domains": []string{name + ".com"},
|
|
"role": "seller",
|
|
})
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+ibToken)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := client.Do(req)
|
|
if resp.StatusCode != http.StatusCreated {
|
|
t.Fatalf("failed to create org %d: %d", i, resp.StatusCode)
|
|
}
|
|
resp.Body.Close()
|
|
}
|
|
|
|
// Create super_admin to list all orgs (IB admin only sees orgs linked to their projects via deal_org)
|
|
createSuperAdmin(t, db, "superadmin-list@test.com")
|
|
saToken := getToken(t, client, server.URL, "superadmin-list@test.com")
|
|
|
|
// List orgs as super_admin
|
|
req, _ := http.NewRequest("GET", server.URL+"/api/orgs", nil)
|
|
req.Header.Set("Authorization", "Bearer "+saToken)
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("list orgs failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
|
|
var orgs []map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&orgs)
|
|
|
|
if len(orgs) < 2 {
|
|
t.Errorf("super_admin expected at least 2 orgs, got %d", len(orgs))
|
|
}
|
|
}
|
|
|
|
func TestSuperAdminCanListAllOrgs(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
// Create super admin first
|
|
createSuperAdmin(t, db, "superadmin@test.com")
|
|
|
|
// Create an IB admin to create orgs
|
|
projectID := uuid.New().String()
|
|
createUserWithRole(t, db, "ibadmin6@test.com", lib.RoleIBAdmin, projectID)
|
|
ibToken := getToken(t, client, server.URL, "ibadmin6@test.com")
|
|
|
|
// Create org
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "SuperAdmin Test Org",
|
|
"domains": []string{"supertest.com"},
|
|
"role": "buyer",
|
|
})
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+ibToken)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := client.Do(req)
|
|
resp.Body.Close()
|
|
|
|
// Super admin lists orgs
|
|
saToken := getToken(t, client, server.URL, "superadmin@test.com")
|
|
req, _ = http.NewRequest("GET", server.URL+"/api/orgs", nil)
|
|
req.Header.Set("Authorization", "Bearer "+saToken)
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("list orgs as super admin failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Errorf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
|
|
var orgs []map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&orgs)
|
|
|
|
// Super admin should see all orgs
|
|
found := false
|
|
for _, org := range orgs {
|
|
if org["name"] == "SuperAdmin Test Org" {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Error("super admin should see all orgs")
|
|
}
|
|
}
|
|
|
|
func TestCreateOrgForbiddenForRegularUser(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
// Create a regular user (buyer role)
|
|
projectID := uuid.New().String()
|
|
createUserWithRole(t, db, "buyer@test.com", lib.RoleBuyerMember, projectID)
|
|
token := getToken(t, client, server.URL, "buyer@test.com")
|
|
|
|
// Try to create org (should fail - only IB admin or super admin can create orgs)
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Forbidden Org",
|
|
"domains": []string{"forbidden.com"},
|
|
"role": "buyer",
|
|
})
|
|
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusForbidden {
|
|
t.Errorf("expected 403 for regular user, got %d", resp.StatusCode)
|
|
}
|
|
}
|
|
|
|
func TestGetOrg(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
projectID := uuid.New().String()
|
|
createUserWithRole(t, db, "ibadmin7@test.com", lib.RoleIBAdmin, projectID)
|
|
token := getToken(t, client, server.URL, "ibadmin7@test.com")
|
|
|
|
// Create org
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Get Test Org",
|
|
"domains": []string{"gettest.com"},
|
|
"role": "seller",
|
|
"contact_email": "contact@gettest.com",
|
|
})
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := client.Do(req)
|
|
var createResp map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&createResp)
|
|
resp.Body.Close()
|
|
|
|
orgID := createResp["entry_id"].(string)
|
|
|
|
// Get the org
|
|
req, _ = http.NewRequest("GET", server.URL+"/api/orgs/"+orgID, nil)
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("get org failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d", resp.StatusCode)
|
|
}
|
|
|
|
var orgResp map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&orgResp)
|
|
|
|
if orgResp["name"] != "Get Test Org" {
|
|
t.Errorf("name mismatch: got %v", orgResp["name"])
|
|
}
|
|
if orgResp["contact_email"] != "contact@gettest.com" {
|
|
t.Errorf("contact_email mismatch: got %v", orgResp["contact_email"])
|
|
}
|
|
}
|
|
|
|
func TestUpdateOrg(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
// Use super_admin for update (org entries use their own ID as project_id, need super_admin access)
|
|
createSuperAdmin(t, db, "superadmin-update@test.com")
|
|
token := getToken(t, client, server.URL, "superadmin-update@test.com")
|
|
|
|
// Create org
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Update Test Org",
|
|
"domains": []string{"update.com"},
|
|
"role": "seller",
|
|
})
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, _ := client.Do(req)
|
|
var createResp map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&createResp)
|
|
resp.Body.Close()
|
|
|
|
orgID := createResp["entry_id"].(string)
|
|
|
|
// Update the org
|
|
updateBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Updated Org Name",
|
|
"domains": []string{"update.com", "updated.com"},
|
|
"description": "Now with a description",
|
|
"version": 1,
|
|
})
|
|
req, _ = http.NewRequest("PATCH", server.URL+"/api/orgs/"+orgID, bytes.NewReader(updateBody))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("update org failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
var errResp map[string]string
|
|
json.NewDecoder(resp.Body).Decode(&errResp)
|
|
t.Fatalf("expected 200, got %d: %v", resp.StatusCode, errResp)
|
|
}
|
|
|
|
var updateResp map[string]interface{}
|
|
json.NewDecoder(resp.Body).Decode(&updateResp)
|
|
|
|
if updateResp["name"] != "Updated Org Name" {
|
|
t.Errorf("name should be updated: got %v", updateResp["name"])
|
|
}
|
|
if updateResp["description"] != "Now with a description" {
|
|
t.Errorf("description should be updated: got %v", updateResp["description"])
|
|
}
|
|
}
|
|
|
|
func TestCreateOrgInvalidRole(t *testing.T) {
|
|
server, db, _, cleanup := testServerSetup(t)
|
|
defer cleanup()
|
|
|
|
client := &http.Client{}
|
|
|
|
projectID := uuid.New().String()
|
|
createUserWithRole(t, db, "ibadmin9@test.com", lib.RoleIBAdmin, projectID)
|
|
token := getToken(t, client, server.URL, "ibadmin9@test.com")
|
|
|
|
// Try to create org with invalid role
|
|
orgBody, _ := json.Marshal(map[string]interface{}{
|
|
"name": "Invalid Role Org",
|
|
"domains": []string{"invalid.com"},
|
|
"role": "invalid_role",
|
|
})
|
|
|
|
req, _ := http.NewRequest("POST", server.URL+"/api/orgs", bytes.NewReader(orgBody))
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
req.Header.Set("Content-Type", "application/json")
|
|
resp, err := client.Do(req)
|
|
if err != nil {
|
|
t.Fatalf("request failed: %v", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
if resp.StatusCode != http.StatusBadRequest {
|
|
t.Errorf("expected 400 for invalid role, got %d", resp.StatusCode)
|
|
}
|
|
|
|
var errResp map[string]string
|
|
json.NewDecoder(resp.Body).Decode(&errResp)
|
|
if errResp["code"] != "invalid_role" {
|
|
t.Errorf("expected invalid_role error code, got %s", errResp["code"])
|
|
}
|
|
}
|