package services import ( "context" "testing" "github.com/DATA-DOG/go-sqlmock" ) func TestAuditService_RecordLogin(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("Failed to create mock db: %v", err) } defer db.Close() service := NewAuditService(db) ctx := context.Background() t.Run("records login successfully", func(t *testing.T) { ipAddress := "192.168.1.1" userAgent := "Mozilla/5.0" mock.ExpectExec("INSERT INTO login_audit"). WithArgs("user-123", "test@example.com", "admin,recruiter", &ipAddress, &userAgent). WillReturnResult(sqlmock.NewResult(1, 1)) err := service.RecordLogin(ctx, LoginAuditInput{ UserID: "user-123", Identifier: "test@example.com", Roles: []string{"admin", "recruiter"}, IPAddress: &ipAddress, UserAgent: &userAgent, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("Unmet expectations: %v", err) } }) t.Run("records login without optional fields", func(t *testing.T) { mock.ExpectExec("INSERT INTO login_audit"). WithArgs("user-456", "admin@test.com", "superadmin", nil, nil). WillReturnResult(sqlmock.NewResult(2, 1)) err := service.RecordLogin(ctx, LoginAuditInput{ UserID: "user-456", Identifier: "admin@test.com", Roles: []string{"superadmin"}, IPAddress: nil, UserAgent: nil, }) if err != nil { t.Fatalf("Unexpected error: %v", err) } if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("Unmet expectations: %v", err) } }) } func TestAuditService_ListLogins(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("Failed to create mock db: %v", err) } defer db.Close() service := NewAuditService(db) ctx := context.Background() t.Run("returns empty list when no audits", func(t *testing.T) { mock.ExpectQuery("SELECT id, user_id, identifier, roles, ip_address, user_agent, created_at FROM login_audit"). WithArgs(50). WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "identifier", "roles", "ip_address", "user_agent", "created_at"})) audits, err := service.ListLogins(ctx, 0) // Should default to 50 if err != nil { t.Fatalf("Unexpected error: %v", err) } if len(audits) != 0 { t.Errorf("Expected 0 audits, got %d", len(audits)) } if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("Unmet expectations: %v", err) } }) t.Run("respects custom limit", func(t *testing.T) { mock.ExpectQuery("SELECT id, user_id, identifier, roles, ip_address, user_agent, created_at FROM login_audit"). WithArgs(10). WillReturnRows(sqlmock.NewRows([]string{"id", "user_id", "identifier", "roles", "ip_address", "user_agent", "created_at"})) _, err := service.ListLogins(ctx, 10) if err != nil { t.Fatalf("Unexpected error: %v", err) } if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("Unmet expectations: %v", err) } }) }