Skip to content

Commit b8369e5

Browse files
committed
[FAB-1452] Setup mock consumer before using disk
https://jira.hyperledger.org/browse/FAB-1452 Consider this: 1. Before we bring up a mock producer and mock consumer we need to initialize them so that they output the right offsets. We do this via a process where we add fill-in blocks until we get them to the desired offset. 2. We move messages between the mock producer to the mock consumer via goroutine that fetches a message from the producer's disk (an unbuffered channel) and places it into the consumer's disk (another unbuffered channel). Up until now, before proceeding to step 2, we would only make sure that the producer was set-up. The goroutine then would add a message to the consumer's disk before the consumer was set-up. As a result, the first message we would receive past the setup process would sometimes be the last fill-in message (instead of the first, regular test message). This changeset adds a hook for checking that consumer has been setup and modifies the unit tests so that they use it before proceeding with the message passing between disks. Change-Id: I3b86f67ffe5110a5165d96bf727f2f5dfa4e462f Signed-off-by: Kostas Christidis <[email protected]>
1 parent 8f1e830 commit b8369e5

File tree

4 files changed

+29
-12
lines changed

4 files changed

+29
-12
lines changed

orderer/kafka/consumer_mock_test.go

+11-11
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,11 @@ type mockConsumerImpl struct {
3535
parentConsumer *mocks.Consumer
3636
chainPartitionManager *mocks.PartitionConsumer
3737
chainPartitionConsumer sarama.PartitionConsumer
38-
disk chan *ab.KafkaMessage
39-
isSetup chan struct{}
40-
t *testing.T
38+
39+
disk chan *ab.KafkaMessage
40+
isSetup chan struct{}
41+
targetOffset int64
42+
t *testing.T
4143
}
4244

4345
func mockNewConsumer(t *testing.T, cp ChainPartition, offset int64, disk chan *ab.KafkaMessage) (Consumer, error) {
@@ -59,6 +61,7 @@ func mockNewConsumer(t *testing.T, cp ChainPartition, offset int64, disk chan *a
5961
}
6062
mc := &mockConsumerImpl{
6163
consumedOffset: 0,
64+
targetOffset: offset,
6265
chainPartition: cp,
6366

6467
parentConsumer: parentConsumer,
@@ -69,19 +72,13 @@ func mockNewConsumer(t *testing.T, cp ChainPartition, offset int64, disk chan *a
6972
t: t,
7073
}
7174
// Stop-gap hack until sarama issue #745 is resolved:
72-
if offset >= testOldestOffset && offset <= (testNewestOffset-1) {
73-
mc.testFillWithBlocks(offset - 1) // Prepare the consumer so that the next Recv gives you blob #offset
75+
if mc.targetOffset >= testOldestOffset && mc.targetOffset <= (testNewestOffset-1) {
76+
mc.testFillWithBlocks(mc.targetOffset - 1) // Prepare the consumer so that the next Recv gives you blob #targetOffset
7477
} else {
7578
err = fmt.Errorf("Out of range offset (seek number) given to consumer: %d", offset)
7679
return mc, err
7780
}
7881

79-
if mc.consumedOffset == offset-1 {
80-
close(mc.isSetup)
81-
} else {
82-
mc.t.Fatal("Mock consumer failed to initialize itself properly")
83-
}
84-
8582
return mc, err
8683
}
8784

@@ -101,6 +98,9 @@ func (mc *mockConsumerImpl) Recv() <-chan *sarama.ConsumerMessage {
10198
case outgoingMsg := <-mc.disk:
10299
mc.consumedOffset++
103100
mc.chainPartitionManager.YieldMessage(testNewConsumerMessage(mc.chainPartition, mc.consumedOffset, outgoingMsg))
101+
if mc.consumedOffset == mc.targetOffset-1 {
102+
close(mc.isSetup) // Hook for callers
103+
}
104104
return mc.chainPartitionConsumer.Messages()
105105
}
106106

orderer/kafka/consumer_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ func testConsumerRecvFunc(given, expected int64) func(t *testing.T) {
5050
testClose(t, mc)
5151
t.Fatal("Consumer should have proceeded normally:", err)
5252
}
53+
<-mc.(*mockConsumerImpl).isSetup
5354
go func() {
5455
disk <- newRegularMessage([]byte("foo"))
5556
}()

orderer/kafka/main.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ func newChain(consenter testableConsenter, support multichain.ConsenterSupport)
9898
halted: false, // Redundant as the default value for booleans is false but added for readability
9999
exitChan: make(chan struct{}),
100100
haltedChan: make(chan struct{}),
101+
setupChan: make(chan struct{}),
101102
}
102103
}
103104

@@ -130,7 +131,9 @@ type chainImpl struct {
130131
halted bool // For the Enqueue() calls
131132
exitChan chan struct{} // For the Chain's Halt() method
132133

133-
haltedChan chan struct{} // Hook for testing
134+
// Hooks for testing
135+
haltedChan chan struct{}
136+
setupChan chan struct{}
134137
}
135138

136139
// Start allocates the necessary resources for staying up to date with this Chain.
@@ -158,6 +161,7 @@ func (ch *chainImpl) Start() {
158161
return
159162
}
160163
ch.consumer = consumer
164+
close(ch.setupChan)
161165

162166
// 3. Set the loop the keep up to date with the chain.
163167
go ch.loop()

orderer/kafka/main_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,12 @@ func TestKafkaConsenterEmptyBatch(t *testing.T) {
108108
case <-time.After(testTimePadding):
109109
t.Fatal("Mock producer not setup in time")
110110
}
111+
// Same for the mock consumer
112+
select {
113+
case <-ch.setupChan:
114+
case <-time.After(testTimePadding):
115+
t.Fatal("Mock consumer not setup in time")
116+
}
111117
}()
112118
wg.Wait()
113119

@@ -166,6 +172,12 @@ func TestKafkaConsenterConfigStyleMultiBatch(t *testing.T) {
166172
case <-time.After(testTimePadding):
167173
t.Fatal("Mock producer not setup in time")
168174
}
175+
// Same for the mock consumer
176+
select {
177+
case <-ch.setupChan:
178+
case <-time.After(testTimePadding):
179+
t.Fatal("Mock consumer not setup in time")
180+
}
169181
}()
170182
wg.Wait()
171183

0 commit comments

Comments
 (0)