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