package handler_test import ( "encoding/json" "fmt" "net/http" "testing" ) func TestPermissionHandler_CreatePermission(t *testing.T) { server, cleanup := setupHandlerTestServer(t) defer cleanup() t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret") adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!") if adminToken == "" { t.Fatal("bootstrap admin failed") } if ok := registerUser(server.URL, "permuser", "permuser@test.com", "UserPass123!"); !ok { t.Fatal("register user failed") } userToken := getToken(server.URL, "permuser", "UserPass123!") if userToken == "" { t.Fatal("get user token failed") } tests := []struct { name string payload map[string]interface{} token string wantStatus int }{ { name: "success", payload: map[string]interface{}{ "name": "Test Permission", "code": "test:permission:create", "type": 2, }, token: adminToken, wantStatus: http.StatusCreated, }, { name: "unauthorized", payload: map[string]interface{}{ "name": "Test Permission", "code": "test:permission:unauth", "type": 2, }, token: "", wantStatus: http.StatusUnauthorized, }, { name: "forbidden", payload: map[string]interface{}{ "name": "Test Permission", "code": "test:permission:forbid", "type": 2, }, token: userToken, wantStatus: http.StatusForbidden, }, { name: "invalid_type", payload: map[string]interface{}{ "name": "Test Permission", "code": "test:permission:badtype", "type": 5, }, token: adminToken, wantStatus: http.StatusBadRequest, }, { name: "missing_required_fields", payload: map[string]interface{}{"name": "Missing Code"}, token: adminToken, wantStatus: http.StatusBadRequest, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, body := doPost(server.URL+"/api/v1/permissions", tt.token, tt.payload) defer resp.Body.Close() if resp.StatusCode != tt.wantStatus { t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body) } }) } } func TestPermissionHandler_ListPermissions(t *testing.T) { server, cleanup := setupHandlerTestServer(t) defer cleanup() t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret") adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!") if adminToken == "" { t.Fatal("bootstrap admin failed") } if ok := registerUser(server.URL, "permuser", "permuser@test.com", "UserPass123!"); !ok { t.Fatal("register user failed") } userToken := getToken(server.URL, "permuser", "UserPass123!") if userToken == "" { t.Fatal("get user token failed") } tests := []struct { name string token string wantStatus int }{ { name: "success_admin", token: adminToken, wantStatus: http.StatusOK, }, { name: "forbidden_regular_user", token: userToken, wantStatus: http.StatusForbidden, }, { name: "unauthorized", token: "", wantStatus: http.StatusUnauthorized, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, body := doGet(server.URL+"/api/v1/permissions", tt.token) defer resp.Body.Close() if resp.StatusCode != tt.wantStatus { t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body) } }) } } func TestPermissionHandler_GetPermission(t *testing.T) { server, cleanup := setupHandlerTestServer(t) defer cleanup() t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret") adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!") if adminToken == "" { t.Fatal("bootstrap admin failed") } // Create a permission to retrieve createResp, createBody := doPost(server.URL+"/api/v1/permissions", adminToken, map[string]interface{}{ "name": "Get Permission Test", "code": "test:permission:get", "type": 2, }) defer createResp.Body.Close() if createResp.StatusCode != http.StatusCreated { t.Fatalf("create permission failed: %d %s", createResp.StatusCode, createBody) } var createResult map[string]interface{} if err := json.Unmarshal([]byte(createBody), &createResult); err != nil { t.Fatalf("parse create response failed: %v", err) } permData, ok := createResult["data"].(map[string]interface{}) if !ok { t.Fatalf("expected data in create response, got %s", createBody) } permID := int64(permData["id"].(float64)) tests := []struct { name string permID string token string wantStatus int }{ { name: "success", permID: fmt.Sprintf("%d", permID), token: adminToken, wantStatus: http.StatusOK, }, { name: "not_found", permID: "99999", token: adminToken, wantStatus: http.StatusNotFound, }, { name: "invalid_id", permID: "invalid", token: adminToken, wantStatus: http.StatusBadRequest, }, { name: "unauthorized", permID: fmt.Sprintf("%d", permID), token: "", wantStatus: http.StatusUnauthorized, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, body := doGet(server.URL+"/api/v1/permissions/"+tt.permID, tt.token) defer resp.Body.Close() if resp.StatusCode != tt.wantStatus { t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body) } }) } } func TestPermissionHandler_UpdatePermission(t *testing.T) { server, cleanup := setupHandlerTestServer(t) defer cleanup() t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret") adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!") if adminToken == "" { t.Fatal("bootstrap admin failed") } // Create a permission to update createResp, createBody := doPost(server.URL+"/api/v1/permissions", adminToken, map[string]interface{}{ "name": "Update Permission Test", "code": "test:permission:update", "type": 2, }) defer createResp.Body.Close() if createResp.StatusCode != http.StatusCreated { t.Fatalf("create permission failed: %d %s", createResp.StatusCode, createBody) } var createResult map[string]interface{} if err := json.Unmarshal([]byte(createBody), &createResult); err != nil { t.Fatalf("parse create response failed: %v", err) } permData := createResult["data"].(map[string]interface{}) permID := int64(permData["id"].(float64)) tests := []struct { name string permID string payload map[string]interface{} token string wantStatus int }{ { name: "success", permID: fmt.Sprintf("%d", permID), payload: map[string]interface{}{ "name": "Updated Permission Name", }, token: adminToken, wantStatus: http.StatusOK, }, { name: "invalid_id", permID: "invalid", payload: map[string]interface{}{ "name": "Updated Permission Name", }, token: adminToken, wantStatus: http.StatusBadRequest, }, { name: "unauthorized", permID: fmt.Sprintf("%d", permID), payload: map[string]interface{}{ "name": "Updated Permission Name", }, token: "", wantStatus: http.StatusUnauthorized, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, body := doPut(server.URL+"/api/v1/permissions/"+tt.permID, tt.token, tt.payload) defer resp.Body.Close() if resp.StatusCode != tt.wantStatus { t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body) } }) } } func TestPermissionHandler_DeletePermission(t *testing.T) { server, cleanup := setupHandlerTestServer(t) defer cleanup() t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret") adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!") if adminToken == "" { t.Fatal("bootstrap admin failed") } // Create a permission to delete createResp, createBody := doPost(server.URL+"/api/v1/permissions", adminToken, map[string]interface{}{ "name": "Delete Permission Test", "code": "test:permission:delete", "type": 2, }) defer createResp.Body.Close() if createResp.StatusCode != http.StatusCreated { t.Fatalf("create permission failed: %d %s", createResp.StatusCode, createBody) } var createResult map[string]interface{} if err := json.Unmarshal([]byte(createBody), &createResult); err != nil { t.Fatalf("parse create response failed: %v", err) } permData := createResult["data"].(map[string]interface{}) permID := int64(permData["id"].(float64)) tests := []struct { name string permID string token string wantStatus int }{ { name: "success", permID: fmt.Sprintf("%d", permID), token: adminToken, wantStatus: http.StatusOK, }, { name: "invalid_id", permID: "invalid", token: adminToken, wantStatus: http.StatusBadRequest, }, { name: "unauthorized", permID: fmt.Sprintf("%d", permID), token: "", wantStatus: http.StatusUnauthorized, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, body := doDelete(server.URL+"/api/v1/permissions/"+tt.permID, tt.token) defer resp.Body.Close() if resp.StatusCode != tt.wantStatus { t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body) } }) } } func TestPermissionHandler_UpdatePermissionStatus(t *testing.T) { server, cleanup := setupHandlerTestServer(t) defer cleanup() t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret") adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!") if adminToken == "" { t.Fatal("bootstrap admin failed") } // Create a permission createResp, createBody := doPost(server.URL+"/api/v1/permissions", adminToken, map[string]interface{}{ "name": "Status Permission Test", "code": "test:permission:status", "type": 2, }) defer createResp.Body.Close() if createResp.StatusCode != http.StatusCreated { t.Fatalf("create permission failed: %d %s", createResp.StatusCode, createBody) } var createResult map[string]interface{} if err := json.Unmarshal([]byte(createBody), &createResult); err != nil { t.Fatalf("parse create response failed: %v", err) } permData := createResult["data"].(map[string]interface{}) permID := int64(permData["id"].(float64)) tests := []struct { name string permID string payload map[string]interface{} token string wantStatus int }{ { name: "success_numeric", permID: fmt.Sprintf("%d", permID), payload: map[string]interface{}{ "status": 0, }, token: adminToken, wantStatus: http.StatusOK, }, { name: "invalid_id", permID: "invalid", payload: map[string]interface{}{ "status": 0, }, token: adminToken, wantStatus: http.StatusBadRequest, }, { name: "unauthorized", permID: fmt.Sprintf("%d", permID), payload: map[string]interface{}{ "status": 0, }, token: "", wantStatus: http.StatusUnauthorized, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { resp, body := doPut(server.URL+"/api/v1/permissions/"+tt.permID+"/status", tt.token, tt.payload) defer resp.Body.Close() if resp.StatusCode != tt.wantStatus { t.Errorf("expected status %d, got %d, body: %s", tt.wantStatus, resp.StatusCode, body) } }) } } func TestPermissionHandler_GetPermissionTree(t *testing.T) { server, cleanup := setupHandlerTestServer(t) defer cleanup() t.Setenv("BOOTSTRAP_SECRET", "perm-bootstrap-secret") adminToken := bootstrapAdmin(server.URL, "perm-bootstrap-secret", "permadmin", "permadmin@test.com", "AdminPass123!") if adminToken == "" { t.Fatal("bootstrap admin failed") } resp, body := doGet(server.URL+"/api/v1/permissions/tree", adminToken) defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Fatalf("expected status %d, got %d, body: %s", http.StatusOK, resp.StatusCode, body) } var result map[string]interface{} if err := json.Unmarshal([]byte(body), &result); err != nil { t.Fatalf("parse response failed: %v", err) } if result["code"] != float64(0) { t.Errorf("expected code 0, got %v", result["code"]) } if result["data"] == nil { t.Errorf("expected data in response") } }