fix: inject Slack URL validator via constructor option instead of field mutation

This commit is contained in:
GitHub Actions
2026-03-15 11:27:51 +00:00
parent 8670cdfd2b
commit 72598ed2ce
3 changed files with 28 additions and 23 deletions

View File

@@ -33,14 +33,29 @@ type NotificationService struct {
validateSlackURL func(string) error
}
func NewNotificationService(db *gorm.DB, mailService MailServiceInterface) *NotificationService {
return &NotificationService{
// NotificationServiceOption configures a NotificationService at construction time.
type NotificationServiceOption func(*NotificationService)
// WithSlackURLValidator overrides the Slack webhook URL validator. Intended for use
// in tests that need to bypass real URL validation without mutating shared state.
func WithSlackURLValidator(fn func(string) error) NotificationServiceOption {
return func(s *NotificationService) {
s.validateSlackURL = fn
}
}
func NewNotificationService(db *gorm.DB, mailService MailServiceInterface, opts ...NotificationServiceOption) *NotificationService {
s := &NotificationService{
DB: db,
httpWrapper: notifications.NewNotifyHTTPWrapper(),
mailService: mailService,
telegramAPIBaseURL: "https://api.telegram.org",
validateSlackURL: validateSlackWebhookURL,
}
for _, opt := range opts {
opt(s)
}
return s
}
var discordWebhookRegex = regexp.MustCompile(`^https://discord(?:app)?\.com/api/webhooks/(\d+)/([a-zA-Z0-9_-]+)`)

View File

@@ -193,8 +193,7 @@ func TestSendJSONPayload_Slack(t *testing.T) {
db, err := gorm.Open(sqlite.Open("file::memory:"), &gorm.Config{})
require.NoError(t, err)
svc := NewNotificationService(db, nil)
svc.validateSlackURL = func(rawURL string) error { return nil }
svc := NewNotificationService(db, nil, WithSlackURLValidator(func(string) error { return nil }))
provider := models.NotificationProvider{
Type: "slack",

View File

@@ -1453,8 +1453,7 @@ func TestSendJSONPayload_ServiceSpecificValidation(t *testing.T) {
})
t.Run("slack_requires_text_or_blocks", func(t *testing.T) {
defer func() { svc.validateSlackURL = validateSlackWebhookURL }()
svc.validateSlackURL = func(rawURL string) error { return nil }
subSvc := NewNotificationService(db, nil, WithSlackURLValidator(func(string) error { return nil }))
provider := models.NotificationProvider{
Type: "slack",
@@ -1470,7 +1469,7 @@ func TestSendJSONPayload_ServiceSpecificValidation(t *testing.T) {
"EventType": "test",
}
err := svc.sendJSONPayload(context.Background(), provider, data)
err := subSvc.sendJSONPayload(context.Background(), provider, data)
require.Error(t, err)
assert.Contains(t, err.Error(), "slack payload requires 'text' or 'blocks' field")
})
@@ -1480,9 +1479,7 @@ func TestSendJSONPayload_ServiceSpecificValidation(t *testing.T) {
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
defer func() { svc.validateSlackURL = validateSlackWebhookURL }()
svc.validateSlackURL = func(rawURL string) error { return nil }
subSvc := NewNotificationService(db, nil, WithSlackURLValidator(func(string) error { return nil }))
provider := models.NotificationProvider{
Type: "slack",
@@ -1498,7 +1495,7 @@ func TestSendJSONPayload_ServiceSpecificValidation(t *testing.T) {
"EventType": "test",
}
err := svc.sendJSONPayload(context.Background(), provider, data)
err := subSvc.sendJSONPayload(context.Background(), provider, data)
require.NoError(t, err)
})
@@ -1507,9 +1504,7 @@ func TestSendJSONPayload_ServiceSpecificValidation(t *testing.T) {
w.WriteHeader(http.StatusOK)
}))
defer server.Close()
defer func() { svc.validateSlackURL = validateSlackWebhookURL }()
svc.validateSlackURL = func(rawURL string) error { return nil }
subSvc := NewNotificationService(db, nil, WithSlackURLValidator(func(string) error { return nil }))
provider := models.NotificationProvider{
Type: "slack",
@@ -1525,7 +1520,7 @@ func TestSendJSONPayload_ServiceSpecificValidation(t *testing.T) {
"EventType": "test",
}
err := svc.sendJSONPayload(context.Background(), provider, data)
err := subSvc.sendJSONPayload(context.Background(), provider, data)
require.NoError(t, err)
})
@@ -3306,8 +3301,7 @@ func TestNotificationService_TestProvider_Slack(t *testing.T) {
}))
defer server.Close()
svc := NewNotificationService(db, nil)
svc.validateSlackURL = func(rawURL string) error { return nil }
svc := NewNotificationService(db, nil, WithSlackURLValidator(func(string) error { return nil }))
provider := models.NotificationProvider{
Type: "slack",
@@ -3337,8 +3331,7 @@ func TestNotificationService_SendExternal_Slack(t *testing.T) {
}))
defer server.Close()
svc := NewNotificationService(db, nil)
svc.validateSlackURL = func(rawURL string) error { return nil }
svc := NewNotificationService(db, nil, WithSlackURLValidator(func(string) error { return nil }))
provider := models.NotificationProvider{
Name: "Slack E2E",
@@ -3374,8 +3367,7 @@ func TestNotificationService_Slack_PayloadNormalizesMessageToText(t *testing.T)
}))
defer server.Close()
svc := NewNotificationService(db, nil)
svc.validateSlackURL = func(rawURL string) error { return nil }
svc := NewNotificationService(db, nil, WithSlackURLValidator(func(string) error { return nil }))
provider := models.NotificationProvider{
Type: "slack",
@@ -3402,8 +3394,7 @@ func TestNotificationService_Slack_PayloadNormalizesMessageToText(t *testing.T)
func TestNotificationService_Slack_PayloadRequiresTextOrBlocks(t *testing.T) {
db := setupNotificationTestDB(t)
svc := NewNotificationService(db, nil)
svc.validateSlackURL = func(rawURL string) error { return nil }
svc := NewNotificationService(db, nil, WithSlackURLValidator(func(string) error { return nil }))
provider := models.NotificationProvider{
Type: "slack",