package eventbus import ( "context" "testing" "time" "lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope" ) func TestAsyncSinkPublishRawReturnsAfterQueueing(t *testing.T) { delegate := newBlockingSink() sink := NewAsyncSink(delegate, AsyncConfig{QueueSize: 1, Workers: 1, OperationTimeout: time.Second}) start := time.Now() if err := sink.PublishRaw(context.Background(), envelope.FrameEnvelope{Protocol: envelope.ProtocolGB32960, VIN: "LNBSCB3D4R1234567"}); err != nil { t.Fatalf("PublishRaw() error = %v", err) } if elapsed := time.Since(start); elapsed > 100*time.Millisecond { t.Fatalf("PublishRaw() blocked for %s, want quick queueing", elapsed) } select { case <-delegate.rawStarted: case <-time.After(time.Second): t.Fatal("delegate raw publish was not started") } delegate.release() if err := sink.Close(); err != nil { t.Fatalf("Close() error = %v", err) } } func TestAsyncSinkPublishesInFIFOOrderWithSingleWorker(t *testing.T) { delegate := &orderedSink{} sink := NewAsyncSink(delegate, AsyncConfig{QueueSize: 4, Workers: 1, OperationTimeout: time.Second}) env := envelope.FrameEnvelope{Protocol: envelope.ProtocolJT808, Phone: "13307795425"} if err := sink.PublishRaw(context.Background(), env); err != nil { t.Fatalf("PublishRaw() error = %v", err) } if err := sink.PublishUnified(context.Background(), env); err != nil { t.Fatalf("PublishUnified() error = %v", err) } if err := sink.Close(); err != nil { t.Fatalf("Close() error = %v", err) } if got, want := delegate.calls, []string{"raw", "unified"}; len(got) != len(want) || got[0] != want[0] || got[1] != want[1] { t.Fatalf("calls = %#v, want %#v", got, want) } } type blockingSink struct { rawStarted chan struct{} releaseRaw chan struct{} } func newBlockingSink() *blockingSink { return &blockingSink{ rawStarted: make(chan struct{}), releaseRaw: make(chan struct{}), } } func (s *blockingSink) PublishRaw(context.Context, envelope.FrameEnvelope) error { close(s.rawStarted) <-s.releaseRaw return nil } func (s *blockingSink) PublishUnified(context.Context, envelope.FrameEnvelope) error { return nil } func (s *blockingSink) PublishFields(context.Context, envelope.FrameEnvelope) error { return nil } func (s *blockingSink) Close() error { s.release() return nil } func (s *blockingSink) release() { select { case <-s.releaseRaw: default: close(s.releaseRaw) } } type orderedSink struct { calls []string } func (s *orderedSink) PublishRaw(context.Context, envelope.FrameEnvelope) error { s.calls = append(s.calls, "raw") return nil } func (s *orderedSink) PublishUnified(context.Context, envelope.FrameEnvelope) error { s.calls = append(s.calls, "unified") return nil } func (s *orderedSink) PublishFields(context.Context, envelope.FrameEnvelope) error { s.calls = append(s.calls, "fields") return nil } func (s *orderedSink) Close() error { return nil }