mirror of https://github.com/veypi/OneAuth.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
224 lines
5.6 KiB
Go
224 lines
5.6 KiB
Go
|
1 week ago
|
package tests
|
||
|
|
|
||
|
|
import (
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestOrgCRUD(t *testing.T) {
|
||
|
|
ensureUsers(t)
|
||
|
|
|
||
|
|
var orgID string
|
||
|
|
|
||
|
|
// Test 1: Create Organization
|
||
|
|
t.Run("Create Organization", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "POST", "/api/orgs", map[string]string{
|
||
|
|
"code": "test_org_crud",
|
||
|
|
"name": "Test Org CRUD",
|
||
|
|
"description": "Organization for CRUD tests",
|
||
|
|
}, User1Token)
|
||
|
|
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
var data struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
}
|
||
|
|
decodeResponse(t, resp, &data)
|
||
|
|
orgID = data.ID
|
||
|
|
t.Logf("Created org: %s", orgID)
|
||
|
|
})
|
||
|
|
|
||
|
|
if orgID == "" {
|
||
|
|
t.Fatal("Failed to create org, skipping remaining tests")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test 2: List Organizations
|
||
|
|
t.Run("List Organizations", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "GET", "/api/orgs", nil, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
var data struct {
|
||
|
|
Items []OrgResp `json:"items"`
|
||
|
|
Total int64 `json:"total"`
|
||
|
|
}
|
||
|
|
decodeResponse(t, resp, &data)
|
||
|
|
t.Logf("Total orgs: %d", data.Total)
|
||
|
|
|
||
|
|
if data.Total <= 0 {
|
||
|
|
t.Errorf("Expected at least 1 org, got %d", data.Total)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
// Test 3: Get Org Details
|
||
|
|
t.Run("Get Org Details", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "GET", "/api/orgs/"+orgID, nil, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
var data OrgResp
|
||
|
|
decodeResponse(t, resp, &data)
|
||
|
|
|
||
|
|
if data.Name != "Test Org CRUD" {
|
||
|
|
t.Errorf("Expected name 'Test Org CRUD', got '%s'", data.Name)
|
||
|
|
}
|
||
|
|
if data.Code != "test_org_crud" {
|
||
|
|
t.Errorf("Expected code 'test_org_crud', got '%s'", data.Code)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
// Test 4: Update Organization
|
||
|
|
t.Run("Update Organization", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "PATCH", "/api/orgs/"+orgID, map[string]string{
|
||
|
|
"name": "Updated Org Name",
|
||
|
|
"description": "Updated description",
|
||
|
|
}, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
// Verify update
|
||
|
|
resp = doRequest(t, "GET", "/api/orgs/"+orgID, nil, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
var data OrgResp
|
||
|
|
decodeResponse(t, resp, &data)
|
||
|
|
|
||
|
|
if data.Name != "Updated Org Name" {
|
||
|
|
t.Errorf("Expected name 'Updated Org Name', got '%s'", data.Name)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
// Test 5: Get Org Members
|
||
|
|
t.Run("Get Org Members", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "GET", "/api/orgs/"+orgID+"/members", nil, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
var data struct {
|
||
|
|
Items []struct {
|
||
|
|
UserID string `json:"user_id"`
|
||
|
|
Role string `json:"role"`
|
||
|
|
} `json:"items"`
|
||
|
|
}
|
||
|
|
decodeResponse(t, resp, &data)
|
||
|
|
t.Logf("Org members count: %d", len(data.Items))
|
||
|
|
})
|
||
|
|
|
||
|
|
// Test 6: Delete Organization (as owner)
|
||
|
|
t.Run("Delete Organization", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "DELETE", "/api/orgs/"+orgID, nil, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
// Verify deletion
|
||
|
|
resp = doRequest(t, "GET", "/api/orgs/"+orgID, nil, User1Token)
|
||
|
|
if resp.Code == 200 {
|
||
|
|
t.Errorf("Expected org to be deleted, but got 200")
|
||
|
|
} else {
|
||
|
|
t.Logf("Org deleted successfully, got code: %d", resp.Code)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
// Test 7: List after deletion
|
||
|
|
t.Run("List After Delete", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "GET", "/api/orgs", nil, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
var data struct {
|
||
|
|
Total int64 `json:"total"`
|
||
|
|
}
|
||
|
|
decodeResponse(t, resp, &data)
|
||
|
|
t.Logf("Total orgs after delete: %d", data.Total)
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test Org Tree
|
||
|
|
func TestOrgTree(t *testing.T) {
|
||
|
|
ensureUsers(t)
|
||
|
|
|
||
|
|
// Create parent org
|
||
|
|
var parentOrgID string
|
||
|
|
t.Run("Create Parent Org", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "POST", "/api/orgs", map[string]string{
|
||
|
|
"code": "parent_org",
|
||
|
|
"name": "Parent Organization",
|
||
|
|
"description": "Parent org for tree test",
|
||
|
|
}, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
var data struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
}
|
||
|
|
decodeResponse(t, resp, &data)
|
||
|
|
parentOrgID = data.ID
|
||
|
|
})
|
||
|
|
|
||
|
|
if parentOrgID == "" {
|
||
|
|
t.Fatal("Failed to create parent org")
|
||
|
|
}
|
||
|
|
|
||
|
|
// Get org tree
|
||
|
|
t.Run("Get Org Tree", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "GET", "/api/orgs/tree", nil, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
// Tree endpoint returns array directly
|
||
|
|
var data []OrgResp
|
||
|
|
decodeResponse(t, resp, &data)
|
||
|
|
t.Logf("Org tree items: %d", len(data))
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
// Test non-member access
|
||
|
|
func TestOrgAccessControl(t *testing.T) {
|
||
|
|
ensureUsers(t)
|
||
|
|
|
||
|
|
// User1 creates org
|
||
|
|
var orgID string
|
||
|
|
t.Run("User1 Creates Org", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "POST", "/api/orgs", map[string]string{
|
||
|
|
"code": "private_org",
|
||
|
|
"name": "Private Organization",
|
||
|
|
"description": "Private org for access test",
|
||
|
|
}, User1Token)
|
||
|
|
assertStatus(t, resp, 200)
|
||
|
|
|
||
|
|
var data struct {
|
||
|
|
ID string `json:"id"`
|
||
|
|
}
|
||
|
|
decodeResponse(t, resp, &data)
|
||
|
|
orgID = data.ID
|
||
|
|
})
|
||
|
|
|
||
|
|
if orgID == "" {
|
||
|
|
t.Fatal("Failed to create org")
|
||
|
|
}
|
||
|
|
|
||
|
|
// User2 (non-member) tries to access
|
||
|
|
t.Run("Non-member Get Org", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "GET", "/api/orgs/"+orgID, nil, User2Token)
|
||
|
|
// Should fail with 403
|
||
|
|
if resp.Code == 200 {
|
||
|
|
t.Errorf("Expected non-member to be denied, got 200")
|
||
|
|
} else {
|
||
|
|
t.Logf("Non-member correctly denied access, code: %d", resp.Code)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("Non-member Update Org", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "PATCH", "/api/orgs/"+orgID, map[string]string{
|
||
|
|
"name": "Hacked",
|
||
|
|
}, User2Token)
|
||
|
|
// Should fail with 403
|
||
|
|
if resp.Code == 200 {
|
||
|
|
t.Errorf("Expected non-member to be denied, got 200")
|
||
|
|
} else {
|
||
|
|
t.Logf("Non-member correctly denied update, code: %d", resp.Code)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
|
||
|
|
t.Run("Non-member Get Members", func(t *testing.T) {
|
||
|
|
resp := doRequest(t, "GET", "/api/orgs/"+orgID+"/members", nil, User2Token)
|
||
|
|
// Should fail with 403
|
||
|
|
if resp.Code == 200 {
|
||
|
|
t.Errorf("Expected non-member to be denied, got 200")
|
||
|
|
} else {
|
||
|
|
t.Logf("Non-member correctly denied members access, code: %d", resp.Code)
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|