package service import ( "context" "encoding/json" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "gorm.io/driver/sqlite" "gorm.io/gorm" "gorm.io/gorm/logger" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/repository" ) // ========== Test Setup ========== func setupAuditServiceTest(t *testing.T) (*AuditService, *gorm.DB) { t.Helper() db, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{ Logger: logger.Default.LogMode(logger.Silent), }) require.NoError(t, err, "failed to open SQLite test db") require.NoError(t, db.AutoMigrate( &model.Account{}, &model.Audit{}, ), "failed to auto-migrate") t.Cleanup(func() { sqlDB, _ := db.DB() sqlDB.Close() }) repo := repository.NewAuditRepo(db) svc := NewAuditService(repo) return svc, db } func createAuditSvcTestAccount(t *testing.T, db *gorm.DB) *model.Account { t.Helper() account := &model.Account{Name: "AuditSvcOrg", Locale: "en", Active: true} require.NoError(t, db.Create(account).Error) return account } // ========== ListByAccount ========== func TestAuditService_ListByAccount(t *testing.T) { svc, db := setupAuditServiceTest(t) account := createAuditSvcTestAccount(t, db) // Seed 3 audit entries for i := 0; i < 3; i++ { audit := &model.Audit{ AccountID: &account.ID, AuditableType: "Conversation", AuditableID: uint(i + 1), Action: "create", AuditedChanges: json.RawMessage(`{"field":"status"}`), } _, err := svc.CreateAudit(context.Background(), audit) require.NoError(t, err) } audits, total, err := svc.ListByAccount(context.Background(), account.ID, "", "", 1, 25) assert.NoError(t, err) assert.Equal(t, int64(3), total) assert.Len(t, audits, 3) } func TestAuditService_ListByAccount_ActionFilter(t *testing.T) { svc, db := setupAuditServiceTest(t) account := createAuditSvcTestAccount(t, db) // Create audit with different actions createAudit := &model.Audit{ AccountID: &account.ID, AuditableType: "Conversation", AuditableID: 1, Action: "create", AuditedChanges: json.RawMessage(`{}`), } _, err := svc.CreateAudit(context.Background(), createAudit) require.NoError(t, err) updateAudit := &model.Audit{ AccountID: &account.ID, AuditableType: "Conversation", AuditableID: 2, Action: "update", AuditedChanges: json.RawMessage(`{}`), } _, err = svc.CreateAudit(context.Background(), updateAudit) require.NoError(t, err) audits, total, err := svc.ListByAccount(context.Background(), account.ID, "update", "", 1, 25) assert.NoError(t, err) assert.Equal(t, int64(1), total) assert.Len(t, audits, 1) assert.Equal(t, "update", audits[0].Action) } func TestAuditService_ListByAccount_DefaultPagination(t *testing.T) { svc, db := setupAuditServiceTest(t) account := createAuditSvcTestAccount(t, db) // No entries — should return empty without error audits, total, err := svc.ListByAccount(context.Background(), account.ID, "", "", 0, 0) assert.NoError(t, err) // page=0 → normalised to page=1, pageSize=0 → normalised to 25 assert.Equal(t, int64(0), total) assert.Len(t, audits, 0) } func TestAuditService_ListByAccount_PaginationBounds(t *testing.T) { svc, _ := setupAuditServiceTest(t) // Test with pageSize > 100 — should be capped to 100 _, _, err := svc.ListByAccount(context.Background(), 1, "", "", 1, 200) // Should not error even with invalid account — just returns empty assert.NoError(t, err) } // ========== CreateAudit ========== func TestAuditService_CreateAudit(t *testing.T) { svc, db := setupAuditServiceTest(t) account := createAuditSvcTestAccount(t, db) audit := &model.Audit{ AccountID: &account.ID, AuditableType: "Message", AuditableID: 42, Action: "delete", AuditedChanges: json.RawMessage(`{"content":"removed"}`), } result, err := svc.CreateAudit(context.Background(), audit) assert.NoError(t, err) assert.NotZero(t, result.ID) assert.Equal(t, "delete", result.Action) } // ========== GetByID ========== func TestAuditService_GetByID(t *testing.T) { svc, db := setupAuditServiceTest(t) account := createAuditSvcTestAccount(t, db) audit := &model.Audit{ AccountID: &account.ID, AuditableType: "Conversation", AuditableID: 1, Action: "create", AuditedChanges: json.RawMessage(`{}`), } created, err := svc.CreateAudit(context.Background(), audit) require.NoError(t, err) found, err := svc.GetByID(context.Background(), created.ID) assert.NoError(t, err) assert.Equal(t, created.ID, found.ID) } func TestAuditService_GetByID_NotFound(t *testing.T) { svc, _ := setupAuditServiceTest(t) _, err := svc.GetByID(context.Background(), 9999) assert.Error(t, err) }