11package events
22
33import (
4+ "bytes"
45 "context"
56 "fmt"
7+ "strconv"
68 "sync"
79 "sync/atomic"
810 "time"
@@ -110,24 +112,32 @@ var _ = DescribeTable("CappedExponentialBinaryDelay",
110112 Entry ("cap: 1m; tries: 20" , time .Minute , 20 , time .Minute ),
111113)
112114
113- var _ = Describe ("DelayingConsumer " , func () {
115+ var _ = Describe ("NotBeforeConsumer " , func () {
114116 Describe ("Consume" , func () {
115- var testMsg = & sarama.ConsumerMessage {
116- Topic : "test.topic" ,
117+ var newTestMsg = func (notBefore time.Time ) * sarama.ConsumerMessage {
118+ headers := []* sarama.RecordHeader {}
119+ if ! notBefore .IsZero () {
120+ headers = append (headers , & sarama.RecordHeader {
121+ Key : HeaderNotBefore ,
122+ Value : []byte (notBefore .Format (NotBeforeTimeFormat )),
123+ })
124+ }
125+ return & sarama.ConsumerMessage {Topic : "test.topic" , Headers : headers }
117126 }
118127
119- It ("delays by the configured duration " , func () {
128+ It ("delays based on the x-tidepool-not-before header " , func () {
120129 logger := newTestDevlog ()
121130 testDelay := 10 * time .Millisecond
122131 ctx := context .Background ()
123132 start := time .Now ()
124- dc := & DelayingConsumer {
133+ notBefore := start .Add (testDelay )
134+ msg := newTestMsg (notBefore )
135+ dc := & NotBeforeConsumer {
125136 Consumer : & mockSaramaMessageConsumer {Logger : logger },
126- Delay : testDelay ,
127137 Logger : logger ,
128138 }
129139
130- err := dc .Consume (ctx , nil , testMsg )
140+ err := dc .Consume (ctx , nil , msg )
131141
132142 Expect (err ).To (BeNil ())
133143 Expect (time .Since (start )).To (BeNumerically (">" , testDelay ))
@@ -137,9 +147,10 @@ var _ = Describe("DelayingConsumer", func() {
137147 logger := newTestDevlog ()
138148 testDelay := 10 * time .Millisecond
139149 abortAfter := 1 * time .Millisecond
140- dc := & DelayingConsumer {
150+ notBefore := time .Now ().Add (testDelay )
151+ msg := newTestMsg (notBefore )
152+ dc := & NotBeforeConsumer {
141153 Consumer : & mockSaramaMessageConsumer {Delay : time .Minute , Logger : logger },
142- Delay : testDelay ,
143154 Logger : logger ,
144155 }
145156 ctx , cancel := context .WithCancel (context .Background ())
@@ -149,7 +160,7 @@ var _ = Describe("DelayingConsumer", func() {
149160 }()
150161 start := time .Now ()
151162
152- err := dc .Consume (ctx , nil , testMsg )
163+ err := dc .Consume (ctx , nil , msg )
153164
154165 Expect (err ).To (BeNil ())
155166 Expect (time .Since (start )).To (BeNumerically (">" , abortAfter ))
@@ -158,14 +169,14 @@ var _ = Describe("DelayingConsumer", func() {
158169 })
159170})
160171
161- var _ = Describe ("ShiftingConsumer " , func () {
172+ var _ = Describe ("CascadingConsumer " , func () {
162173 Describe ("Consume" , func () {
163174 var testMsg = & sarama.ConsumerMessage {
164175 Topic : "test.topic" ,
165176 }
166177
167178 Context ("on failure" , func () {
168- It ("shifts topics" , func () {
179+ It ("cascades topics" , func () {
169180 t := GinkgoT ()
170181 logger := newTestDevlog ()
171182 ctx := context .Background ()
@@ -195,6 +206,102 @@ var _ = Describe("ShiftingConsumer", func() {
195206 Expect (mockProducer .Close ()).To (Succeed ())
196207 Expect (err ).To (BeNil ())
197208 })
209+
210+ It ("increments the failures header" , func () {
211+ t := GinkgoT ()
212+ logger := newTestDevlog ()
213+ ctx := context .Background ()
214+ testConfig := mocks .NewTestConfig ()
215+ mockProducer := mocks .NewAsyncProducer (t , testConfig )
216+ msg := & sarama.ConsumerMessage {
217+ Headers : []* sarama.RecordHeader {
218+ {
219+ Key : HeaderFailures , Value : []byte ("3" ),
220+ },
221+ },
222+ }
223+ nextTopic := "text-next"
224+ sc := & CascadingConsumer {
225+ Consumer : & mockSaramaMessageConsumer {
226+ Err : fmt .Errorf ("test error" ),
227+ Logger : logger ,
228+ },
229+ NextTopic : nextTopic ,
230+ Producer : mockProducer ,
231+ Logger : logger ,
232+ }
233+
234+ cf := func (msg * sarama.ProducerMessage ) error {
235+ failures := 0
236+ for _ , header := range msg .Headers {
237+ if ! bytes .Equal (header .Key , HeaderFailures ) {
238+ continue
239+ }
240+ parsed , err := strconv .ParseInt (string (header .Value ), 10 , 32 )
241+ Expect (err ).To (Succeed ())
242+ failures = int (parsed )
243+ if failures != 4 {
244+ return fmt .Errorf ("expected failures == 4, got %d" , failures )
245+ }
246+ return nil
247+ }
248+ return fmt .Errorf ("expected failures header wasn't found" )
249+ }
250+ mockProducer .ExpectInputWithMessageCheckerFunctionAndSucceed (cf )
251+
252+ err := sc .Consume (ctx , nil , msg )
253+ Expect (mockProducer .Close ()).To (Succeed ())
254+ Expect (err ).To (BeNil ())
255+ })
256+
257+ It ("updates the not before header" , func () {
258+ t := GinkgoT ()
259+ logger := newTestDevlog ()
260+ ctx := context .Background ()
261+ testConfig := mocks .NewTestConfig ()
262+ mockProducer := mocks .NewAsyncProducer (t , testConfig )
263+ msg := & sarama.ConsumerMessage {
264+ Headers : []* sarama.RecordHeader {
265+ {
266+ Key : HeaderFailures , Value : []byte ("2" ),
267+ },
268+ },
269+ }
270+ nextTopic := "text-next"
271+ sc := & CascadingConsumer {
272+ Consumer : & mockSaramaMessageConsumer {
273+ Err : fmt .Errorf ("test error" ),
274+ Logger : logger ,
275+ },
276+ NextTopic : nextTopic ,
277+ Producer : mockProducer ,
278+ Logger : logger ,
279+ }
280+
281+ cf := func (msg * sarama.ProducerMessage ) error {
282+ for _ , header := range msg .Headers {
283+ if ! bytes .Equal (header .Key , HeaderNotBefore ) {
284+ continue
285+ }
286+ parsed , err := time .Parse (NotBeforeTimeFormat , string (header .Value ))
287+ if err != nil {
288+ return err
289+ }
290+ until := time .Until (parsed )
291+ delta := 10 * time .Millisecond
292+ if until < 2 * time .Second - delta || until > 2 * time .Second + delta {
293+ return fmt .Errorf ("expected 2 seconds' delay, got: %s" , until )
294+ }
295+ return nil
296+ }
297+ return fmt .Errorf ("expected failures header wasn't found" )
298+ }
299+ mockProducer .ExpectInputWithMessageCheckerFunctionAndSucceed (cf )
300+
301+ err := sc .Consume (ctx , nil , msg )
302+ Expect (mockProducer .Close ()).To (Succeed ())
303+ Expect (err ).To (BeNil ())
304+ })
198305 })
199306
200307 Context ("on success" , func () {
@@ -244,8 +351,8 @@ var _ = Describe("ShiftingConsumer", func() {
244351 })
245352})
246353
247- var _ = Describe ("ShiftingSaramaEventsRunner " , func () {
248- It ("shifts through configured delays" , func () {
354+ var _ = Describe ("CascadingSaramaEventsRunner " , func () {
355+ It ("cascades through configured delays" , func () {
249356 ctx , cancel := context .WithTimeout (context .Background (), 3 * time .Second )
250357 defer cancel ()
251358 testDelays := []time.Duration {0 , 1 , 2 , 3 , 5 }
@@ -256,7 +363,7 @@ var _ = Describe("ShiftingSaramaEventsRunner", func() {
256363 Logger : testLogger ,
257364 }
258365 testConfig := SaramaRunnerConfig {
259- Topics : []string {"test.shifting " },
366+ Topics : []string {"test.cascading " },
260367 MessageConsumer : testMessageConsumer ,
261368 Sarama : mocks .NewTestConfig (),
262369 }
@@ -338,7 +445,7 @@ var _ = Describe("ShiftingSaramaEventsRunner", func() {
338445 })
339446})
340447
341- // testSaramaBuilders injects mocks into the ShiftingSaramaEventsRunner
448+ // testSaramaBuilders injects mocks into the CascadingSaramaEventsRunner
342449type testSaramaBuilders struct {
343450 consumerGroup func ([]string , string , * sarama.Config ) (sarama.ConsumerGroup , error )
344451 producer func ([]string , * sarama.Config ) (sarama.AsyncProducer , error )
0 commit comments