package repository import ( "context" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/gorm" "github.com/gochat/gochat/internal/model" ) // Helper: create prerequisite Account + PlatformApp for Permissible tests. func createPermissiblePrereqs(t *testing.T, db *gorm.DB) (*model.Account, *model.PlatformApp) { t.Helper() account := &model.Account{Name: "PermTestOrg", Locale: "en", Active: true} require.NoError(t, db.Create(account).Error) active := true app := &model.PlatformApp{ Name: "PermTestApp", AccountID: &account.ID, Description: "Test platform app for permissible", Type: "api", Status: "active", Active: &active, } require.NoError(t, db.Create(app).Error) return account, app } // Helper: create a second PlatformApp for multi-app tests. func createSecondPlatformApp(t *testing.T, db *gorm.DB, accountID uint) *model.PlatformApp { t.Helper() active := true app := &model.PlatformApp{ Name: "PermTestApp2", AccountID: &accountID, Description: "Second test platform app", Type: "api", Status: "active", Active: &active, } require.NoError(t, db.Create(app).Error) return app } // ========== 1. Create + GetByID roundtrip ========== func TestPermissibleRepo_CreateAndGetByID(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) account, app := createPermissiblePrereqs(t, db) perm := &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, } err := repo.Create(context.Background(), perm) require.NoError(t, err) assert.NotZero(t, perm.ID, "ID should be set after Create") assert.Equal(t, app.ID, perm.PlatformAppID) assert.Equal(t, model.PermissibleTypeAccount, perm.PermissibleType) assert.Equal(t, account.ID, perm.PermissibleID) // GetByID roundtrip found, err := repo.GetByID(context.Background(), perm.ID) require.NoError(t, err) assert.Equal(t, perm.ID, found.ID) assert.Equal(t, app.ID, found.PlatformAppID) assert.Equal(t, model.PermissibleTypeAccount, found.PermissibleType) assert.Equal(t, account.ID, found.PermissibleID) } // ========== 2. FindByPlatformAppID ========== func TestPermissibleRepo_FindByPlatformAppID(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) account, app := createPermissiblePrereqs(t, db) // Create multiple permissibles for the same app (different resource types) perm1 := &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, } perm2 := &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeUser, PermissibleID: account.ID, } require.NoError(t, repo.Create(context.Background(), perm1)) require.NoError(t, repo.Create(context.Background(), perm2)) results, err := repo.FindByPlatformAppID(context.Background(), app.ID) require.NoError(t, err) assert.Len(t, results, 2) // Verify both types are present types := map[string]bool{} for _, p := range results { types[p.PermissibleType] = true assert.Equal(t, app.ID, p.PlatformAppID) } assert.True(t, types[model.PermissibleTypeAccount]) assert.True(t, types[model.PermissibleTypeUser]) } func TestPermissibleRepo_FindByPlatformAppID_Empty(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) _, app := createPermissiblePrereqs(t, db) results, err := repo.FindByPlatformAppID(context.Background(), app.ID) require.NoError(t, err) assert.Len(t, results, 0) } // ========== 3. FindByResource (which apps can access Account X) ========== func TestPermissibleRepo_FindByResource(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) account, app1 := createPermissiblePrereqs(t, db) app2 := createSecondPlatformApp(t, db, account.ID) // Both apps get access to the same Account resource require.NoError(t, repo.Create(context.Background(), &model.Permissible{ PlatformAppID: app1.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, })) require.NoError(t, repo.Create(context.Background(), &model.Permissible{ PlatformAppID: app2.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, })) // FindByResource should return both permissibles results, err := repo.FindByResource(context.Background(), model.PermissibleTypeAccount, account.ID) require.NoError(t, err) assert.Len(t, results, 2) // Verify both apps are represented appIDs := map[uint]bool{} for _, p := range results { appIDs[p.PlatformAppID] = true assert.Equal(t, model.PermissibleTypeAccount, p.PermissibleType) assert.Equal(t, account.ID, p.PermissibleID) } assert.True(t, appIDs[app1.ID]) assert.True(t, appIDs[app2.ID]) } // ========== 4. FindByPlatformAppAndResource (check if app has permission on specific resource) ========== func TestPermissibleRepo_FindByPlatformAppAndResource(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) account, app := createPermissiblePrereqs(t, db) perm := &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, } require.NoError(t, repo.Create(context.Background(), perm)) // Found: app has permission on this resource found, err := repo.FindByPlatformAppAndResource(context.Background(), app.ID, model.PermissibleTypeAccount, account.ID) require.NoError(t, err) assert.Equal(t, perm.ID, found.ID) assert.Equal(t, app.ID, found.PlatformAppID) assert.Equal(t, model.PermissibleTypeAccount, found.PermissibleType) assert.Equal(t, account.ID, found.PermissibleID) } func TestPermissibleRepo_FindByPlatformAppAndResource_NotFound(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) account, app := createPermissiblePrereqs(t, db) // No permissible created — should return gorm.ErrRecordNotFound _, err := repo.FindByPlatformAppAndResource(context.Background(), app.ID, model.PermissibleTypeAccount, account.ID) assert.Error(t, err) assert.Equal(t, gorm.ErrRecordNotFound, err) } // ========== 5. Delete single Permissible ========== func TestPermissibleRepo_Delete(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) account, app := createPermissiblePrereqs(t, db) perm := &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, } require.NoError(t, repo.Create(context.Background(), perm)) err := repo.Delete(context.Background(), perm.ID) require.NoError(t, err) // Verify it's gone _, err = repo.GetByID(context.Background(), perm.ID) assert.Error(t, err) assert.Equal(t, gorm.ErrRecordNotFound, err) } // ========== 6. DeleteByPlatformAppAndResource ========== func TestPermissibleRepo_DeleteByPlatformAppAndResource(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) account, app := createPermissiblePrereqs(t, db) // Create two permissibles: one for Account, one for User permAccount := &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, } permUser := &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeUser, PermissibleID: account.ID, } require.NoError(t, repo.Create(context.Background(), permAccount)) require.NoError(t, repo.Create(context.Background(), permUser)) // Delete only the Account permission err := repo.DeleteByPlatformAppAndResource(context.Background(), app.ID, model.PermissibleTypeAccount, account.ID) require.NoError(t, err) // Account permission should be gone _, err = repo.FindByPlatformAppAndResource(context.Background(), app.ID, model.PermissibleTypeAccount, account.ID) assert.Equal(t, gorm.ErrRecordNotFound, err) // User permission should still exist found, err := repo.FindByPlatformAppAndResource(context.Background(), app.ID, model.PermissibleTypeUser, account.ID) require.NoError(t, err) assert.Equal(t, permUser.ID, found.ID) } // ========== 7. DeleteByPlatformAppID (cleanup when app is deleted) ========== func TestPermissibleRepo_DeleteByPlatformAppID(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) account, app := createPermissiblePrereqs(t, db) app2 := createSecondPlatformApp(t, db, account.ID) // Create permissibles for both apps require.NoError(t, repo.Create(context.Background(), &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, })) require.NoError(t, repo.Create(context.Background(), &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeUser, PermissibleID: account.ID, })) require.NoError(t, repo.Create(context.Background(), &model.Permissible{ PlatformAppID: app2.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, })) // Delete all permissibles for app1 err := repo.DeleteByPlatformAppID(context.Background(), app.ID) require.NoError(t, err) // App1's permissibles should all be gone results, err := repo.FindByPlatformAppID(context.Background(), app.ID) require.NoError(t, err) assert.Len(t, results, 0) // App2's permissible should still exist results, err = repo.FindByPlatformAppID(context.Background(), app2.ID) require.NoError(t, err) assert.Len(t, results, 1) assert.Equal(t, model.PermissibleTypeAccount, results[0].PermissibleType) } // ========== 8. Duplicate permission should error (unique constraint) ========== func TestPermissibleRepo_DuplicatePermissionError(t *testing.T) { db := setupTestDB(t, &model.Permissible{}, &model.PlatformApp{}) repo := NewPermissibleRepo(db) account, app := createPermissiblePrereqs(t, db) perm := &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, } require.NoError(t, repo.Create(context.Background(), perm)) // Attempt to create duplicate (same platform_app_id + permissible_type + permissible_id) dup := &model.Permissible{ PlatformAppID: app.ID, PermissibleType: model.PermissibleTypeAccount, PermissibleID: account.ID, } err := repo.Create(context.Background(), dup) assert.Error(t, err, "duplicate permissible should return an error") }