Duty revoke must share the project advisory lock with reading old holders and writing members, so a post-commit service snapshot cannot miss a transfer. Heal still fills the new holder after commit, and sync failure stays ERR_DUTY_SYNC. Co-authored-by: Cursor <cursoragent@cursor.com>
52 lines
1.4 KiB
Go
52 lines
1.4 KiB
Go
package server
|
|
|
|
import (
|
|
"errors"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"chat-agent-system/internal/authz"
|
|
)
|
|
|
|
func TestResolveUpdateProjectRole_KeepsExistingOwner(t *testing.T) {
|
|
role, err := resolveUpdateProjectRole("", &authz.ProjectMemberRecord{ProjectRole: authz.RoleOwner})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if role != authz.RoleOwner {
|
|
t.Fatalf("omitted project_role must keep owner, got %q", role)
|
|
}
|
|
}
|
|
|
|
func TestResolveUpdateProjectRole_RejectsMissingMember(t *testing.T) {
|
|
if _, err := resolveUpdateProjectRole("", nil); !errors.Is(err, errProjectRoleRequired) {
|
|
t.Fatalf("want errProjectRoleRequired, got %v", err)
|
|
}
|
|
if _, err := resolveUpdateProjectRole("", &authz.ProjectMemberRecord{}); !errors.Is(err, errProjectRoleRequired) {
|
|
t.Fatalf("empty existing role must be rejected, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestWriteDutySyncError_UsesExplicitCode(t *testing.T) {
|
|
rec := httptest.NewRecorder()
|
|
writeDutySyncError(rec)
|
|
if rec.Code != http.StatusInternalServerError {
|
|
t.Fatalf("status=%d", rec.Code)
|
|
}
|
|
if !strings.Contains(rec.Body.String(), "ERR_DUTY_SYNC") {
|
|
t.Fatalf("body=%s", rec.Body.String())
|
|
}
|
|
}
|
|
|
|
func TestResolveUpdateProjectRole_ExplicitRoleWins(t *testing.T) {
|
|
role, err := resolveUpdateProjectRole(authz.RoleViewer, &authz.ProjectMemberRecord{ProjectRole: authz.RoleOwner})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if role != authz.RoleViewer {
|
|
t.Fatalf("explicit role must win, got %q", role)
|
|
}
|
|
}
|