github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/gossip/state/payloads_buffer_test.go (about)

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