package services import ( "context" "database/sql" "testing" "github.com/DATA-DOG/go-sqlmock" ) func TestNewEmailService(t *testing.T) { db, _, err := sqlmock.New() if err != nil { t.Fatalf("Failed to create mock db: %v", err) } defer db.Close() credsSvc := &CredentialsService{ DB: db, cache: make(map[string]string), } service := NewEmailService(db, credsSvc) concreteService, ok := service.(*emailServiceImpl) if !ok { t.Fatal("Expected NewEmailService to return *emailServiceImpl") } if concreteService == nil { t.Error("Expected service, got nil") } if concreteService.db != db { t.Error("Expected db to be set") } if concreteService.credentialsService != credsSvc { t.Error("Expected credentialsService to be set") } } func TestEmailService_SendTemplateEmail_NoAMQPURL(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("Failed to create mock db: %v", err) } defer db.Close() credsSvc := &CredentialsService{ DB: db, cache: make(map[string]string), } service := NewEmailService(db, credsSvc) ctx := context.Background() t.Run("returns error when AMQP URL not configured", func(t *testing.T) { // Return empty/null amqp_url mock.ExpectQuery("SELECT amqp_url FROM email_settings"). WillReturnRows(sqlmock.NewRows([]string{"amqp_url"}).AddRow(sql.NullString{Valid: false})) err := service.SendTemplateEmail(ctx, "test@example.com", "welcome", map[string]interface{}{"name": "Test"}) if err == nil { t.Error("Expected error for missing AMQP URL, got nil") } if err.Error() != "AMQP URL not configured in email_settings" { t.Errorf("Unexpected error message: %v", err) } if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("Unmet expectations: %v", err) } }) } func TestEmailService_SendTemplateEmail_DBError(t *testing.T) { db, mock, err := sqlmock.New() if err != nil { t.Fatalf("Failed to create mock db: %v", err) } defer db.Close() credsSvc := &CredentialsService{ DB: db, cache: make(map[string]string), } service := NewEmailService(db, credsSvc) ctx := context.Background() t.Run("handles db error gracefully", func(t *testing.T) { // Return error on query mock.ExpectQuery("SELECT amqp_url FROM email_settings"). WillReturnError(sql.ErrConnDone) // Should still fail due to empty URL after logging error err := service.SendTemplateEmail(ctx, "test@example.com", "welcome", nil) if err == nil { t.Error("Expected error, got nil") } if err := mock.ExpectationsWereMet(); err != nil { t.Errorf("Unmet expectations: %v", err) } }) } func TestEmailJob_Struct(t *testing.T) { job := EmailJob{ To: "user@example.com", Template: "password_reset", Variables: map[string]interface{}{"reset_link": "https://example.com/reset"}, } if job.To != "user@example.com" { t.Errorf("Expected To='user@example.com', got '%s'", job.To) } if job.Template != "password_reset" { t.Errorf("Expected Template='password_reset', got '%s'", job.Template) } if job.Variables["reset_link"] != "https://example.com/reset" { t.Errorf("Expected reset_link variable to be set") } }