All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m20s
74 lines
2.9 KiB
Go
74 lines
2.9 KiB
Go
package outbox_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/break/junhong_cmp_fiber/internal/infrastructure/messaging/outbox"
|
|
"github.com/break/junhong_cmp_fiber/internal/model"
|
|
outboxquery "github.com/break/junhong_cmp_fiber/internal/query/outbox"
|
|
"github.com/break/junhong_cmp_fiber/internal/testutil"
|
|
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
|
)
|
|
|
|
func TestMetricsCoverBacklogRetriesFailuresAndThresholdAlerts(t *testing.T) {
|
|
db := testutil.NewPostgresTransaction(t)
|
|
testutil.CreateTemporaryOutboxTable(t, db)
|
|
repository := outbox.NewRepository()
|
|
now := time.Date(2026, 7, 23, 10, 0, 0, 0, time.UTC)
|
|
|
|
states := []struct {
|
|
id string
|
|
eventType string
|
|
status int
|
|
retries int
|
|
}{
|
|
{id: "metrics-pending", eventType: "example.a", status: constants.OutboxStatusPending},
|
|
{id: "metrics-delivering", eventType: "example.a", status: constants.OutboxStatusDelivering, retries: 1},
|
|
{id: "metrics-delivered", eventType: "example.b", status: constants.OutboxStatusDelivered},
|
|
{id: "metrics-failed", eventType: "example.b", status: constants.OutboxStatusFailed, retries: 3},
|
|
}
|
|
for _, state := range states {
|
|
event, err := repository.Append(context.Background(), db, outbox.Envelope{
|
|
EventID: state.id, EventType: state.eventType, AggregateType: "example", AggregateID: state.id,
|
|
ResourceType: "example", ResourceID: state.id, Payload: struct {
|
|
Visible bool `json:"visible"`
|
|
}{Visible: true},
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("准备指标事件失败:%v", err)
|
|
}
|
|
updates := map[string]any{"status": state.status, "retry_count": state.retries, "created_at": now.Add(-2 * time.Minute), "updated_at": now}
|
|
if state.status == constants.OutboxStatusDelivering {
|
|
updates["lease_owner"] = "dead-worker"
|
|
updates["lease_expires_at"] = now.Add(-time.Minute)
|
|
}
|
|
if state.status == constants.OutboxStatusDelivered {
|
|
updates["delivered_at"] = now.Add(-time.Minute)
|
|
}
|
|
if err := db.Model(&model.OutboxEvent{}).Where("id = ?", event.ID).Updates(updates).Error; err != nil {
|
|
t.Fatalf("设置指标事件状态失败:%v", err)
|
|
}
|
|
}
|
|
|
|
query := outboxquery.NewQuery(db, func() time.Time { return now })
|
|
metrics, err := query.GetMetrics(context.Background(), time.Hour)
|
|
if err != nil {
|
|
t.Fatalf("查询 Outbox 指标失败:%v", err)
|
|
}
|
|
if metrics.PendingCount != 1 || metrics.DeliveringCount != 1 || metrics.ExpiredLeaseCount != 1 ||
|
|
metrics.DeliveredInWindow != 1 || metrics.FinalFailedCount != 1 || metrics.OldestPendingAgeSecs != 120 {
|
|
t.Fatalf("Outbox 指标不完整:%+v", metrics)
|
|
}
|
|
if len(metrics.RetryDistribution) != 2 || len(metrics.BacklogByEventType) != 2 {
|
|
t.Fatalf("重试分布或事件类型积压不完整:%+v", metrics)
|
|
}
|
|
alerts := outboxquery.EvaluateAlerts(metrics, outboxquery.Thresholds{
|
|
PendingCount: 1, OldestPendingAge: time.Minute, ExpiredLeaseCount: 1, FinalFailedCount: 1,
|
|
})
|
|
if len(alerts) != 4 {
|
|
t.Fatalf("阈值告警数量错误:%+v", alerts)
|
|
}
|
|
}
|