@@ -85,8 +85,10 @@ func TestForcefulOwnershipChange(t *testing.T) {
8585 maxAge2 := 500 * time .Millisecond
8686 config2 := config .WithClientRecordMaxAge (& maxAge2 )
8787
88- kinsumer1 , err := NewWithInterfaces (k , dynamo , streamName , * applicationName , "client_1" , config1 )
89- kinsumer2 , err := NewWithInterfaces (k , dynamo , streamName , * applicationName , "client_2" , config2 )
88+ kinsumer1 , err1 := NewWithInterfaces (k , dynamo , streamName , * applicationName , "client_1" , config1 )
89+ kinsumer2 , err2 := NewWithInterfaces (k , dynamo , streamName , * applicationName , "client_2" , config2 )
90+ require .NoError (t , err1 )
91+ require .NoError (t , err2 )
9092
9193 desc , err := k .DescribeStream (& kinesis.DescribeStreamInput {
9294 StreamName : & streamName ,
@@ -103,33 +105,83 @@ func TestForcefulOwnershipChange(t *testing.T) {
103105
104106 kinsumer1ResultBeforeOwnerChange := readEventsToSlice (kinsumer1 .records , 5 * time .Second )
105107
106- assert .Equal (t , 2000 , len (kinsumer1ResultBeforeOwnerChange )) // Assert that we get 100 results
108+ assert .Equal (t , 2000 , len (kinsumer1ResultBeforeOwnerChange ))
107109
108110 kinsumer2 .waitGroup .Add (1 ) // consume will mark waitgroup as done on exit, so we add to it to avoid a panic
109111 go kinsumer2 .consume (shard )
110112
111- time .Sleep (1500 * time .Millisecond ) // Sleep for long enough that an ownership change will happen
113+ // Because we retain the shard if no data is coming through, we mimic a stale client scenario by sending data but not acking
114+ lastK1Record := & consumedRecord {
115+ checkpointer : & checkpointer {},
116+ }
117+ OwnerChangeLoop:
118+ for {
119+ spamStreamModified (t , k , 1 , streamName , 9999 )
120+ getEventLoop:
121+ select {
122+ case k1record := <- kinsumer1 .records : // if kinsumer1 gets it, don't ack
123+ lastK1Record = k1record
124+ break getEventLoop
125+ case k2record := <- kinsumer2 .records : // if kisumer2 gets it, ownership has changed. Ack then move on to the test.
126+ k2record .checkpointer .update (aws .StringValue (k2record .record .SequenceNumber ))
127+ // because this may be called with no genuine record to k1, we use the k2 sequence number.
128+ // this shouldn't make a difference since this commit will fail.
129+ lastK1Record .checkpointer .update (aws .StringValue (k2record .record .SequenceNumber )) // Ack the last k1 record we have, to instigate behaviour we would see for that client
130+ break OwnerChangeLoop
131+ }
132+ time .Sleep (120 * time .Millisecond )
133+ }
112134
113- go spamStreamModified (t , k , 2000 , streamName , 4000 )
135+ time .Sleep (300 * time .Millisecond )
136+
137+ go spamStreamModified (t , k , 1000 , streamName , 5000 )
114138
115139 resultsAfterOwnerChange := readMultipleToSlice ([]chan * consumedRecord {kinsumer1 .records , kinsumer2 .records }, 5 * time .Second )
116- kinsumer1ResultAfterOwnerChange := resultsAfterOwnerChange [0 ]
117- kinsumer2ResultAfterOwnerChange := resultsAfterOwnerChange [1 ]
140+ kinsumer1ResultAfterOwnerChangePreClean := resultsAfterOwnerChange [0 ]
141+ kinsumer2ResultAfterOwnerChangePreClean := resultsAfterOwnerChange [1 ]
142+
143+ // clean out the records we just used to instigate a change in ownership
144+ kinsumer1ResultAfterOwnerChange := make ([]* consumedRecord , 0 )
145+ for _ , val := range kinsumer1ResultAfterOwnerChangePreClean {
146+ if string (val .record .Data ) != "9999" {
147+ kinsumer1ResultAfterOwnerChange = append (kinsumer1ResultAfterOwnerChange , val )
148+ }
149+ }
150+
151+ kinsumer2ResultAfterOwnerChange := make ([]* consumedRecord , 0 )
152+ for _ , val := range kinsumer2ResultAfterOwnerChangePreClean {
153+ if string (val .record .Data ) != "9999" {
154+ kinsumer2ResultAfterOwnerChange = append (kinsumer2ResultAfterOwnerChange , val )
155+ }
156+ }
118157
119158 /*
120- // Leaving this here but commented out since it's useful in inspecting the behaviour when something does look off.
121- investigationSlice := make([]string, 0)
122- for _, record := range kinsumer1ResultAfterOwnerChange {
123- investigationSlice = append(investigationSlice, string(record.record.Data))
159+ // Leaving this here but commented out since it's useful in inspecting the behaviour when something does look off.
160+ if len(resultsAfterOwnerChange) > 0 {
161+ investigationSlice := make([]string, 0)
162+ for _, record := range kinsumer1ResultAfterOwnerChange {
163+ investigationSlice = append(investigationSlice, string(record.record.Data))
164+ }
165+ fmt.Println(investigationSlice)
124166 }
125167 */
126168
127169 assert .Equal (t , 0 , len (kinsumer1ResultAfterOwnerChange ))
128- assert .Equal (t , 2000 , len (kinsumer2ResultAfterOwnerChange ))
170+ assert .Equal (t , 1000 , len (kinsumer2ResultAfterOwnerChange ))
171+
172+ dupes := make ([]string , 0 )
173+
174+ for _ , val1 := range kinsumer1ResultAfterOwnerChange {
175+ for _ , val2 := range kinsumer2ResultAfterOwnerChange {
176+ if string (val1 .record .Data ) == string (val2 .record .Data ) {
177+ dupes = append (dupes , string (val1 .record .Data ))
178+ }
179+ }
180+ }
129181
130182 // Check that every expected value is present in the results
131183 missingIntegers := make ([]int , 0 )
132- for i := 4000 ; i < 6000 ; i ++ {
184+ for i := 5000 ; i < 6000 ; i ++ {
133185 present := false
134186 for _ , val := range kinsumer2ResultAfterOwnerChange {
135187 if string (val .record .Data ) == fmt .Sprint (i ) {
@@ -519,8 +571,6 @@ func TestConsumerStopStart(t *testing.T) {
519571
520572}
521573
522- // TODO: For some reason, using the readMultipleToSlice function in this test causes us to receive no data for the first two consumers. Figure out why and resolve.
523- // (ideally we start to read the data first then we start to stop and consumers)
524574// TestMultipleConsumerStopStart tests the same thing as TestConsumerStopStart, but for the scenario where there are multiple clients vying for control of the same shard.
525575// This is a common scenario when shards are merged, because the reported shard count will change relatively slowly over time (seconds), and for a period different clients will report different shard counts
526576// The aim of this test is to give us some more robust assurance that there are no additional issues for multiple consumers on a shard which aren't caught when we only have one consumer at a time.
@@ -609,7 +659,6 @@ func TestMultipleConsumerStopStart(t *testing.T) {
609659 }
610660 }()
611661
612- // TODO: Investigate why starting this process earlier results in an empty result set for one of the consumers.
613662 results := readMultipleToSlice ([]chan * consumedRecord {kinsumer1 .records , kinsumer2 .records , kinsumer3 .records }, 10 * time .Second )
614663
615664 kinsumer1Result := results [0 ]
@@ -621,8 +670,6 @@ func TestMultipleConsumerStopStart(t *testing.T) {
621670 assert .NotEqual (t , 0 , len (kinsumer2Result ))
622671 assert .NotEqual (t , 0 , len (kinsumer3Result ))
623672
624- fmt .Println ("Lengths: " , len (kinsumer1Result ), len (kinsumer2Result ), len (kinsumer3Result )) // TODO: Remove this
625-
626673 // Check for dupes within each client's results
627674 kinsumer1Dupes := getDupesFromSlice (kinsumer1Result )
628675 kinsumer2Dupes := getDupesFromSlice (kinsumer2Result )
0 commit comments