Skip to content

Commit 363f6a7

Browse files
committed
[FAB-3383] Increase gossip unit test coverage
Gossip unit test coverage is pretty good, but can be even better. This change set makes all our code (except protos extension that are found in protos/gossip/) have code coverage of above 85%. github.com/hyperledger/fabric/core/deliverservice 29.143s : 92.5% github.com/hyperledger/fabric/core/deliverservice/blocksprovider 7.047s : 86.1% github.com/hyperledger/fabric/core/deliverservice/mocks 1.018s : 93.8% github.com/hyperledger/fabric/gossip/api 0.003s : 100.0% github.com/hyperledger/fabric/gossip/comm 11.078s : 85.9% github.com/hyperledger/fabric/gossip/comm/mock 0.031s : 85.3% github.com/hyperledger/fabric/gossip/common 0.002s : 100.0% github.com/hyperledger/fabric/gossip/discovery 25.064s : 86.5% github.com/hyperledger/fabric/gossip/election 7.130s : 94.2% github.com/hyperledger/fabric/gossip/filter 0.040s : 100.0% github.com/hyperledger/fabric/gossip/gossip 72.131s : 86.7% github.com/hyperledger/fabric/gossip/gossip/algo 6.552s : 97.1% github.com/hyperledger/fabric/gossip/gossip/channel 21.811s : 92.1% github.com/hyperledger/fabric/gossip/gossip/msgstore 8.014s : 100.0% github.com/hyperledger/fabric/gossip/gossip/pull 2.688s : 96.3% github.com/hyperledger/fabric/gossip/identity 0.012s : 90.7% github.com/hyperledger/fabric/gossip/integration 0.078s : 85.7% github.com/hyperledger/fabric/gossip/service 83.191s : 86.8% github.com/hyperledger/fabric/gossip/state 37.891s : 86.3% github.com/hyperledger/fabric/gossip/state/mocks 0.020s : 90.0% github.com/hyperledger/fabric/gossip/util 0.029s : 100.0% Change-Id: Ifcbf4fa20cd5829f64cdd9b5d1e0507b38118271 Signed-off-by: Yacov Manevich <[email protected]>
1 parent f0c3bfc commit 363f6a7

25 files changed

+899
-93
lines changed

core/deliverservice/blocksprovider/blocksprovider_test.go

+79-34
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ limitations under the License.
1616
package blocksprovider
1717

1818
import (
19+
"errors"
1920
"sync"
21+
"sync/atomic"
2022
"testing"
2123
"time"
2224

@@ -26,16 +28,22 @@ import (
2628
"github.com/hyperledger/fabric/protos/common"
2729
"github.com/hyperledger/fabric/protos/orderer"
2830
"github.com/stretchr/testify/assert"
31+
"github.com/stretchr/testify/mock"
2932
)
3033

3134
type mockMCS struct {
35+
mock.Mock
3236
}
3337

3438
func (*mockMCS) GetPKIidOfCert(peerIdentity api.PeerIdentityType) common2.PKIidType {
3539
return common2.PKIidType("pkiID")
3640
}
3741

38-
func (*mockMCS) VerifyBlock(chainID common2.ChainID, signedBlock []byte) error {
42+
func (m *mockMCS) VerifyBlock(chainID common2.ChainID, signedBlock []byte) error {
43+
args := m.Called()
44+
if args.Get(0) != nil {
45+
return args.Get(0).(error)
46+
}
3947
return nil
4048
}
4149

@@ -55,47 +63,42 @@ func (*mockMCS) ValidateIdentity(peerIdentity api.PeerIdentityType) error {
5563
return nil
5664
}
5765

66+
type rcvFunc func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error)
67+
5868
// Used to generate a simple test case to initialize delivery
5969
// from given block sequence number.
60-
func makeTestCase(ledgerHeight uint64) func(*testing.T) {
70+
func makeTestCase(ledgerHeight uint64, mcs api.MessageCryptoService, shouldSucceed bool, rcv rcvFunc) func(*testing.T) {
6171
return func(t *testing.T) {
6272
gossipServiceAdapter := &mocks.MockGossipServiceAdapter{GossipBlockDisseminations: make(chan uint64)}
6373
deliverer := &mocks.MockBlocksDeliverer{Pos: ledgerHeight}
64-
deliverer.MockRecv = mocks.MockRecv
65-
66-
provider := &blocksProviderImpl{
67-
chainID: "***TEST_CHAINID***",
68-
gossip: gossipServiceAdapter,
69-
client: deliverer,
70-
mcs: &mockMCS{},
71-
}
72-
74+
deliverer.MockRecv = rcv
75+
provider := NewBlocksProvider("***TEST_CHAINID***", deliverer, gossipServiceAdapter, mcs)
76+
defer provider.Stop()
7377
ready := make(chan struct{})
7478
go func() {
7579
go provider.DeliverBlocks()
7680
// Send notification
7781
ready <- struct{}{}
7882
}()
7983

80-
time.Sleep(time.Duration(10) * time.Millisecond)
81-
provider.Stop()
82-
83-
select {
84-
case <-ready:
85-
{
86-
// Check that all blocks received eventually get gossiped and locally committed
87-
assert.True(t, deliverer.RecvCnt == gossipServiceAdapter.AddPayloadsCnt)
88-
select {
89-
case <-gossipServiceAdapter.GossipBlockDisseminations:
90-
case <-time.After(time.Second):
91-
assert.Fail(t, "Didn't gossip a block within a timely manner")
92-
}
93-
return
94-
}
95-
case <-time.After(time.Duration(1) * time.Second):
96-
{
97-
t.Fatal("Test hasn't finished in timely manner, failing.")
98-
}
84+
time.Sleep(time.Second)
85+
86+
assertDelivery(t, gossipServiceAdapter, deliverer, shouldSucceed)
87+
}
88+
}
89+
90+
func assertDelivery(t *testing.T, ga *mocks.MockGossipServiceAdapter, deliverer *mocks.MockBlocksDeliverer, shouldSucceed bool) {
91+
// Check that all blocks received eventually get gossiped and locally committed
92+
93+
select {
94+
case <-ga.GossipBlockDisseminations:
95+
if !shouldSucceed {
96+
assert.Fail(t, "Should not have succeede")
97+
}
98+
assert.True(t, deliverer.RecvCnt == ga.AddPayloadsCnt)
99+
case <-time.After(time.Second):
100+
if shouldSucceed {
101+
assert.Fail(t, "Didn't gossip a block within a timely manner")
99102
}
100103
}
101104
}
@@ -105,19 +108,22 @@ func makeTestCase(ledgerHeight uint64) func(*testing.T) {
105108
oldest and that eventually it terminates after the Stop method has been called.
106109
*/
107110
func TestBlocksProviderImpl_GetBlockFromTheOldest(t *testing.T) {
108-
makeTestCase(uint64(0))(t)
111+
mcs := &mockMCS{}
112+
mcs.On("VerifyBlock", mock.Anything).Return(nil)
113+
makeTestCase(uint64(0), mcs, true, mocks.MockRecv)(t)
109114
}
110115

111116
/*
112117
Test to check whenever blocks provider starts calling new blocks from the
113118
oldest and that eventually it terminates after the Stop method has been called.
114119
*/
115120
func TestBlocksProviderImpl_GetBlockFromSpecified(t *testing.T) {
116-
makeTestCase(uint64(101))(t)
121+
mcs := &mockMCS{}
122+
mcs.On("VerifyBlock", mock.Anything).Return(nil)
123+
makeTestCase(uint64(101), mcs, true, mocks.MockRecv)(t)
117124
}
118125

119126
func TestBlocksProvider_CheckTerminationDeliveryResponseStatus(t *testing.T) {
120-
121127
tmp := struct{ mocks.MockBlocksDeliverer }{}
122128

123129
// Making mocked Recv() function to return DeliverResponse_Status to force block
@@ -158,7 +164,7 @@ func TestBlocksProvider_CheckTerminationDeliveryResponseStatus(t *testing.T) {
158164
assert.Equal(t, int32(1), tmp.RecvCnt)
159165
// No payload should commit locally
160166
assert.Equal(t, int32(0), gossipServiceAdapter.AddPayloadsCnt)
161-
// No payload should be transfered to other peers
167+
// No payload should be transferred to other peers
162168
select {
163169
case <-gossipServiceAdapter.GossipBlockDisseminations:
164170
assert.Fail(t, "Gossiped block but shouldn't have")
@@ -172,3 +178,42 @@ func TestBlocksProvider_CheckTerminationDeliveryResponseStatus(t *testing.T) {
172178
}
173179
}
174180
}
181+
182+
func TestBlockFetchFailure(t *testing.T) {
183+
rcvr := func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
184+
return nil, errors.New("Failed fetching block")
185+
}
186+
mcs := &mockMCS{}
187+
mcs.On("VerifyBlock", mock.Anything).Return(nil)
188+
makeTestCase(uint64(0), mcs, false, rcvr)(t)
189+
}
190+
191+
func TestBlockVerificationFailure(t *testing.T) {
192+
attempts := int32(0)
193+
rcvr := func(mock *mocks.MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
194+
if atomic.LoadInt32(&attempts) == int32(1) {
195+
return &orderer.DeliverResponse{
196+
Type: &orderer.DeliverResponse_Status{
197+
Status: common.Status_SUCCESS,
198+
},
199+
}, nil
200+
}
201+
atomic.AddInt32(&attempts, int32(1))
202+
return &orderer.DeliverResponse{
203+
Type: &orderer.DeliverResponse_Block{
204+
Block: &common.Block{
205+
Header: &common.BlockHeader{
206+
Number: 0,
207+
DataHash: []byte{},
208+
PreviousHash: []byte{},
209+
},
210+
Data: &common.BlockData{
211+
Data: [][]byte{},
212+
},
213+
}},
214+
}, nil
215+
}
216+
mcs := &mockMCS{}
217+
mcs.On("VerifyBlock", mock.Anything).Return(errors.New("Invalid signature"))
218+
makeTestCase(uint64(0), mcs, false, rcvr)(t)
219+
}

core/deliverservice/mocks/blocksprovider.go

+2-6
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,9 @@ func (mock *MockBlocksDeliverer) Send(env *common.Envelope) error {
114114
// Read starting position
115115
switch t := seekInfo.Start.Type.(type) {
116116
case *orderer.SeekPosition_Oldest:
117-
{
118-
mock.Pos = 0
119-
}
117+
mock.Pos = 0
120118
case *orderer.SeekPosition_Specified:
121-
{
122-
mock.Pos = t.Specified.Number
123-
}
119+
mock.Pos = t.Specified.Number
124120
}
125121
return nil
126122
}

core/deliverservice/mocks/blocksprovider_test.go

+90-2
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,114 @@ limitations under the License.
1717
package mocks
1818

1919
import (
20+
"context"
21+
"math"
22+
"sync/atomic"
2023
"testing"
24+
"time"
2125

26+
pb "github.com/golang/protobuf/proto"
2227
"github.com/hyperledger/fabric/core/deliverservice/blocksprovider"
28+
"github.com/hyperledger/fabric/protos/common"
29+
proto "github.com/hyperledger/fabric/protos/gossip"
30+
"github.com/hyperledger/fabric/protos/orderer"
31+
"github.com/stretchr/testify/assert"
2332
)
2433

2534
func TestMockBlocksDeliverer(t *testing.T) {
35+
// Make sure it implements BlocksDeliverer
2636
var bd blocksprovider.BlocksDeliverer
2737
bd = &MockBlocksDeliverer{}
2838
_ = bd
39+
40+
assert.Panics(t, func() {
41+
bd.Recv()
42+
})
43+
bd.(*MockBlocksDeliverer).MockRecv = func(mock *MockBlocksDeliverer) (*orderer.DeliverResponse, error) {
44+
return &orderer.DeliverResponse{
45+
Type: &orderer.DeliverResponse_Status{
46+
Status: common.Status_FORBIDDEN,
47+
},
48+
}, nil
49+
}
50+
status, err := bd.Recv()
51+
assert.Nil(t, err)
52+
assert.Equal(t, common.Status_FORBIDDEN, status.GetStatus())
53+
bd.(*MockBlocksDeliverer).MockRecv = MockRecv
54+
block, err := bd.Recv()
55+
assert.Nil(t, err)
56+
assert.Equal(t, uint64(0), block.GetBlock().Header.Number)
57+
58+
bd.(*MockBlocksDeliverer).Close()
59+
60+
seekInfo := &orderer.SeekInfo{
61+
Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Oldest{Oldest: &orderer.SeekOldest{}}},
62+
Stop: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: math.MaxUint64}}},
63+
Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY,
64+
}
65+
si, err := pb.Marshal(seekInfo)
66+
assert.NoError(t, err)
67+
68+
payload := &common.Payload{}
69+
70+
payload.Data = si
71+
b, err := pb.Marshal(payload)
72+
assert.NoError(t, err)
73+
assert.Nil(t, bd.Send(&common.Envelope{Payload: b}))
2974
}
3075

3176
func TestMockGossipServiceAdapter(t *testing.T) {
77+
// Make sure it implements GossipServiceAdapter
3278
var gsa blocksprovider.GossipServiceAdapter
33-
gsa = &MockGossipServiceAdapter{}
79+
seqNums := make(chan uint64, 1)
80+
gsa = &MockGossipServiceAdapter{GossipBlockDisseminations: seqNums}
3481
_ = gsa
3582

83+
// Test gossip
84+
msg := &proto.GossipMessage{
85+
Content: &proto.GossipMessage_DataMsg{
86+
DataMsg: &proto.DataMessage{
87+
Payload: &proto.Payload{
88+
SeqNum: uint64(100),
89+
},
90+
},
91+
},
92+
}
93+
gsa.Gossip(msg)
94+
select {
95+
case seq := <-seqNums:
96+
assert.Equal(t, uint64(100), seq)
97+
case <-time.After(time.Second):
98+
assert.Fail(t, "Didn't gossip within a timely manner")
99+
}
100+
101+
// Test AddPayload
102+
gsa.AddPayload("TEST", msg.GetDataMsg().Payload)
103+
assert.Equal(t, int32(1), atomic.LoadInt32(&(gsa.(*MockGossipServiceAdapter).AddPayloadsCnt)))
104+
105+
// Test PeersOfChannel
106+
assert.Len(t, gsa.PeersOfChannel(nil), 0)
107+
}
108+
109+
func TestMockAtomicBroadcastClient(t *testing.T) {
110+
// Make sure it implements MockAtomicBroadcastClient
111+
var abc orderer.AtomicBroadcastClient
112+
abc = &MockAtomicBroadcastClient{BD: &MockBlocksDeliverer{}}
113+
114+
assert.Panics(t, func() {
115+
abc.Broadcast(context.Background())
116+
})
117+
c, err := abc.Deliver(context.Background())
118+
assert.Nil(t, err)
119+
assert.NotNil(t, c)
36120
}
37121

38122
func TestMockLedgerInfo(t *testing.T) {
39123
var li blocksprovider.LedgerInfo
40-
li = &MockLedgerInfo{}
124+
li = &MockLedgerInfo{uint64(8)}
41125
_ = li
126+
127+
height, err := li.LedgerHeight()
128+
assert.Equal(t, uint64(8), height)
129+
assert.NoError(t, err)
42130
}

core/deliverservice/mocks/orderer.go

-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ func (o *Orderer) SendBlock(seq uint64) {
7777
func (o *Orderer) Deliver(stream orderer.AtomicBroadcast_DeliverServer) error {
7878
envlp, err := stream.Recv()
7979
if err != nil {
80-
fmt.Println(err)
8180
return nil
8281
}
8382
payload := &common.Payload{}
+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package mocks
18+
19+
import (
20+
"math"
21+
"testing"
22+
"time"
23+
24+
pb "github.com/golang/protobuf/proto"
25+
"github.com/hyperledger/fabric/protos/common"
26+
"github.com/hyperledger/fabric/protos/orderer"
27+
"github.com/stretchr/testify/assert"
28+
"google.golang.org/grpc"
29+
)
30+
31+
type clStream struct {
32+
grpc.ServerStream
33+
}
34+
35+
func (cs *clStream) Send(*orderer.DeliverResponse) error {
36+
return nil
37+
}
38+
func (cs *clStream) Recv() (*common.Envelope, error) {
39+
seekInfo := &orderer.SeekInfo{
40+
Start: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: 0}}},
41+
Stop: &orderer.SeekPosition{Type: &orderer.SeekPosition_Specified{Specified: &orderer.SeekSpecified{Number: math.MaxUint64}}},
42+
Behavior: orderer.SeekInfo_BLOCK_UNTIL_READY,
43+
}
44+
si, _ := pb.Marshal(seekInfo)
45+
payload := &common.Payload{}
46+
payload.Data = si
47+
b, err := pb.Marshal(payload)
48+
if err != nil {
49+
panic(err)
50+
}
51+
e := &common.Envelope{Payload: b}
52+
return e, nil
53+
}
54+
55+
func TestOrderer(t *testing.T) {
56+
o := NewOrderer(8000, t)
57+
58+
go func() {
59+
time.Sleep(time.Second)
60+
o.SendBlock(uint64(0))
61+
o.Shutdown()
62+
}()
63+
64+
assert.Panics(t, func() {
65+
o.Broadcast(nil)
66+
})
67+
o.SetNextExpectedSeek(uint64(0))
68+
o.Deliver(&clStream{})
69+
}

0 commit comments

Comments
 (0)