test: EventPublisher publish accepted/rejected/timeout with observer assertions
This commit is contained in:
+11
-4
@@ -55,6 +55,7 @@ type pendingEntry struct {
|
|||||||
eventJSON []byte
|
eventJSON []byte
|
||||||
sent bool
|
sent bool
|
||||||
result chan publishResult
|
result chan publishResult
|
||||||
|
mu sync.Mutex
|
||||||
once sync.Once
|
once sync.Once
|
||||||
timer *time.Timer
|
timer *time.Timer
|
||||||
}
|
}
|
||||||
@@ -138,18 +139,22 @@ func (p *EventPublisher) Close() {
|
|||||||
p.wg.Wait()
|
p.wg.Wait()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// trySend sends the EVENT envelope. It does not modify entry.sent — callers
|
||||||
|
// are responsible for setting it under p.mu before and/or after this call.
|
||||||
func (p *EventPublisher) trySend(entry *pendingEntry) error {
|
func (p *EventPublisher) trySend(entry *pendingEntry) error {
|
||||||
|
entry.mu.Lock()
|
||||||
|
defer entry.mu.Unlock()
|
||||||
|
if entry.sent {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
err := p.envoy.Send([]byte(envelope.EncloseEvent(entry.eventJSON)))
|
err := p.envoy.Send([]byte(envelope.EncloseEvent(entry.eventJSON)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.envoy.Observer().Record(p.envoy.PeerID(),
|
p.envoy.Observer().Record(p.envoy.PeerID(),
|
||||||
PublishSendFailed{EventID: entry.eventID, Err: err, At: time.Now()})
|
PublishSendFailed{EventID: entry.eventID, Err: err, At: time.Now()})
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
p.mu.Lock()
|
|
||||||
entry.sent = true
|
entry.sent = true
|
||||||
p.mu.Unlock()
|
|
||||||
|
|
||||||
p.envoy.Observer().Record(p.envoy.PeerID(),
|
p.envoy.Observer().Record(p.envoy.PeerID(),
|
||||||
PublishDispatched{EventID: entry.eventID, At: time.Now()})
|
PublishDispatched{EventID: entry.eventID, At: time.Now()})
|
||||||
return nil
|
return nil
|
||||||
@@ -225,7 +230,9 @@ func (p *EventPublisher) handleEvents() {
|
|||||||
case EventDisconnected:
|
case EventDisconnected:
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
for _, e := range p.pending {
|
for _, e := range p.pending {
|
||||||
|
e.mu.Lock()
|
||||||
e.sent = false
|
e.sent = false
|
||||||
|
e.mu.Unlock()
|
||||||
}
|
}
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
}
|
}
|
||||||
|
|||||||
+37
-4
@@ -9,7 +9,8 @@ import (
|
|||||||
|
|
||||||
func TestEventPublisher(t *testing.T) {
|
func TestEventPublisher(t *testing.T) {
|
||||||
t.Run("publish accepted", func(t *testing.T) {
|
t.Run("publish accepted", func(t *testing.T) {
|
||||||
p, envoy := newMockEnvoy(t)
|
obs := &mockObserver{}
|
||||||
|
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||||
p.connect()
|
p.connect()
|
||||||
|
|
||||||
pub := NewEventPublisher(envoy)
|
pub := NewEventPublisher(envoy)
|
||||||
@@ -50,10 +51,14 @@ func TestEventPublisher(t *testing.T) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}, "Publish did not return accepted result")
|
}, "Publish did not return accepted result")
|
||||||
|
|
||||||
|
assert.Len(t, EventsOf[PublishDispatched](obs), 1)
|
||||||
|
assert.Len(t, EventsOf[PublishAccepted](obs), 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("publish rejected", func(t *testing.T) {
|
t.Run("publish rejected", func(t *testing.T) {
|
||||||
p, envoy := newMockEnvoy(t)
|
obs := &mockObserver{}
|
||||||
|
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||||
p.connect()
|
p.connect()
|
||||||
|
|
||||||
pub := NewEventPublisher(envoy)
|
pub := NewEventPublisher(envoy)
|
||||||
@@ -94,11 +99,39 @@ func TestEventPublisher(t *testing.T) {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}, "Publish did not return rejected result")
|
}, "Publish did not return rejected result")
|
||||||
|
|
||||||
|
assert.Len(t, EventsOf[PublishDispatched](obs), 1)
|
||||||
|
assert.Len(t, EventsOf[PublishRejected](obs), 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("publish timeout", func(t *testing.T) {
|
t.Run("publish timeout", func(t *testing.T) {
|
||||||
// pub.Publish(id, json, 75*time.Millisecond) — do not feed OK
|
obs := &mockObserver{}
|
||||||
// assert err != nil (timeout error) after ~75ms
|
p, envoy := newMockEnvoy(t, WithEmbassyObserver(obs))
|
||||||
|
p.connect()
|
||||||
|
|
||||||
|
pub := NewEventPublisher(envoy)
|
||||||
|
t.Cleanup(pub.Close)
|
||||||
|
|
||||||
|
const id = "cccc3333"
|
||||||
|
eventJSON := []byte(`{"id":"cccc3333","kind":1}`)
|
||||||
|
|
||||||
|
ch := make(chan error, 1)
|
||||||
|
go func() {
|
||||||
|
_, _, err := pub.Publish(id, eventJSON, NegativeTestTimeout)
|
||||||
|
ch <- err
|
||||||
|
}()
|
||||||
|
|
||||||
|
Eventually(t, func() bool {
|
||||||
|
select {
|
||||||
|
case err := <-ch:
|
||||||
|
return err != nil
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}, "Publish did not return a timeout error")
|
||||||
|
|
||||||
|
assert.Len(t, EventsOf[PublishDispatched](obs), 1)
|
||||||
|
assert.Len(t, EventsOf[PublishTimeout](obs), 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("concurrent correlation", func(t *testing.T) {
|
t.Run("concurrent correlation", func(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user