package eventbus import ( "context" "errors" "testing" "time" "lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope" ) func TestRetryingSinkRetriesRawUntilSuccess(t *testing.T) { delegate := &flakySink{rawFailures: 1} sink := NewRetryingSink(delegate, RetryConfig{Attempts: 3}) err := sink.PublishRaw(context.Background(), envelope.FrameEnvelope{Protocol: envelope.ProtocolJT808}) if err != nil { t.Fatalf("PublishRaw() error = %v", err) } if delegate.rawCalls != 2 { t.Fatalf("raw calls = %d, want 2", delegate.rawCalls) } } func TestRetryingSinkReturnsLastErrorAfterAttempts(t *testing.T) { delegate := &flakySink{rawFailures: 3} sink := NewRetryingSink(delegate, RetryConfig{Attempts: 2}) err := sink.PublishRaw(context.Background(), envelope.FrameEnvelope{Protocol: envelope.ProtocolJT808}) if !errors.Is(err, errFlakyPublish) { t.Fatalf("PublishRaw() error = %v, want %v", err, errFlakyPublish) } if delegate.rawCalls != 2 { t.Fatalf("raw calls = %d, want 2", delegate.rawCalls) } } func TestRetryingSinkStopsWhenContextCanceledDuringBackoff(t *testing.T) { delegate := &flakySink{rawFailures: 10} sink := NewRetryingSink(delegate, RetryConfig{Attempts: 5, Backoff: time.Minute}) ctx, cancel := context.WithCancel(context.Background()) cancel() err := sink.PublishRaw(ctx, envelope.FrameEnvelope{Protocol: envelope.ProtocolJT808}) if !errors.Is(err, context.Canceled) { t.Fatalf("PublishRaw() error = %v, want context canceled", err) } if delegate.rawCalls != 1 { t.Fatalf("raw calls = %d, want 1", delegate.rawCalls) } } var errFlakyPublish = errors.New("publish failed") type flakySink struct { rawFailures int unifiedFailures int rawCalls int unifiedCalls int } func (s *flakySink) PublishRaw(context.Context, envelope.FrameEnvelope) error { s.rawCalls++ if s.rawCalls <= s.rawFailures { return errFlakyPublish } return nil } func (s *flakySink) PublishUnified(context.Context, envelope.FrameEnvelope) error { s.unifiedCalls++ if s.unifiedCalls <= s.unifiedFailures { return errFlakyPublish } return nil } func (s *flakySink) Close() error { return nil }