yao/openapi/tests/user/member_test.go
Max ca2344edb8 Refactor invitation handling and improve test coverage
- Updated invitation creation logic to support email invitations and customizable expiry durations.
- Enhanced tests for invitation creation, including scenarios for registered and unregistered users, and handling of missing email requirements.
- Refactored API endpoints to use consistent parameter naming for team IDs.
- Improved error handling and logging for invitation-related operations, ensuring clarity in failure cases.
- Added support for sending invitation emails through the messenger service, with appropriate templates and settings.
2025-10-08 16:16:49 +08:00

1024 lines
30 KiB
Go

package user_test
import (
"bytes"
"encoding/json"
"io"
"net/http"
"testing"
"github.com/stretchr/testify/assert"
"github.com/yaoapp/yao/openapi"
"github.com/yaoapp/yao/openapi/tests/testutils"
)
// TestMemberList tests the GET /user/teams/:team_id/members endpoint
func TestMemberList(t *testing.T) {
// Initialize test environment
serverURL := testutils.Prepare(t)
defer testutils.Clean()
// Get base URL from server config
baseURL := ""
if openapi.Server != nil && openapi.Server.Config != nil {
baseURL = openapi.Server.Config.BaseURL
}
// Register a test client for OAuth authentication
testClient := testutils.RegisterTestClient(t, "Member List Test Client", []string{"https://localhost/callback"})
defer testutils.CleanupTestClient(t, testClient.ClientID)
// Obtain access token for authenticated requests
tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")
// Create a test team first
createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Member List Test Team")
teamID := getTeamID(createdTeam)
testCases := []struct {
name string
teamID string
query string
headers map[string]string
expectCode int
expectMsg string
}{
{
"list members without authentication",
teamID,
"",
map[string]string{},
401,
"should require authentication",
},
{
"list members with valid token",
teamID,
"",
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
200,
"should return team members",
},
{
"list members with pagination",
teamID,
"?page=1&pagesize=10",
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
200,
"should handle pagination parameters",
},
{
"list members with status filter",
teamID,
"?status=active",
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
200,
"should filter by status",
},
{
"list members of non-existent team",
"non-existent-team-id",
"",
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
404,
"should return not found for non-existent team",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
requestURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members" + tc.query
req, err := http.NewRequest("GET", requestURL, nil)
assert.NoError(t, err, "Should create HTTP request")
// Add headers
for key, value := range tc.headers {
req.Header.Set(key, value)
}
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err, "HTTP request should succeed")
if resp != nil {
defer resp.Body.Close()
assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err, "Should read response body")
if resp.StatusCode == 200 {
// Parse response as pagination result
var response map[string]interface{}
err = json.Unmarshal(body, &response)
assert.NoError(t, err, "Should parse JSON response")
// Check pagination structure
assert.Contains(t, response, "data", "Should have data array")
assert.Contains(t, response, "total", "Should have total count")
assert.Contains(t, response, "page", "Should have page number")
assert.Contains(t, response, "pagesize", "Should have pagesize")
// Verify that creator is automatically added as member
if data, ok := response["data"].([]interface{}); ok {
assert.GreaterOrEqual(t, len(data), 1, "Should have at least the owner as member")
if len(data) > 0 {
member := data[0].(map[string]interface{})
assert.Equal(t, tokenInfo.UserID, member["user_id"], "Owner should be in member list")
assert.Equal(t, "owner", member["role_id"], "Creator should have owner role")
}
}
}
t.Logf("Member list test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
}
})
}
}
// TestMemberGet tests the GET /user/teams/:team_id/members/:member_id endpoint
func TestMemberGet(t *testing.T) {
// Initialize test environment
serverURL := testutils.Prepare(t)
defer testutils.Clean()
// Get base URL from server config
baseURL := ""
if openapi.Server != nil && openapi.Server.Config != nil {
baseURL = openapi.Server.Config.BaseURL
}
// Register a test client for OAuth authentication
testClient := testutils.RegisterTestClient(t, "Member Get Test Client", []string{"https://localhost/callback"})
defer testutils.CleanupTestClient(t, testClient.ClientID)
// Obtain access token for authenticated requests
tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")
// Create a test team and get owner member ID
createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Member Get Test Team")
teamID := getTeamID(createdTeam)
// Get member list to find the owner member ID
ownerMemberID := getOwnerMemberID(t, serverURL, baseURL, teamID, tokenInfo.AccessToken)
testCases := []struct {
name string
teamID string
memberID string
headers map[string]string
expectCode int
expectMsg string
}{
{
"get member without authentication",
teamID,
ownerMemberID,
map[string]string{},
401,
"should require authentication",
},
{
"get existing member",
teamID,
ownerMemberID,
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
200,
"should return member details",
},
{
"get non-existent member",
teamID,
"999999",
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
404,
"should return not found for non-existent member",
},
{
"get member from non-existent team",
"non-existent-team-id",
ownerMemberID,
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
404,
"should return not found for non-existent team",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
requestURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members/" + tc.memberID
req, err := http.NewRequest("GET", requestURL, nil)
assert.NoError(t, err, "Should create HTTP request")
// Add headers
for key, value := range tc.headers {
req.Header.Set(key, value)
}
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err, "HTTP request should succeed")
if resp != nil {
defer resp.Body.Close()
assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err, "Should read response body")
if resp.StatusCode == 200 {
// Parse response as member object
var member map[string]interface{}
err = json.Unmarshal(body, &member)
assert.NoError(t, err, "Should parse JSON response")
// Verify member structure
assert.Contains(t, member, "id", "Should have member ID")
assert.Contains(t, member, "team_id", "Should have team_id")
assert.Contains(t, member, "user_id", "Should have user_id")
assert.Contains(t, member, "role_id", "Should have role_id")
assert.Contains(t, member, "status", "Should have status")
assert.Contains(t, member, "created_at", "Should have created_at")
assert.Contains(t, member, "updated_at", "Should have updated_at")
// Verify values
assert.Equal(t, teamID, member["team_id"], "Should have correct team_id")
assert.Equal(t, tokenInfo.UserID, member["user_id"], "Should have correct user_id")
}
t.Logf("Member get test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
}
})
}
}
// TestMemberCreateDirect tests the POST /user/teams/:team_id/members endpoint
func TestMemberCreateDirect(t *testing.T) {
// Initialize test environment
serverURL := testutils.Prepare(t)
defer testutils.Clean()
// Get base URL from server config
baseURL := ""
if openapi.Server != nil && openapi.Server.Config != nil {
baseURL = openapi.Server.Config.BaseURL
}
// Register a test client for OAuth authentication
testClient := testutils.RegisterTestClient(t, "Member Create Test Client", []string{"https://localhost/callback"})
defer testutils.CleanupTestClient(t, testClient.ClientID)
// Obtain access token for authenticated requests
tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")
// Create a test team
createdTeam := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Member Create Test Team")
teamID := getTeamID(createdTeam)
testCases := []struct {
name string
teamID string
body map[string]interface{}
headers map[string]string
expectCode int
expectMsg string
}{
{
"create member without authentication",
teamID,
map[string]interface{}{
"user_id": "test-user-123",
"role_id": "member",
},
map[string]string{},
401,
"should require authentication",
},
{
"create member with valid data",
teamID,
map[string]interface{}{
"user_id": "test-user-123",
"member_type": "user",
"role_id": "member",
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
201,
"should create member successfully",
},
{
"create member with settings",
teamID,
map[string]interface{}{
"user_id": "test-user-456",
"member_type": "user",
"role_id": "admin",
"settings": map[string]interface{}{
"notifications": true,
"permissions": []string{"read", "write"},
},
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
201,
"should create member with settings",
},
{
"create member without user_id",
teamID,
map[string]interface{}{
"role_id": "member",
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
400,
"should require user_id",
},
{
"create member without role_id",
teamID,
map[string]interface{}{
"user_id": "test-user-789",
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
400,
"should require role_id",
},
{
"create duplicate member",
teamID,
map[string]interface{}{
"user_id": "test-user-123", // Same as first successful case
"role_id": "member",
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
409,
"should reject duplicate member",
},
{
"create member in non-existent team",
"non-existent-team-id",
map[string]interface{}{
"user_id": "test-user-999",
"role_id": "member",
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
404,
"should return not found for non-existent team",
},
{
"create member with invalid JSON",
teamID,
nil, // Will send invalid JSON
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
400,
"should handle invalid JSON",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
requestURL := serverURL + baseURL + "/user/teams/" + tc.teamID + "/members"
var req *http.Request
var err error
if tc.body == nil {
// Send invalid JSON for invalid JSON test case
req, err = http.NewRequest("POST", requestURL, bytes.NewBufferString("invalid json"))
} else {
bodyBytes, _ := json.Marshal(tc.body)
req, err = http.NewRequest("POST", requestURL, bytes.NewBuffer(bodyBytes))
}
assert.NoError(t, err, "Should create HTTP request")
req.Header.Set("Content-Type", "application/json")
// Add headers
for key, value := range tc.headers {
req.Header.Set(key, value)
}
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err, "HTTP request should succeed")
if resp != nil {
defer resp.Body.Close()
assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err, "Should read response body")
if resp.StatusCode == 201 {
// Parse response as created member
var response map[string]interface{}
err = json.Unmarshal(body, &response)
assert.NoError(t, err, "Should parse JSON response")
// Verify response structure
assert.Contains(t, response, "member_id", "Should have member_id")
assert.NotEmpty(t, response["member_id"], "Member ID should not be empty")
}
t.Logf("Member create test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
}
})
}
}
// TestMemberUpdate tests the PUT /user/teams/:team_id/members/:member_id endpoint
func TestMemberUpdate(t *testing.T) {
// Initialize test environment
serverURL := testutils.Prepare(t)
defer testutils.Clean()
// Get base URL from server config
baseURL := ""
if openapi.Server != nil && openapi.Server.Config != nil {
baseURL = openapi.Server.Config.BaseURL
}
// Register a test client for OAuth authentication
testClient := testutils.RegisterTestClient(t, "Member Update Test Client", []string{"https://localhost/callback"})
defer testutils.CleanupTestClient(t, testClient.ClientID)
// Obtain access token for authenticated requests
tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")
testCases := []struct {
name string
setupFunc func() (string, string) // Returns (teamID, memberID)
body map[string]interface{}
headers map[string]string
expectCode int
expectMsg string
}{
{
"update member without authentication",
func() (string, string) {
team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 1")
teamID := getTeamID(team)
memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-1")
return teamID, memberID
},
map[string]interface{}{
"role_id": "admin",
},
map[string]string{},
401,
"should require authentication",
},
{
"update member role",
func() (string, string) {
team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 2")
teamID := getTeamID(team)
memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-2")
return teamID, memberID
},
map[string]interface{}{
"role_id": "admin",
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
200,
"should update member role",
},
{
"update member status",
func() (string, string) {
team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 3")
teamID := getTeamID(team)
memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-3")
return teamID, memberID
},
map[string]interface{}{
"status": "inactive",
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
200,
"should update member status",
},
{
"update non-existent member",
func() (string, string) {
team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 5")
teamID := getTeamID(team)
return teamID, "999999"
},
map[string]interface{}{
"role_id": "admin",
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
404,
"should return not found for non-existent member",
},
{
"update member in non-existent team",
func() (string, string) {
team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 6")
teamID := getTeamID(team)
memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-5")
return "non-existent-team-id", memberID
},
map[string]interface{}{
"role_id": "admin",
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
404,
"should return not found for non-existent team",
},
{
"update member with invalid JSON",
func() (string, string) {
team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Update Test Team 7")
teamID := getTeamID(team)
memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-update-user-6")
return teamID, memberID
},
nil, // Will send invalid JSON
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
400,
"should handle invalid JSON",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
teamID, memberID := tc.setupFunc()
requestURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
var req *http.Request
var err error
if tc.body == nil {
// Send invalid JSON for invalid JSON test case
req, err = http.NewRequest("PUT", requestURL, bytes.NewBufferString("invalid json"))
} else {
bodyBytes, _ := json.Marshal(tc.body)
req, err = http.NewRequest("PUT", requestURL, bytes.NewBuffer(bodyBytes))
}
assert.NoError(t, err, "Should create HTTP request")
req.Header.Set("Content-Type", "application/json")
// Add headers
for key, value := range tc.headers {
req.Header.Set(key, value)
}
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err, "HTTP request should succeed")
if resp != nil {
defer resp.Body.Close()
assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err, "Should read response body")
if resp.StatusCode == 200 {
// Parse response as success message
var response map[string]interface{}
err = json.Unmarshal(body, &response)
assert.NoError(t, err, "Should parse JSON response")
assert.Contains(t, response, "message", "Should have success message")
assert.Equal(t, "Member updated successfully", response["message"], "Should have correct success message")
}
t.Logf("Member update test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
}
})
}
}
// TestMemberDelete tests the DELETE /user/teams/:team_id/members/:member_id endpoint
func TestMemberDelete(t *testing.T) {
// Initialize test environment
serverURL := testutils.Prepare(t)
defer testutils.Clean()
// Get base URL from server config
baseURL := ""
if openapi.Server != nil && openapi.Server.Config != nil {
baseURL = openapi.Server.Config.BaseURL
}
// Register a test client for OAuth authentication
testClient := testutils.RegisterTestClient(t, "Member Delete Test Client", []string{"https://localhost/callback"})
defer testutils.CleanupTestClient(t, testClient.ClientID)
// Obtain access token for authenticated requests
tokenInfo := testutils.ObtainAccessToken(t, serverURL, testClient.ClientID, testClient.ClientSecret, "https://localhost/callback", "openid profile")
// Create teams and members for testing deletion
createMemberForDeletion := func(name string) (string, string) {
team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Delete Test Team "+name)
teamID := getTeamID(team)
memberID := createTestMember(t, serverURL, baseURL, teamID, tokenInfo.AccessToken, "test-delete-user-"+name)
return teamID, memberID
}
testCases := []struct {
name string
setupFunc func() (string, string) // Returns (teamID, memberID)
headers map[string]string
expectCode int
expectMsg string
}{
{
"delete member without authentication",
func() (string, string) { return createMemberForDeletion("1") },
map[string]string{},
401,
"should require authentication",
},
{
"delete existing member",
func() (string, string) { return createMemberForDeletion("2") },
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
200,
"should delete member successfully",
},
{
"delete non-existent member",
func() (string, string) {
team := createTestTeam(t, serverURL, baseURL, tokenInfo.AccessToken, "Delete Test Team 3")
return getTeamID(team), "999999"
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
404,
"should return not found for non-existent member",
},
{
"delete member from non-existent team",
func() (string, string) {
_, memberID := createMemberForDeletion("4")
return "non-existent-team-id", memberID
},
map[string]string{
"Authorization": "Bearer " + tokenInfo.AccessToken,
},
404,
"should return not found for non-existent team",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
teamID, memberID := tc.setupFunc()
requestURL := serverURL + baseURL + "/user/teams/" + teamID + "/members/" + memberID
req, err := http.NewRequest("DELETE", requestURL, nil)
assert.NoError(t, err, "Should create HTTP request")
// Add headers
for key, value := range tc.headers {
req.Header.Set(key, value)
}
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err, "HTTP request should succeed")
if resp != nil {
defer resp.Body.Close()
assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err, "Should read response body")
if resp.StatusCode == 200 {
// Parse response as success message
var response map[string]interface{}
err = json.Unmarshal(body, &response)
assert.NoError(t, err, "Should parse JSON response")
assert.Contains(t, response, "message", "Should have success message")
assert.Equal(t, "Member removed successfully", response["message"], "Should have correct success message")
}
t.Logf("Member delete test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
}
})
}
}
// TestMemberPermissionVerification tests permission verification for member operations
func TestMemberPermissionVerification(t *testing.T) {
// Initialize test environment
serverURL := testutils.Prepare(t)
defer testutils.Clean()
// Get base URL from server config
baseURL := ""
if openapi.Server != nil && openapi.Server.Config != nil {
baseURL = openapi.Server.Config.BaseURL
}
// Register test clients for different users
ownerClient := testutils.RegisterTestClient(t, "Owner Test Client", []string{"https://localhost/callback"})
defer testutils.CleanupTestClient(t, ownerClient.ClientID)
nonOwnerClient := testutils.RegisterTestClient(t, "Non-Owner Test Client", []string{"https://localhost/callback"})
defer testutils.CleanupTestClient(t, nonOwnerClient.ClientID)
// Obtain access tokens
ownerToken := testutils.ObtainAccessToken(t, serverURL, ownerClient.ClientID, ownerClient.ClientSecret, "https://localhost/callback", "openid profile")
nonOwnerToken := testutils.ObtainAccessToken(t, serverURL, nonOwnerClient.ClientID, nonOwnerClient.ClientSecret, "https://localhost/callback", "openid profile")
// Create a team with owner
createdTeam := createTestTeam(t, serverURL, baseURL, ownerToken.AccessToken, "Permission Test Team")
teamID := getTeamID(createdTeam)
// Add non-owner as a member
memberID := createTestMember(t, serverURL, baseURL, teamID, ownerToken.AccessToken, nonOwnerToken.UserID)
testCases := []struct {
name string
endpoint string
method string
token string
expectCode int
expectMsg string
}{
{
"owner can list members",
"/user/teams/" + teamID + "/members",
"GET",
ownerToken.AccessToken,
200,
"owner should be able to list members",
},
{
"member can list members",
"/user/teams/" + teamID + "/members",
"GET",
nonOwnerToken.AccessToken,
200,
"member should be able to list members",
},
{
"owner can get member details",
"/user/teams/" + teamID + "/members/" + memberID,
"GET",
ownerToken.AccessToken,
200,
"owner should be able to get member details",
},
{
"member can get member details",
"/user/teams/" + teamID + "/members/" + memberID,
"GET",
nonOwnerToken.AccessToken,
200,
"member should be able to get member details",
},
{
"owner can create members",
"/user/teams/" + teamID + "/members",
"POST",
ownerToken.AccessToken,
201, // Will create successfully
"owner should be able to create members",
},
{
"member cannot create members",
"/user/teams/" + teamID + "/members",
"POST",
nonOwnerToken.AccessToken,
403,
"member should not be able to create members",
},
{
"owner can update members",
"/user/teams/" + teamID + "/members/" + memberID,
"PUT",
ownerToken.AccessToken,
200,
"owner should be able to update members",
},
{
"member cannot update members",
"/user/teams/" + teamID + "/members/" + memberID,
"PUT",
nonOwnerToken.AccessToken,
403,
"member should not be able to update members",
},
{
"owner can delete members",
"/user/teams/" + teamID + "/members/" + memberID,
"DELETE",
ownerToken.AccessToken,
200,
"owner should be able to delete members",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
requestURL := serverURL + baseURL + tc.endpoint
var req *http.Request
var err error
// Create request body for POST/PUT methods
if tc.method == "POST" {
body := map[string]interface{}{
"user_id": "test-permission-user",
"role_id": "member",
}
bodyBytes, _ := json.Marshal(body)
req, err = http.NewRequest(tc.method, requestURL, bytes.NewBuffer(bodyBytes))
req.Header.Set("Content-Type", "application/json")
} else if tc.method == "PUT" {
body := map[string]interface{}{
"role_id": "admin",
}
bodyBytes, _ := json.Marshal(body)
req, err = http.NewRequest(tc.method, requestURL, bytes.NewBuffer(bodyBytes))
req.Header.Set("Content-Type", "application/json")
} else {
req, err = http.NewRequest(tc.method, requestURL, nil)
}
assert.NoError(t, err, "Should create HTTP request")
req.Header.Set("Authorization", "Bearer "+tc.token)
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err, "HTTP request should succeed")
if resp != nil {
defer resp.Body.Close()
assert.Equal(t, tc.expectCode, resp.StatusCode, "Expected status code %d for %s", tc.expectCode, tc.name)
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err, "Should read response body")
t.Logf("Permission test %s: status=%d, body=%s", tc.name, resp.StatusCode, string(body))
}
})
}
}
// Helper functions
// createTestTeam creates a team for testing and returns the team data
func createTestTeam(t *testing.T, serverURL, baseURL, accessToken, teamName string) map[string]interface{} {
createTeamBody := map[string]interface{}{
"name": teamName,
"description": "Team created for testing purposes",
}
bodyBytes, err := json.Marshal(createTeamBody)
assert.NoError(t, err, "Should marshal team creation body")
req, err := http.NewRequest("POST", serverURL+baseURL+"/user/teams", bytes.NewBuffer(bodyBytes))
assert.NoError(t, err, "Should create team creation request")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+accessToken)
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err, "Should send team creation request")
defer resp.Body.Close()
assert.Equal(t, 201, resp.StatusCode, "Should create team successfully")
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err, "Should read team creation response")
var team map[string]interface{}
err = json.Unmarshal(body, &team)
assert.NoError(t, err, "Should parse team creation response")
return team
}
// createTestMember creates a member for testing and returns the user_id (which serves as member_id in API context)
func createTestMember(t *testing.T, serverURL, baseURL, teamID, accessToken, userID string) string {
createMemberBody := map[string]interface{}{
"user_id": userID,
"member_type": "user",
"role_id": "member",
}
bodyBytes, err := json.Marshal(createMemberBody)
assert.NoError(t, err, "Should marshal member creation body")
req, err := http.NewRequest("POST", serverURL+baseURL+"/user/teams/"+teamID+"/members", bytes.NewBuffer(bodyBytes))
assert.NoError(t, err, "Should create member creation request")
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+accessToken)
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err, "Should send member creation request")
defer resp.Body.Close()
assert.Equal(t, 201, resp.StatusCode, "Should create member successfully")
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err, "Should read member creation response")
var response map[string]interface{}
err = json.Unmarshal(body, &response)
assert.NoError(t, err, "Should parse member creation response")
_, ok := response["member_id"]
assert.True(t, ok, "Should have member_id in response")
// For API purposes, the member_id is the user_id in the context of team_id
// So we return the user_id that was used to create the member
return userID
}
// getOwnerMemberID gets the user_id of the team owner (which serves as member_id in API context)
func getOwnerMemberID(t *testing.T, serverURL, baseURL, teamID, accessToken string) string {
req, err := http.NewRequest("GET", serverURL+baseURL+"/user/teams/"+teamID+"/members", nil)
assert.NoError(t, err, "Should create member list request")
req.Header.Set("Authorization", "Bearer "+accessToken)
client := &http.Client{}
resp, err := client.Do(req)
assert.NoError(t, err, "Should send member list request")
defer resp.Body.Close()
assert.Equal(t, 200, resp.StatusCode, "Should get members successfully")
body, err := io.ReadAll(resp.Body)
assert.NoError(t, err, "Should read member list response")
var response map[string]interface{}
err = json.Unmarshal(body, &response)
assert.NoError(t, err, "Should parse member list response")
data, ok := response["data"].([]interface{})
assert.True(t, ok, "Should have data array")
assert.Greater(t, len(data), 0, "Should have at least one member")
// Find the owner member and return their user_id
for _, item := range data {
member := item.(map[string]interface{})
if role, ok := member["role_id"].(string); ok && role == "owner" {
userID, ok := member["user_id"].(string)
if !ok {
t.Fatal("Owner member missing user_id")
}
return userID
}
}
t.Fatal("Could not find owner member")
return ""
}
// Note: getTeamID function is already defined in team_test.go