feat(go): decouple gateway publish with async sink
This commit is contained in:
105
go/vehicle-gateway/internal/eventbus/async_sink_test.go
Normal file
105
go/vehicle-gateway/internal/eventbus/async_sink_test.go
Normal file
@@ -0,0 +1,105 @@
|
||||
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) 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) Close() error {
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user