github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/gossip/state/payloads_buffer_test.go (about) 1 /* 2 Copyright IBM Corp. 2016 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 state 18 19 import ( 20 "crypto/rand" 21 "sync" 22 "sync/atomic" 23 "testing" 24 "time" 25 26 "github.com/hyperledger/fabric/gossip/util" 27 proto "github.com/hyperledger/fabric/protos/gossip" 28 "github.com/stretchr/testify/assert" 29 ) 30 31 func init() { 32 util.SetupTestLogging() 33 } 34 35 func randomPayloadWithSeqNum(seqNum uint64) (*proto.Payload, error) { 36 data := make([]byte, 64) 37 _, err := rand.Read(data) 38 if err != nil { 39 return nil, err 40 } 41 return &proto.Payload{ 42 SeqNum: seqNum, 43 Data: data, 44 }, nil 45 } 46 47 func TestNewPayloadsBuffer(t *testing.T) { 48 payloadsBuffer := NewPayloadsBuffer(10) 49 assert.Equal(t, payloadsBuffer.Next(), uint64(10)) 50 } 51 52 func TestPayloadsBufferImpl_Push(t *testing.T) { 53 buffer := NewPayloadsBuffer(5) 54 55 payload, err := randomPayloadWithSeqNum(4) 56 57 if err != nil { 58 t.Fatal("Wasn't able to generate random payload for test") 59 } 60 61 t.Log("Pushing new payload into buffer") 62 buffer.Push(payload) 63 64 // Payloads with sequence number less than buffer top 65 // index should not be accepted 66 t.Log("Getting next block sequence number") 67 assert.Equal(t, buffer.Next(), uint64(5)) 68 t.Log("Check block buffer size") 69 assert.Equal(t, buffer.Size(), 0) 70 71 // Adding new payload with seq. number equal to top 72 // payload should not be added 73 payload, err = randomPayloadWithSeqNum(5) 74 if err != nil { 75 t.Fatal("Wasn't able to generate random payload for test") 76 } 77 78 t.Log("Pushing new payload into buffer") 79 buffer.Push(payload) 80 t.Log("Getting next block sequence number") 81 assert.Equal(t, buffer.Next(), uint64(5)) 82 t.Log("Check block buffer size") 83 assert.Equal(t, buffer.Size(), 1) 84 } 85 86 func TestPayloadsBufferImpl_Ready(t *testing.T) { 87 fin := make(chan struct{}) 88 buffer := NewPayloadsBuffer(1) 89 assert.Equal(t, buffer.Next(), uint64(1)) 90 91 go func() { 92 <-buffer.Ready() 93 fin <- struct{}{} 94 }() 95 96 time.AfterFunc(100*time.Millisecond, func() { 97 payload, err := randomPayloadWithSeqNum(1) 98 99 if err != nil { 100 t.Fatal("Wasn't able to generate random payload for test") 101 } 102 buffer.Push(payload) 103 }) 104 105 select { 106 case <-fin: 107 payload := buffer.Pop() 108 assert.Equal(t, payload.SeqNum, uint64(1)) 109 case <-time.After(500 * time.Millisecond): 110 t.Fail() 111 } 112 } 113 114 // Test to push several concurrent blocks into the buffer 115 // with same sequence number, only one expected to succeed 116 func TestPayloadsBufferImpl_ConcurrentPush(t *testing.T) { 117 118 // Test setup, next block num to expect and 119 // how many concurrent pushes to simulate 120 nextSeqNum := uint64(7) 121 concurrency := 10 122 123 buffer := NewPayloadsBuffer(nextSeqNum) 124 assert.Equal(t, buffer.Next(), uint64(nextSeqNum)) 125 126 startWG := sync.WaitGroup{} 127 startWG.Add(1) 128 129 finishWG := sync.WaitGroup{} 130 finishWG.Add(concurrency) 131 132 payload, err := randomPayloadWithSeqNum(nextSeqNum) 133 assert.NoError(t, err) 134 135 var errors []error 136 137 ready := int32(0) 138 readyWG := sync.WaitGroup{} 139 readyWG.Add(1) 140 go func() { 141 // Wait for next expected block to arrive 142 <-buffer.Ready() 143 atomic.AddInt32(&ready, 1) 144 readyWG.Done() 145 }() 146 147 for i := 0; i < concurrency; i++ { 148 go func() { 149 startWG.Wait() 150 errors = append(errors, buffer.Push(payload)) 151 finishWG.Done() 152 }() 153 } 154 startWG.Done() 155 finishWG.Wait() 156 157 success := 0 158 159 // Only one push attempt expected to succeed 160 for _, err := range errors { 161 if err == nil { 162 success++ 163 } 164 } 165 166 readyWG.Wait() 167 assert.Equal(t, int32(1), atomic.LoadInt32(&ready)) 168 assert.Equal(t, 1, success) 169 // Buffer size has to be only one 170 assert.Equal(t, 1, buffer.Size()) 171 }