1
1
package events
2
2
3
3
import (
4
+ "bytes"
4
5
"context"
5
6
"fmt"
7
+ "strconv"
6
8
"sync"
7
9
"sync/atomic"
8
10
"time"
@@ -110,24 +112,32 @@ var _ = DescribeTable("CappedExponentialBinaryDelay",
110
112
Entry ("cap: 1m; tries: 20" , time .Minute , 20 , time .Minute ),
111
113
)
112
114
113
- var _ = Describe ("DelayingConsumer " , func () {
115
+ var _ = Describe ("NotBeforeConsumer " , func () {
114
116
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 }
117
126
}
118
127
119
- It ("delays by the configured duration " , func () {
128
+ It ("delays based on the x-tidepool-not-before header " , func () {
120
129
logger := newTestDevlog ()
121
130
testDelay := 10 * time .Millisecond
122
131
ctx := context .Background ()
123
132
start := time .Now ()
124
- dc := & DelayingConsumer {
133
+ notBefore := start .Add (testDelay )
134
+ msg := newTestMsg (notBefore )
135
+ dc := & NotBeforeConsumer {
125
136
Consumer : & mockSaramaMessageConsumer {Logger : logger },
126
- Delay : testDelay ,
127
137
Logger : logger ,
128
138
}
129
139
130
- err := dc .Consume (ctx , nil , testMsg )
140
+ err := dc .Consume (ctx , nil , msg )
131
141
132
142
Expect (err ).To (BeNil ())
133
143
Expect (time .Since (start )).To (BeNumerically (">" , testDelay ))
@@ -137,9 +147,10 @@ var _ = Describe("DelayingConsumer", func() {
137
147
logger := newTestDevlog ()
138
148
testDelay := 10 * time .Millisecond
139
149
abortAfter := 1 * time .Millisecond
140
- dc := & DelayingConsumer {
150
+ notBefore := time .Now ().Add (testDelay )
151
+ msg := newTestMsg (notBefore )
152
+ dc := & NotBeforeConsumer {
141
153
Consumer : & mockSaramaMessageConsumer {Delay : time .Minute , Logger : logger },
142
- Delay : testDelay ,
143
154
Logger : logger ,
144
155
}
145
156
ctx , cancel := context .WithCancel (context .Background ())
@@ -149,7 +160,7 @@ var _ = Describe("DelayingConsumer", func() {
149
160
}()
150
161
start := time .Now ()
151
162
152
- err := dc .Consume (ctx , nil , testMsg )
163
+ err := dc .Consume (ctx , nil , msg )
153
164
154
165
Expect (err ).To (BeNil ())
155
166
Expect (time .Since (start )).To (BeNumerically (">" , abortAfter ))
@@ -158,14 +169,14 @@ var _ = Describe("DelayingConsumer", func() {
158
169
})
159
170
})
160
171
161
- var _ = Describe ("ShiftingConsumer " , func () {
172
+ var _ = Describe ("CascadingConsumer " , func () {
162
173
Describe ("Consume" , func () {
163
174
var testMsg = & sarama.ConsumerMessage {
164
175
Topic : "test.topic" ,
165
176
}
166
177
167
178
Context ("on failure" , func () {
168
- It ("shifts topics" , func () {
179
+ It ("cascades topics" , func () {
169
180
t := GinkgoT ()
170
181
logger := newTestDevlog ()
171
182
ctx := context .Background ()
@@ -195,6 +206,102 @@ var _ = Describe("ShiftingConsumer", func() {
195
206
Expect (mockProducer .Close ()).To (Succeed ())
196
207
Expect (err ).To (BeNil ())
197
208
})
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
+ })
198
305
})
199
306
200
307
Context ("on success" , func () {
@@ -244,8 +351,8 @@ var _ = Describe("ShiftingConsumer", func() {
244
351
})
245
352
})
246
353
247
- var _ = Describe ("ShiftingSaramaEventsRunner " , func () {
248
- It ("shifts through configured delays" , func () {
354
+ var _ = Describe ("CascadingSaramaEventsRunner " , func () {
355
+ It ("cascades through configured delays" , func () {
249
356
ctx , cancel := context .WithTimeout (context .Background (), 3 * time .Second )
250
357
defer cancel ()
251
358
testDelays := []time.Duration {0 , 1 , 2 , 3 , 5 }
@@ -256,7 +363,7 @@ var _ = Describe("ShiftingSaramaEventsRunner", func() {
256
363
Logger : testLogger ,
257
364
}
258
365
testConfig := SaramaRunnerConfig {
259
- Topics : []string {"test.shifting " },
366
+ Topics : []string {"test.cascading " },
260
367
MessageConsumer : testMessageConsumer ,
261
368
Sarama : mocks .NewTestConfig (),
262
369
}
@@ -338,7 +445,7 @@ var _ = Describe("ShiftingSaramaEventsRunner", func() {
338
445
})
339
446
})
340
447
341
- // testSaramaBuilders injects mocks into the ShiftingSaramaEventsRunner
448
+ // testSaramaBuilders injects mocks into the CascadingSaramaEventsRunner
342
449
type testSaramaBuilders struct {
343
450
consumerGroup func ([]string , string , * sarama.Config ) (sarama.ConsumerGroup , error )
344
451
producer func ([]string , * sarama.Config ) (sarama.AsyncProducer , error )
0 commit comments