package services import ( "authorization/db" "authorization/models" "errors" "testing" "github.com/DATA-DOG/go-sqlmock" ) func setupMockDB(t *testing.T) (sqlmock.Sqlmock, func()) { mockDB, mock, err := sqlmock.New() if err != nil { t.Fatalf("Failed to create mock database: %v", err) } originalDB := db.DB db.DB = mockDB cleanup := func() { db.DB = originalDB mockDB.Close() } return mock, cleanup } func TestAuthorize_PermissionNotFound(t *testing.T) { mock, cleanup := setupMockDB(t) defer cleanup() ctx := &models.AuthorizationContext{ UsersID: "user123", Resource: "nonexistent", Action: "read", RoleID: 1, ResourceData: make(map[string]string), Environment: make(map[string]string), } // Mock user query userRows := sqlmock.NewRows([]string{"users_id", "email_address", "role_id", "is_deleted"}). AddRow("user123", "john@example.com", 1, "0") mock.ExpectQuery("SELECT users_id, email_address"). WithArgs("user123"). WillReturnRows(userRows) // Mock permission query with role check mock.ExpectQuery("SELECT p.permissions_id, p.permission_name, p.description, p.resource, p.action FROM uess_user_management.permissions p INNER JOIN uess_user_management.role_permissions rp"). WithArgs("nonexistent", "read", 1). WillReturnError(errors.New("permission not found")) result, err := Authorize(ctx) if err != nil { t.Errorf("Expected no error, got %v", err) } if result.Allowed { t.Error("Expected access denied") } if result.Message == "" { t.Error("Expected error message") } } func TestAuthorize_Success(t *testing.T) { mock, cleanup := setupMockDB(t) defer cleanup() ctx := &models.AuthorizationContext{ UsersID: "user123", Resource: "document", Action: "read", RoleID: 1, ResourceData: make(map[string]string), Environment: make(map[string]string), } // Mock user query userRows := sqlmock.NewRows([]string{"users_id", "email_address", "role_id", "is_deleted"}). AddRow("user123", "john@example.com", 1, "0") mock.ExpectQuery("SELECT users_id, email_address"). WithArgs("user123"). WillReturnRows(userRows) // Mock permission query with role check permRows := sqlmock.NewRows([]string{"id", "permission_name", "description", "resource", "action"}). AddRow(1, "read_document", "Read document permission", "document", "read") mock.ExpectQuery("SELECT p.permissions_id, p.permission_name, p.description, p.resource, p.action FROM uess_user_management.permissions p INNER JOIN uess_user_management.role_permissions rp"). WithArgs("document", "read", 1). WillReturnRows(permRows) // Mock user attributes query attrRows := sqlmock.NewRows([]string{"attribute_name", "attribute_value"}). AddRow("department", "engineering") mock.ExpectQuery("SELECT attribute_name, attribute_value FROM uess_user_management.user_attributes WHERE users_id = \\?"). WithArgs("user123", "user123"). WillReturnRows(attrRows) // Mock policy attributes query (empty for this test) policyRows := sqlmock.NewRows([]string{"id", "attribute_name", "attribute_type", "comparison", "attribute_value", "permission_id"}) mock.ExpectQuery("SELECT id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM uess_user_management.policy_attributes WHERE permission_id = \\?"). WithArgs(1). WillReturnRows(policyRows) result, err := Authorize(ctx) if err != nil { t.Errorf("Expected no error, got %v", err) } if !result.Allowed { t.Error("Expected access granted") } if result.Message != "Access granted" { t.Errorf("Expected 'Access granted', got '%s'", result.Message) } } func TestAuthorize_UserAttributesError(t *testing.T) { mock, cleanup := setupMockDB(t) defer cleanup() ctx := &models.AuthorizationContext{ UsersID: "user123", Resource: "document", Action: "read", RoleID: 1, ResourceData: make(map[string]string), Environment: make(map[string]string), } // Mock user query userRows := sqlmock.NewRows([]string{"users_id", "email_address", "role_id", "is_deleted"}). AddRow("user123", "john@example.com", 1, "0") mock.ExpectQuery("SELECT users_id, email_address"). WithArgs("user123"). WillReturnRows(userRows) // Mock permission query with role check permRows := sqlmock.NewRows([]string{"id", "permission_name", "description", "resource", "action"}). AddRow(1, "read_document", "Read document permission", "document", "read") mock.ExpectQuery("SELECT p.permissions_id, p.permission_name, p.description, p.resource, p.action FROM uess_user_management.permissions p INNER JOIN uess_user_management.role_permissions rp"). WithArgs("document", "read", 1). WillReturnRows(permRows) // Mock user attributes query with error mock.ExpectQuery("SELECT attribute_name, attribute_value FROM uess_user_management.user_attributes WHERE users_id = \\?"). WithArgs("user123", "user123"). WillReturnError(errors.New("database error")) result, err := Authorize(ctx) if err == nil { t.Error("Expected error for user attributes failure") } if result.Allowed { t.Error("Expected access denied") } } func TestAuthorize_PolicyAttributesError(t *testing.T) { mock, cleanup := setupMockDB(t) defer cleanup() ctx := &models.AuthorizationContext{ UsersID: "user123", Resource: "document", Action: "read", RoleID: 1, ResourceData: make(map[string]string), Environment: make(map[string]string), } // Mock user query userRows := sqlmock.NewRows([]string{"users_id", "email_address", "role_id", "is_deleted"}). AddRow("user123", "john@example.com", 1, "0") mock.ExpectQuery("SELECT users_id, email_address"). WithArgs("user123"). WillReturnRows(userRows) // Mock permission query with role check permRows := sqlmock.NewRows([]string{"id", "permission_name", "description", "resource", "action"}). AddRow(1, "read_document", "Read document permission", "document", "read") mock.ExpectQuery("SELECT p.permissions_id, p.permission_name, p.description, p.resource, p.action FROM uess_user_management.permissions p INNER JOIN uess_user_management.role_permissions rp"). WithArgs("document", "read", 1). WillReturnRows(permRows) // Mock user attributes query attrRows := sqlmock.NewRows([]string{"attribute_name", "attribute_value"}). AddRow("department", "engineering") mock.ExpectQuery("SELECT attribute_name, attribute_value FROM uess_user_management.user_attributes WHERE users_id = \\?"). WithArgs("user123", "user123"). WillReturnRows(attrRows) // Mock policy attributes query with error mock.ExpectQuery("SELECT id, attribute_name, attribute_type, comparison, attribute_value, permission_id FROM uess_user_management.policy_attributes WHERE permission_id = \\?"). WithArgs(1). WillReturnError(errors.New("database error")) result, err := Authorize(ctx) if err == nil { t.Error("Expected error for policy attributes failure") } if result.Allowed { t.Error("Expected access denied") } } func TestGetRoleCandidates_Priority(t *testing.T) { t.Run("uses candidate roles first", func(t *testing.T) { ctx := &models.AuthorizationContext{ CandidateRoles: []int{4, 2}, RoleIDs: []int{3}, RoleID: 1, } roles := getRoleCandidates(ctx) if len(roles) != 2 || roles[0] != 4 || roles[1] != 2 { t.Fatalf("unexpected roles: %v", roles) } }) t.Run("falls back to role ids array", func(t *testing.T) { ctx := &models.AuthorizationContext{ RoleIDs: []int{3, 7}, } roles := getRoleCandidates(ctx) if len(roles) != 2 || roles[0] != 3 || roles[1] != 7 { t.Fatalf("unexpected roles: %v", roles) } }) t.Run("falls back to single role", func(t *testing.T) { ctx := &models.AuthorizationContext{RoleID: 9} roles := getRoleCandidates(ctx) if len(roles) != 1 || roles[0] != 9 { t.Fatalf("unexpected roles: %v", roles) } }) } func TestAuthorize_DeletedUserRedirectsToLogin(t *testing.T) { mock, cleanup := setupMockDB(t) defer cleanup() ctx := &models.AuthorizationContext{ UsersID: "deleted-user", Resource: "document", Action: "read", RoleID: 1, ResourceData: make(map[string]string), Environment: make(map[string]string), } userRows := sqlmock.NewRows([]string{"users_id", "email_address", "role_id", "is_deleted"}). AddRow("deleted-user", "deleted@example.com", 1, "1") mock.ExpectQuery("SELECT users_id, email_address, role_id, is_deleted"). WithArgs("deleted-user"). WillReturnRows(userRows) result, err := Authorize(ctx) if err != nil { t.Errorf("Expected no error, got %v", err) } if result.Allowed { t.Error("Expected access denied") } if result.RedirectRoute != "/login" { t.Errorf("Expected redirect to /login, got %q", result.RedirectRoute) } }