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