package auth import ( "fmt" "testing" "github.com/google/uuid" "github.com/stretchr/testify/assert" ) func TestCan(t *testing.T) { // Строки матрицы прав из docs/auth-and-roles.md: user, moderator, admin. matrix := []struct { perm Permission name string want [3]bool }{ {PermAdminPanel, "admin panel", [3]bool{false, true, true}}, {PermListUsers, "list users", [3]bool{false, true, true}}, {PermManageLibrary, "manage library", [3]bool{false, false, true}}, {PermViewLibraryStatus, "library status", [3]bool{false, true, true}}, {PermSuggestTracks, "suggest tracks", [3]bool{false, true, true}}, {PermSystemStatus, "system status", [3]bool{false, false, true}}, } roles := [3]Role{RoleUser, RoleModerator, RoleAdmin} for _, row := range matrix { for i, r := range roles { t.Run(fmt.Sprintf("%s/%s", row.name, r), func(t *testing.T) { assert.Equal(t, row.want[i], Can(r, row.perm)) }) } } assert.False(t, Can(Role("guest"), PermAdminPanel)) } func TestCanManageUser(t *testing.T) { actions := map[UserAction]string{ UserCreate: "create", UserEdit: "edit", UserResetPassword: "reset", UserBlock: "block", UserChangeRole: "role", UserDelete: "delete", UserResetRecommendations: "recs", } // want[actor][target] для каждого действия; порядок ролей — user, moderator, admin. cases := map[UserAction][3][3]bool{ UserCreate: {{false, false, false}, {true, false, false}, {true, true, true}}, UserEdit: {{false, false, false}, {true, false, false}, {true, true, true}}, UserResetPassword: {{false, false, false}, {true, false, false}, {true, true, true}}, UserBlock: {{false, false, false}, {true, false, false}, {true, true, true}}, UserChangeRole: {{false, false, false}, {false, false, false}, {true, true, true}}, UserDelete: {{false, false, false}, {false, false, false}, {true, true, true}}, UserResetRecommendations: {{false, false, false}, {true, false, false}, {true, true, true}}, } roles := [3]Role{RoleUser, RoleModerator, RoleAdmin} for action, want := range cases { for ai, ar := range roles { for ti, tr := range roles { t.Run(fmt.Sprintf("%s/%s->%s", actions[action], ar, tr), func(t *testing.T) { actor := Actor{ID: uuid.New(), Role: ar} target := Actor{ID: uuid.New(), Role: tr} assert.Equal(t, want[ai][ti], CanManageUser(actor, target, action)) }) } } } } func TestCanManageUserSelf(t *testing.T) { admin := Actor{ID: uuid.New(), Role: RoleAdmin} for _, a := range []UserAction{UserBlock, UserDelete, UserChangeRole} { assert.False(t, CanManageUser(admin, admin, a), "action %d on self", a) } assert.True(t, CanManageUser(admin, admin, UserEdit)) assert.True(t, CanManageUser(admin, admin, UserResetPassword)) } func TestReviewUploadsIsSeparateFromRole(t *testing.T) { assert.False(t, Principal{Role: RoleAdmin}.Allowed(PermReviewUploads)) assert.True(t, Principal{Role: RoleModerator, ReviewsUploads: true}.Allowed(PermReviewUploads)) assert.True(t, Principal{Role: RoleUser, ReviewsUploads: true}.Allowed(PermReviewUploads)) assert.False(t, Principal{Role: RoleUser}.Allowed(PermReviewUploads)) assert.True(t, Principal{Role: RoleUser, ReviewsUploads: true}.Allowed(PermSuggestTracks) == false) } func TestCanAssignRole(t *testing.T) { cases := []struct { actor, role Role want bool }{ {RoleAdmin, RoleAdmin, true}, {RoleAdmin, RoleModerator, true}, {RoleAdmin, RoleUser, true}, {RoleAdmin, Role("root"), false}, {RoleModerator, RoleUser, true}, {RoleModerator, RoleModerator, false}, {RoleModerator, RoleAdmin, false}, {RoleUser, RoleUser, false}, } for _, tc := range cases { assert.Equal(t, tc.want, CanAssignRole(tc.actor, tc.role), "%s assigns %s", tc.actor, tc.role) } }