package delivery import ( "context" "log/slog" "net" "net/http" "time" "gorm.io/gorm" "sneak.berlin/go/webhooker/internal/database" ) // Exported constants for test access. const ( ExportDeliveryChannelSize = deliveryChannelSize ExportRetryChannelSize = retryChannelSize ExportDefaultFailureThreshold = defaultFailureThreshold ExportDefaultCooldown = defaultCooldown ) // ExportIsBlockedIP exposes isBlockedIP for testing. func ExportIsBlockedIP(ip net.IP) bool { return isBlockedIP(ip) } // ExportBlockedNetworks exposes blockedNetworks. func ExportBlockedNetworks() []*net.IPNet { return blockedNetworks } // ExportIsForwardableHeader exposes isForwardableHeader. func ExportIsForwardableHeader(name string) bool { return isForwardableHeader(name) } // ExportTruncate exposes truncate for testing. func ExportTruncate(s string, maxLen int) string { return truncate(s, maxLen) } // ExportDeliverHTTP exposes deliverHTTP for testing. func (e *Engine) ExportDeliverHTTP( ctx context.Context, webhookDB *gorm.DB, d *database.Delivery, task *Task, ) { e.deliverHTTP(ctx, webhookDB, d, task) } // ExportDeliverDatabase exposes deliverDatabase. func (e *Engine) ExportDeliverDatabase( webhookDB *gorm.DB, d *database.Delivery, ) { e.deliverDatabase(webhookDB, d) } // ExportDeliverLog exposes deliverLog for testing. func (e *Engine) ExportDeliverLog( webhookDB *gorm.DB, d *database.Delivery, ) { e.deliverLog(webhookDB, d) } // ExportDeliverSlack exposes deliverSlack for testing. func (e *Engine) ExportDeliverSlack( ctx context.Context, webhookDB *gorm.DB, d *database.Delivery, ) { e.deliverSlack(ctx, webhookDB, d) } // ExportProcessNewTask exposes processNewTask. func (e *Engine) ExportProcessNewTask( ctx context.Context, task *Task, ) { e.processNewTask(ctx, task) } // ExportProcessRetryTask exposes processRetryTask. func (e *Engine) ExportProcessRetryTask( ctx context.Context, task *Task, ) { e.processRetryTask(ctx, task) } // ExportProcessDelivery exposes processDelivery. func (e *Engine) ExportProcessDelivery( ctx context.Context, webhookDB *gorm.DB, d *database.Delivery, task *Task, ) { e.processDelivery(ctx, webhookDB, d, task) } // ExportGetCircuitBreaker exposes getCircuitBreaker. func (e *Engine) ExportGetCircuitBreaker( targetID string, ) *CircuitBreaker { return e.getCircuitBreaker(targetID) } // ExportParseHTTPConfig exposes parseHTTPConfig. func (e *Engine) ExportParseHTTPConfig( configJSON string, ) (*HTTPTargetConfig, error) { return e.parseHTTPConfig(configJSON) } // ExportParseSlackConfig exposes parseSlackConfig. func (e *Engine) ExportParseSlackConfig( configJSON string, ) (*SlackTargetConfig, error) { return e.parseSlackConfig(configJSON) } // ExportDoHTTPRequest exposes doHTTPRequest. func (e *Engine) ExportDoHTTPRequest( ctx context.Context, cfg *HTTPTargetConfig, event *database.Event, ) (int, string, int64, error) { return e.doHTTPRequest(ctx, cfg, event) } // ExportScheduleRetry exposes scheduleRetry. func (e *Engine) ExportScheduleRetry( task Task, delay time.Duration, ) { e.scheduleRetry(task, delay) } // ExportRecoverPendingDeliveries exposes // recoverPendingDeliveries. func (e *Engine) ExportRecoverPendingDeliveries( ctx context.Context, webhookDB *gorm.DB, webhookID string, ) { e.recoverPendingDeliveries( ctx, webhookDB, webhookID, ) } // ExportRecoverWebhookDeliveries exposes // recoverWebhookDeliveries. func (e *Engine) ExportRecoverWebhookDeliveries( ctx context.Context, webhookID string, ) { e.recoverWebhookDeliveries(ctx, webhookID) } // ExportRecoverInFlight exposes recoverInFlight. func (e *Engine) ExportRecoverInFlight( ctx context.Context, ) { e.recoverInFlight(ctx) } // ExportStart exposes start for testing. func (e *Engine) ExportStart(ctx context.Context) { e.start(ctx) } // ExportStop exposes stop for testing. func (e *Engine) ExportStop() { e.stop() } // ExportDeliveryCh returns the delivery channel. func (e *Engine) ExportDeliveryCh() chan Task { return e.deliveryCh } // ExportRetryCh returns the retry channel. func (e *Engine) ExportRetryCh() chan Task { return e.retryCh } // NewTestEngine creates an Engine for unit tests without // database dependencies. func NewTestEngine( log *slog.Logger, client *http.Client, workers int, ) *Engine { return &Engine{ log: log, client: client, deliveryCh: make(chan Task, deliveryChannelSize), retryCh: make(chan Task, retryChannelSize), workers: workers, } } // NewTestEngineSmallRetry creates an Engine with a tiny // retry channel buffer for overflow testing. func NewTestEngineSmallRetry( log *slog.Logger, ) *Engine { return &Engine{ log: log, retryCh: make(chan Task, 1), } } // NewTestEngineWithDB creates an Engine with a real // database and dbManager for integration tests. func NewTestEngineWithDB( db *database.Database, dbMgr *database.WebhookDBManager, log *slog.Logger, client *http.Client, workers int, ) *Engine { return &Engine{ database: db, dbManager: dbMgr, log: log, client: client, deliveryCh: make(chan Task, deliveryChannelSize), retryCh: make(chan Task, retryChannelSize), workers: workers, } } // NewTestCircuitBreaker creates a CircuitBreaker with // custom settings for testing. func NewTestCircuitBreaker( threshold int, cooldown time.Duration, ) *CircuitBreaker { return &CircuitBreaker{ state: CircuitClosed, threshold: threshold, cooldown: cooldown, } }