veza/veza-backend-api/internal/eventbus/rabbitmq_test.go

62 lines
1.9 KiB
Go
Raw Normal View History

fix(eventbus): log RabbitMQ publish failures instead of silent drop Sixth item of the v1.0.6 backlog. `RabbitMQEventBus.Publish` returned the broker error but did not log it. Callers that wrap Publish in fire-and-forget (`_ = eb.Publish(...)`) lost events with zero trace — during an RMQ outage the backend would quietly shed work and operators only noticed via downstream symptoms (missing notifications, stuck async jobs, etc.). Changes * `Publish` now emits a structured ERROR with the exchange, routing_key, payload_bytes, content_type, and message_id on every broker failure. The function still returns the error so call-sites that actually check it keep working exactly as before. * The pre-existing "EventBus disabled" warning is kept but upgraded with payload_bytes so dashboards can quantify drops when RMQ is intentionally off (tests, dev without docker-compose --profile). * `infrastructure/eventbus/rabbitmq.go:PublishEvent` (the newer, event-sourcing variant) already had this pattern — this commit brings the legacy path in line. Tests * 2 new tests in `rabbitmq_test.go`: - disabled bus emits a single WARN with structured context and returns EventBusUnavailableError - nil logger path stays panic-free (legacy callers construct bus without a logger) * Broker-side failure path (closed channel) is not unit-tested here because amqp091-go types don't expose a mockable channel without spinning up a real RMQ — covered by the existing integration test in `internal/integration/e2e_test.go`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 18:50:51 +00:00
package eventbus
import (
"context"
"errors"
"testing"
amqp "github.com/rabbitmq/amqp091-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
"go.uber.org/zap/zaptest/observer"
)
// TestPublish_DisabledBusLogsWarnAndReturnsError verifies the "EventBus
// disabled" path emits a WARN with message-size context and still returns
// an EventBusUnavailableError so callers that care can notice.
func TestPublish_DisabledBusLogsWarnAndReturnsError(t *testing.T) {
core, observed := observer.New(zapcore.WarnLevel)
eb := &RabbitMQEventBus{
config: &RabbitMQConfig{Enable: false},
logger: zap.New(core),
IsEnabled: false,
}
err := eb.Publish(context.Background(), "veza.events", "track.uploaded", false, false, amqp.Publishing{
Body: []byte(`{"track_id":"abc"}`),
})
var unavail *EventBusUnavailableError
require.True(t, errors.As(err, &unavail), "disabled bus must return EventBusUnavailableError")
entries := observed.All()
require.Len(t, entries, 1)
assert.Equal(t, zapcore.WarnLevel, entries[0].Level)
assert.Contains(t, entries[0].Message, "disabled")
// Verify structured context so dashboards can group drops by
// exchange+routing_key.
fields := map[string]interface{}{}
for _, f := range entries[0].Context {
fields[f.Key] = f
}
assert.Contains(t, fields, "exchange")
assert.Contains(t, fields, "routing_key")
assert.Contains(t, fields, "payload_bytes")
}
// TestPublish_NilLoggerIsAllowed guards against the legacy callers that
// construct an EventBus without a logger — the method must stay panic-free.
func TestPublish_NilLoggerIsAllowed(t *testing.T) {
eb := &RabbitMQEventBus{
config: &RabbitMQConfig{Enable: false},
logger: nil,
IsEnabled: false,
}
assert.NotPanics(t, func() {
_ = eb.Publish(context.Background(), "x", "y", false, false, amqp.Publishing{Body: []byte("hi")})
})
}