refactor(test): restructure integration tests for auth and permissions

- Move and split 'auth/auth_test.go' into the 'tests/' directory
    - Add 'tests/main_test.go' for global test suite setup
    - Add 'tests/helpers_test.go' for shared test utilities
    - Create separate test files for different auth scenarios ('auth_test.go', 'none_auth_test.go')
    - Add focused tests for org permissions and middleware ('org_permission_test.go', 'resource_perm_test.go', 'org_load_middleware_test.go')
master
veypi 7 days ago
parent f7c4f1ee86
commit 01620b3185

@ -1,252 +0,0 @@
package auth
import (
"context"
"fmt"
"os"
"testing"
"time"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/models"
)
// setupTestDB 初始化测试数据库
func setupTestDB() {
// 使用 SQLite 内存模式
cfg.Config.DB.Type = "sqlite"
cfg.Config.DB.Type = fmt.Sprintf("file::memory:?cache=shared&_time=%d", time.Now().UnixNano())
// 初始化数据库表
if err := models.AllModels.AutoMigrate(cfg.DB()); err != nil {
panic(err)
}
}
// TestMain 负责测试环境的全局初始化
func TestMain(m *testing.M) {
setupTestDB()
code := m.Run()
os.Exit(code)
}
func getTestAuth() Auth {
// 每次获取一个新的 scope避免测试间冲突虽然内存库是共享的但数据清理可能不完全
// 为了简单起见,我们在 TestMain 中只初始化一次 DB但可以通过 scope 区分
scope := fmt.Sprintf("test_scope_%d", time.Now().UnixNano())
a := Factory.New(scope)
// 添加角色定义
a.AddRole("admin", "Administrator", "*:*")
a.AddRole("editor", "Editor",
"article:create",
"article:read",
"article:update",
)
a.AddRole("viewer", "Viewer", "article:read")
a.AddRole("deleter", "Deleter", "article:delete")
// 初始化
if err := a.(*appAuth).init(); err != nil {
panic(err)
}
return a
}
// TestBasicPermission 测试基础权限授予与检查
func TestBasicPermission(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_basic_001"
// 初始状态应该无权限
ok, err := a.CheckPermission(ctx, userID, "", "article:read", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no permission initially")
}
// 授予 viewer 角色
if err := a.GrantRole(ctx, userID, "", "viewer"); err != nil {
t.Fatalf("GrantRole failed: %v", err)
}
// 应该有 article:read 权限
ok, err = a.CheckPermission(ctx, userID, "", "article:read", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if !ok {
t.Error("Expected article:read permission after granting viewer role")
}
// 不应该有 article:create 权限
ok, err = a.CheckPermission(ctx, userID, "", "article:create", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no article:create permission for viewer")
}
}
// TestWildcardPermission 测试通配符权限
func TestWildcardPermission(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_admin_001"
// 授予 admin 角色 (*:*)
if err := a.GrantRole(ctx, userID, "", "admin"); err != nil {
t.Fatalf("GrantRole failed: %v", err)
}
// 应该拥有所有权限
tests := []string{
"article:read",
"article:delete",
"user:create",
"config:update", // system:config:update 会被解析为 system 应用的权限,而 admin 是 test_app 的 admin
}
for _, perm := range tests {
ok, err := a.CheckPermission(ctx, userID, "", perm, "")
if err != nil {
t.Errorf("CheckPermission %s failed: %v", perm, err)
continue
}
if !ok {
t.Errorf("Expected permission %s for admin", perm)
}
}
}
// TestStrictPermissionIsolation 验证权限严格隔离性 (用户请求场景)
// 验证:拥有 delete 权限的用户,是否能通过 read 权限检查
func TestStrictPermissionIsolation(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_deleter_001"
// 授予 deleter 角色 (只包含 article:delete)
if err := a.GrantRole(ctx, userID, "", "deleter"); err != nil {
t.Fatalf("GrantRole failed: %v", err)
}
// 1. 检查 article:delete (应该通过)
ok, err := a.CheckPermission(ctx, userID, "", "article:delete", "")
if err != nil {
t.Fatalf("CheckPermission error: %v", err)
}
if !ok {
t.Errorf("Expected user to have article:delete permission")
}
// 2. 检查 article:read (应该失败)
// 关键验证点delete 不包含 read
ok, err = a.CheckPermission(ctx, userID, "", "article:read", "")
if err != nil {
t.Fatalf("CheckPermission error: %v", err)
}
if ok {
t.Errorf("Strict isolation failed: User with 'article:delete' passed 'article:read' check")
}
}
// TestOrgIsolation 测试多租户/组织隔离
func TestOrgIsolation(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_org_001"
orgA := "org_a"
orgB := "org_b"
// 在 OrgA 中授予 editor 角色
if err := a.GrantRole(ctx, userID, orgA, "editor"); err != nil {
t.Fatalf("GrantRole failed: %v", err)
}
// 在 OrgA 上下文中检查 article:create (应该通过)
ok, err := a.CheckPermission(ctx, userID, orgA, "article:create", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if !ok {
t.Error("Expected permission in OrgA")
}
// 在 OrgB 上下文中检查 article:create (应该失败)
ok, err = a.CheckPermission(ctx, userID, orgB, "article:create", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no permission in OrgB (role was granted in OrgA)")
}
// 在全局上下文中检查 (应该失败,因为角色绑定在 OrgA)
ok, err = a.CheckPermission(ctx, userID, "", "article:create", "")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no global permission")
}
}
// TestResourcePermission 测试特定资源权限
func TestResourcePermission(t *testing.T) {
a := getTestAuth()
ctx := context.Background()
userID := "user_res_001"
resID := "doc_123"
// 需要先创建权限定义,因为 GrantResourcePerm 会检查权限是否存在
permID := fmt.Sprintf("%s:doc:read", a.(*appAuth).scope)
perm := models.Permission{
ID: permID,
Scope: a.(*appAuth).scope,
Resource: "doc",
Action: "read",
Description: "Read Doc",
}
if err := cfg.DB().Create(&perm).Error; err != nil {
t.Fatalf("Failed to create permission: %v", err)
}
// 初始无权限
ok, err := a.CheckPermission(ctx, userID, "", "doc:read", resID)
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no permission")
}
// 授予对特定资源 doc_123 的 doc:read 权限
if err := a.GrantResourcePerm(ctx, userID, "", "doc:read", resID); err != nil {
t.Fatalf("GrantResourcePerm failed: %v", err)
}
// 检查 doc:read on doc_123 (应该通过)
ok, err = a.CheckPermission(ctx, userID, "", "doc:read", resID)
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if !ok {
t.Error("Expected permission on specific resource")
}
// 检查 doc:read on doc_456 (应该失败)
ok, err = a.CheckPermission(ctx, userID, "", "doc:read", "doc_456")
if err != nil {
t.Fatalf("CheckPermission failed: %v", err)
}
if ok {
t.Error("Expected no permission on other resource")
}
}

@ -0,0 +1,86 @@
package tests
import (
"encoding/json"
"testing"
)
func TestAuth(t *testing.T) {
// Ensure base users are created (Admin, User1, User2)
ensureUsers(t)
// Test Temp User Lifecycle
tempUser := "temp_user"
tempPass := "password123"
tempEmail := "temp@test.com"
// 1. Register Temp User
t.Run("Register Temp User", func(t *testing.T) {
resp := doRequest(t, "POST", "/api/auth/register", map[string]string{
"username": tempUser,
"password": tempPass,
"email": tempEmail,
}, "")
// If user exists from previous run, that's fine, but in clean run it should be 200
if resp.Code != 200 {
var r struct {
Code int `json:"code"`
}
json.Unmarshal(resp.Body.Bytes(), &r)
if r.Code != 40003 && r.Code != 40001 {
t.Errorf("Expected 40003 or 40001, got %d", r.Code)
}
} else {
assertStatus(t, resp, 200)
}
})
// 2. Login Temp User
var tempToken string
var tempID string
t.Run("Login Temp User", func(t *testing.T) {
resp := doRequest(t, "POST", "/api/auth/login", map[string]string{
"username": tempUser,
"password": tempPass,
}, "")
assertStatus(t, resp, 200)
t.Logf("Login Response: %s", resp.Body.String())
var data LoginResp
decodeResponse(t, resp, &data)
tempToken = data.AccessToken
})
if tempToken == "" {
t.Fatal("Failed to get temp token, skipping remaining auth tests")
}
// 3. Get User Info
t.Run("Get Temp User Info", func(t *testing.T) {
resp := doRequest(t, "GET", "/api/auth/me", nil, tempToken)
assertStatus(t, resp, 200)
var data UserResp
decodeResponse(t, resp, &data)
tempID = data.ID
})
// 4. Update User Info
t.Run("Update Temp User Info", func(t *testing.T) {
resp := doRequest(t, "PATCH", "/api/users/"+tempID, map[string]string{
"nickname": "Temp Nickname",
}, tempToken)
assertStatus(t, resp, 200)
})
// 5. Logout
t.Run("Logout Temp User", func(t *testing.T) {
resp := doRequest(t, "POST", "/api/auth/logout", map[string]interface{}{}, tempToken)
assertStatus(t, resp, 200)
})
// 6. Verify Token Invalid after Logout (Optional, depends on implementation)
// If logout blacklist is implemented, this should fail with 401
}

@ -0,0 +1,99 @@
package tests
import (
"encoding/json"
"testing"
)
// ensureUsers ensures that the test users exist and tokens are set
func ensureUsers(t *testing.T) {
if AdminToken != "" {
return
}
// Admin
adminUser := "admin_test"
adminPass := "password123"
adminEmail := "admin@test.com"
// Try to login first (in case DB persists but memory cleared - unlikely with TestMain cleanup)
// Or just register and ignore "already exists" error
// Register Admin
registerResp := doRequest(t, "POST", "/api/auth/register", map[string]string{
"username": adminUser,
"password": adminPass,
"email": adminEmail,
}, "")
// If 200 or 400 (already exists), proceed to login
if registerResp.Code != 200 {
// Verify if it's because user already exists
var resp struct {
Code int `json:"code"`
}
if err := json.Unmarshal(registerResp.Body.Bytes(), &resp); err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}
if resp.Code != 40003 && resp.Code != 40001 {
t.Errorf("Expected Vigo code 40003 or 40001, got %d", resp.Code)
}
}
// Login Admin
loginResp := doRequest(t, "POST", "/api/auth/login", map[string]string{
"username": adminUser,
"password": adminPass,
}, "")
assertStatus(t, loginResp, 200)
var loginData LoginResp
decodeResponse(t, loginResp, &loginData)
AdminToken = loginData.AccessToken
AdminID = loginData.User.ID
// Verify me endpoint works (optional, but good for sanity)
// meResp := doRequest(t, "GET", "/api/auth/me", nil, AdminToken)
// assertStatus(t, meResp, 200)
// User1
user1Name := "user1_test"
user1Pass := "password123"
user1Email := "user1@test.com"
doRequest(t, "POST", "/api/auth/register", map[string]string{
"username": user1Name,
"password": user1Pass,
"email": user1Email,
}, "")
loginResp1 := doRequest(t, "POST", "/api/auth/login", map[string]string{
"username": user1Name,
"password": user1Pass,
}, "")
assertStatus(t, loginResp1, 200)
var loginData1 LoginResp
decodeResponse(t, loginResp1, &loginData1)
User1Token = loginData1.AccessToken
User1ID = loginData1.User.ID
// User2
user2Name := "user2_test"
user2Pass := "password123"
user2Email := "user2@test.com"
doRequest(t, "POST", "/api/auth/register", map[string]string{
"username": user2Name,
"password": user2Pass,
"email": user2Email,
}, "")
loginResp2 := doRequest(t, "POST", "/api/auth/login", map[string]string{
"username": user2Name,
"password": user2Pass,
}, "")
assertStatus(t, loginResp2, 200)
var loginData2 LoginResp
decodeResponse(t, loginResp2, &loginData2)
User2Token = loginData2.AccessToken
User2ID = loginData2.User.ID
}

@ -0,0 +1,169 @@
package tests
import (
"bytes"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/veypi/vbase"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/models"
"github.com/veypi/vigo/contrib/config"
"github.com/veypi/vigo/contrib/event"
)
const TestDBFile = "test.db"
// Global variables to hold test data
var (
AdminToken string
User1Token string
User2Token string
AdminID string
User1ID string
User2ID string
)
func TestMain(m *testing.M) {
// Setup
setup()
// Run tests
code := m.Run()
// Teardown
teardown()
os.Exit(code)
}
func setup() {
// Clean up previous run
os.Remove(TestDBFile)
// Configure for testing
cfg.Config.DB = config.Database{
Type: "sqlite",
DSN: TestDBFile,
}
cfg.Config.Redis = config.Redis{
Addr: "memory",
}
// Initialize DB connection
// Force re-initialization if necessary, but cfg.Config.DB.Client calls might need a reset?
// Assuming vigo/contrib/config handles this or we need to manually trigger it.
// Looking at cfg.go: var DB = Config.DB.Client
// Since DB is a variable, it might have been initialized with default values.
// We might need to rely on the fact that Config.DB.Client() creates a new connection based on current Config.DB values.
// But wait, cfg.DB is a variable initialized at package level.
// If the app uses cfg.DB directly, it might be stale.
// However, looking at main.go, it uses `models.Migrate()`.
// models/init.go probably uses cfg.DB.
// Important: Initialize the application components
models.Migrate()
event.Start()
// Set router
// vbase.Router is already initialized in init.go
}
func teardown() {
os.Remove(TestDBFile)
}
// Helpers
func doRequest(t *testing.T, method, path string, body interface{}, token string) *httptest.ResponseRecorder {
var bodyReader io.Reader
if body != nil {
jsonBody, err := json.Marshal(body)
if err != nil {
t.Fatalf("Failed to marshal body: %v", err)
}
bodyReader = bytes.NewReader(jsonBody)
}
req, err := http.NewRequest(method, path, bodyReader)
if err != nil {
t.Fatalf("Failed to create request: %v", err)
}
if token != "" {
req.Header.Set("Authorization", "Bearer "+token)
}
req.Header.Set("Content-Type", "application/json")
w := httptest.NewRecorder()
// Create a vigo context to wrap the request
// However, since we are testing the router, we should just serve HTTP
vbase.Router.ServeHTTP(w, req)
return w
}
func assertStatus(t *testing.T, w *httptest.ResponseRecorder, expectedCode int) {
if w.Code != expectedCode {
// Vigo might return 200 OK but with a JSON error code in body
// Check body for error details
t.Errorf("Expected HTTP status %d, got %d. Body: %s", expectedCode, w.Code, w.Body.String())
}
}
// assertVigoCode checks the 'code' field in JSON response
func assertVigoCode(t *testing.T, w *httptest.ResponseRecorder, expectedCode int) {
var resp struct {
Code int `json:"code"`
}
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
t.Fatalf("Failed to unmarshal response: %v. Body: %s", err, w.Body.String())
}
if resp.Code != expectedCode {
t.Errorf("Expected Vigo code %d, got %d. Body: %s", expectedCode, resp.Code, w.Body.String())
}
}
// decodeResponse decodes the JSON response into v
func decodeResponse(t *testing.T, w *httptest.ResponseRecorder, v interface{}) {
if err := json.Unmarshal(w.Body.Bytes(), v); err != nil {
t.Fatalf("Failed to unmarshal response: %v. Body: %s", err, w.Body.String())
}
}
// Common structs for responses
type BaseResp struct {
Code int `json:"code"`
Msg string `json:"msg"`
}
type LoginResp struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
ExpiresIn int `json:"expires_in"`
User struct {
ID string `json:"id"`
Username string `json:"username"`
Email string `json:"email"`
} `json:"user"`
}
type UserResp struct {
ID string `json:"id"`
Username string `json:"username"`
Nickname string `json:"nickname"`
Email string `json:"email"`
RoleCode string `json:"role_code"`
}
type OrgResp struct {
ID string `json:"id"`
Name string `json:"name"`
Code string `json:"code"`
}

@ -0,0 +1,41 @@
package tests
import (
"net/http"
"testing"
)
func TestNoneAuth(t *testing.T) {
endpoints := []struct {
method string
path string
body interface{}
}{
{"GET", "/api/auth/me", nil},
{"POST", "/api/auth/logout", map[string]interface{}{}},
{"GET", "/api/users", nil},
{"POST", "/api/users", map[string]interface{}{}},
{"GET", "/api/orgs", nil},
{"POST", "/api/orgs", map[string]interface{}{}},
{"GET", "/api/roles", nil},
{"POST", "/api/roles", map[string]interface{}{}},
{"GET", "/api/settings", nil},
{"GET", "/api/oauth/clients", nil},
{"GET", "/api/oauth/providers", nil},
}
for _, ep := range endpoints {
t.Run(ep.method+" "+ep.path, func(t *testing.T) {
w := doRequest(t, ep.method, ep.path, ep.body, "")
// Expect 401 Unauthorized
// Vigo might return 200 with code 40100 in JSON
if w.Code == http.StatusUnauthorized {
return
}
// Check JSON body for code 40100
assertVigoCode(t, w, 40100)
})
}
}

@ -0,0 +1,92 @@
package tests
import (
"testing"
)
func TestOrgLoadMiddleware(t *testing.T) {
ensureUsers(t)
var orgID string
// 1. User1 Creates Org (Owner)
t.Run("User1 Creates Org", func(t *testing.T) {
resp := doRequest(t, "POST", "/api/orgs", map[string]string{
"code": "test_org_load_mw",
"name": "Test Org Load Middleware",
"description": "Created by User1 for Middleware 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, skipping remaining tests")
}
// 2. User1 Get Org Details (Success)
t.Run("User1 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 Load Middleware" {
t.Errorf("Expected name 'Test Org Load Middleware', got '%s'", data.Name)
}
})
// 3. User1 Update Org (Success)
t.Run("User1 Update Org", func(t *testing.T) {
resp := doRequest(t, "PATCH", "/api/orgs/"+orgID, map[string]string{
"name": "Updated Org Middleware",
}, User1Token)
assertStatus(t, resp, 200)
})
// 4. User2 Get Org Details (Fail - 403 Forbidden)
t.Run("User2 Get Org Details (Fail)", func(t *testing.T) {
resp := doRequest(t, "GET", "/api/orgs/"+orgID, nil, User2Token)
// Expect 403 or 404 depending on implementation of LoadOrg
// Usually 403 if authenticated but not authorized
if resp.Code == 200 {
t.Errorf("Expected error code (403/404), got 200")
} else {
// Optional: check specific error code in body
var errResp BaseResp
decodeResponse(t, resp, &errResp)
// e.g. 40300 or similar
if errResp.Code < 40000 {
t.Logf("Got error code: %d, msg: %s", errResp.Code, errResp.Msg)
}
}
})
// 5. User1 adds User2 as Member
t.Run("User1 adds User2 as Member", func(t *testing.T) {
resp := doRequest(t, "POST", "/api/orgs/"+orgID+"/members", map[string]string{
"user_id": User2ID,
"role": "member",
}, User1Token)
assertStatus(t, resp, 200)
})
// 6. User2 Get Org Details (Success - Now Member)
t.Run("User2 Get Org Details (Success)", func(t *testing.T) {
resp := doRequest(t, "GET", "/api/orgs/"+orgID, nil, User2Token)
assertStatus(t, resp, 200)
var data OrgResp
decodeResponse(t, resp, &data)
if data.Name != "Updated Org Middleware" {
t.Errorf("Expected name 'Updated Org Middleware', got '%s'", data.Name)
}
})
}

@ -0,0 +1,103 @@
package tests
import (
"testing"
)
func TestOrgPermission(t *testing.T) {
ensureUsers(t)
// User1 will be the Org Creator (Owner)
// User2 will be the Outsider -> Member
var orgID string
// 1. User1 Creates Org
t.Run("User1 Creates Org", func(t *testing.T) {
resp := doRequest(t, "POST", "/api/orgs", map[string]string{
"code": "test_org_1",
"name": "Test Org 1",
"description": "Created by User1",
}, User1Token)
// If org code already exists (from previous run), we might get 400
// But let's assume clean run or handle unique code
if resp.Code == 400 {
// Try to get the org if it exists, or just use a unique code
// For simplicity in TestMain environment, we can use a fixed code
// If it fails, we might need to query it.
// Let's just assert 200 for now as we clean DB.
}
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, skipping remaining org tests")
}
// 2. User2 tries to update Org (Should Fail - Outsider)
t.Run("User2 (Outsider) updates Org", func(t *testing.T) {
resp := doRequest(t, "PATCH", "/api/orgs/"+orgID, map[string]string{
"name": "Hacked By User2",
}, User2Token)
if resp.Code != 200 {
// Good
} else {
var errResp BaseResp
decodeResponse(t, resp, &errResp)
if errResp.Code < 40000 {
t.Errorf("Expected error code, got %d. Msg: %s", errResp.Code, errResp.Msg)
}
}
})
// 3. User1 adds User2 as Member
t.Run("User1 adds User2 as Member", func(t *testing.T) {
// Endpoint: POST /api/orgs/:id/users
// Body: { user_id: "...", role_code: "member" }
resp := doRequest(t, "POST", "/api/orgs/"+orgID+"/members", map[string]string{
"user_id": User2ID,
"role": "member",
}, User1Token)
assertStatus(t, resp, 200)
})
// 4. User2 (Member) tries to update Org (Should Fail - Member cannot update org info)
t.Run("User2 (Member) updates Org", func(t *testing.T) {
resp := doRequest(t, "PATCH", "/api/orgs/"+orgID, map[string]string{
"name": "Hacked By Member",
}, User2Token)
if resp.Code != 200 {
// Good
} else {
var errResp BaseResp
decodeResponse(t, resp, &errResp)
if errResp.Code < 40000 {
t.Errorf("Expected error code, got %d. Msg: %s", errResp.Code, errResp.Msg)
}
}
})
// 5. User1 (Owner) updates Org (Should Success)
t.Run("User1 (Owner) updates Org", func(t *testing.T) {
resp := doRequest(t, "PATCH", "/api/orgs/"+orgID, map[string]string{
"name": "Updated By User1",
}, User1Token)
assertStatus(t, resp, 200)
var data OrgResp
decodeResponse(t, resp, &data)
if data.Name != "Updated By User1" {
t.Errorf("Expected name 'Updated By User1', got '%s'", data.Name)
}
})
}

@ -0,0 +1,75 @@
package tests
import (
"testing"
)
func TestResourcePermission(t *testing.T) {
ensureUsers(t)
// Case 1: Admin modifies User1 (Should Success)
t.Run("Admin modifies User1", func(t *testing.T) {
resp := doRequest(t, "PATCH", "/api/users/"+User1ID, map[string]string{
"nickname": "Edited By Admin",
}, AdminToken)
assertStatus(t, resp, 200)
var data UserResp
decodeResponse(t, resp, &data)
if data.Nickname != "Edited By Admin" {
t.Errorf("Expected nickname 'Edited By Admin', got '%s'", data.Nickname)
}
})
// Case 2: User1 modifies User1 (Should Success)
t.Run("User1 modifies User1", func(t *testing.T) {
resp := doRequest(t, "PATCH", "/api/users/"+User1ID, map[string]string{
"nickname": "Edited By Self",
}, User1Token)
assertStatus(t, resp, 200)
var data UserResp
decodeResponse(t, resp, &data)
if data.Nickname != "Edited By Self" {
t.Errorf("Expected nickname 'Edited By Self', got '%s'", data.Nickname)
}
})
// Case 3: User1 modifies User2 (Should Fail 403/404)
t.Run("User1 modifies User2", func(t *testing.T) {
resp := doRequest(t, "PATCH", "/api/users/"+User2ID, map[string]string{
"nickname": "Hacked By User1",
}, User1Token)
// Expecting 403 Forbidden or 404 NotFound
if resp.Code != 200 {
// Good
} else {
// Check Vigo code
var errResp BaseResp
decodeResponse(t, resp, &errResp)
// Common Forbidden/NotFound codes: 40300, 40400, etc.
// Or maybe 40100 Unauthorized
if errResp.Code < 40000 {
t.Errorf("Expected error code, got %d. Msg: %s", errResp.Code, errResp.Msg)
}
}
})
// Case 4: User1 modifies Admin (Should Fail 403/404)
t.Run("User1 modifies Admin", func(t *testing.T) {
resp := doRequest(t, "PATCH", "/api/users/"+AdminID, map[string]string{
"nickname": "Hacked By User1",
}, User1Token)
if resp.Code != 200 {
// Good
} else {
var errResp BaseResp
decodeResponse(t, resp, &errResp)
if errResp.Code < 40000 {
t.Errorf("Expected error code, got %d. Msg: %s", errResp.Code, errResp.Msg)
}
}
})
}
Loading…
Cancel
Save