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  }