github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/orderer/solo/consensus_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 solo
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  
    23  	mockconfigvaluesorderer "github.com/hyperledger/fabric/common/mocks/configvalues/channel/orderer"
    24  	mockblockcutter "github.com/hyperledger/fabric/orderer/mocks/blockcutter"
    25  	mockmultichain "github.com/hyperledger/fabric/orderer/mocks/multichain"
    26  	cb "github.com/hyperledger/fabric/protos/common"
    27  
    28  	logging "github.com/op/go-logging"
    29  )
    30  
    31  func init() {
    32  	logging.SetLevel(logging.DEBUG, "")
    33  }
    34  
    35  var testMessage = &cb.Envelope{Payload: []byte("TEST_MESSAGE")}
    36  
    37  func syncQueueMessage(msg *cb.Envelope, chain *chain, bc *mockblockcutter.Receiver) {
    38  	chain.Enqueue(msg)
    39  	bc.Block <- struct{}{}
    40  }
    41  
    42  type waitableGo struct {
    43  	done chan struct{}
    44  }
    45  
    46  func goWithWait(target func()) *waitableGo {
    47  	wg := &waitableGo{
    48  		done: make(chan struct{}),
    49  	}
    50  	go func() {
    51  		target()
    52  		close(wg.done)
    53  	}()
    54  	return wg
    55  }
    56  
    57  func TestEmptyBatch(t *testing.T) {
    58  	batchTimeout, _ := time.ParseDuration("1ms")
    59  	support := &mockmultichain.ConsenterSupport{
    60  		Batches:         make(chan []*cb.Envelope),
    61  		BlockCutterVal:  mockblockcutter.NewReceiver(),
    62  		SharedConfigVal: &mockconfigvaluesorderer.SharedConfig{BatchTimeoutVal: batchTimeout},
    63  	}
    64  	defer close(support.BlockCutterVal.Block)
    65  	bs := newChain(support)
    66  	wg := goWithWait(bs.main)
    67  	defer bs.Halt()
    68  
    69  	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
    70  	bs.Halt()
    71  	select {
    72  	case <-support.Batches:
    73  		t.Fatalf("Expected no invocations of Append")
    74  	case <-wg.done:
    75  	}
    76  }
    77  
    78  func TestBatchTimer(t *testing.T) {
    79  	batchTimeout, _ := time.ParseDuration("1ms")
    80  	support := &mockmultichain.ConsenterSupport{
    81  		Batches:         make(chan []*cb.Envelope),
    82  		BlockCutterVal:  mockblockcutter.NewReceiver(),
    83  		SharedConfigVal: &mockconfigvaluesorderer.SharedConfig{BatchTimeoutVal: batchTimeout},
    84  	}
    85  	defer close(support.BlockCutterVal.Block)
    86  	bs := newChain(support)
    87  	wg := goWithWait(bs.main)
    88  	defer bs.Halt()
    89  
    90  	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
    91  
    92  	select {
    93  	case <-support.Batches:
    94  	case <-time.After(time.Second):
    95  		t.Fatalf("Expected a block to be cut because of batch timer expiration but did not")
    96  	}
    97  
    98  	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
    99  	select {
   100  	case <-support.Batches:
   101  	case <-time.After(time.Second):
   102  		t.Fatalf("Did not create the second batch, indicating that the timer was not appopriately reset")
   103  	}
   104  
   105  	bs.Halt()
   106  	select {
   107  	case <-support.Batches:
   108  		t.Fatalf("Expected no invocations of Append")
   109  	case <-wg.done:
   110  	}
   111  }
   112  
   113  func TestBatchTimerHaltOnFilledBatch(t *testing.T) {
   114  	batchTimeout, _ := time.ParseDuration("1h")
   115  	support := &mockmultichain.ConsenterSupport{
   116  		Batches:         make(chan []*cb.Envelope),
   117  		BlockCutterVal:  mockblockcutter.NewReceiver(),
   118  		SharedConfigVal: &mockconfigvaluesorderer.SharedConfig{BatchTimeoutVal: batchTimeout},
   119  	}
   120  	defer close(support.BlockCutterVal.Block)
   121  
   122  	bs := newChain(support)
   123  	wg := goWithWait(bs.main)
   124  	defer bs.Halt()
   125  
   126  	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
   127  	support.BlockCutterVal.CutNext = true
   128  	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
   129  
   130  	select {
   131  	case <-support.Batches:
   132  	case <-time.After(time.Second):
   133  		t.Fatalf("Expected a block to be cut because the batch was filled, but did not")
   134  	}
   135  
   136  	// Change the batch timeout to be near instant, if the timer was not reset, it will still be waiting an hour
   137  	bs.batchTimeout = time.Millisecond
   138  
   139  	support.BlockCutterVal.CutNext = false
   140  	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
   141  
   142  	select {
   143  	case <-support.Batches:
   144  	case <-time.After(time.Second):
   145  		t.Fatalf("Did not create the second batch, indicating that the old timer was still running")
   146  	}
   147  
   148  	bs.Halt()
   149  	select {
   150  	case <-time.After(time.Second):
   151  		t.Fatalf("Should have exited")
   152  	case <-wg.done:
   153  	}
   154  }
   155  
   156  func TestConfigStyleMultiBatch(t *testing.T) {
   157  	batchTimeout, _ := time.ParseDuration("1h")
   158  	support := &mockmultichain.ConsenterSupport{
   159  		Batches:         make(chan []*cb.Envelope),
   160  		BlockCutterVal:  mockblockcutter.NewReceiver(),
   161  		SharedConfigVal: &mockconfigvaluesorderer.SharedConfig{BatchTimeoutVal: batchTimeout},
   162  	}
   163  	defer close(support.BlockCutterVal.Block)
   164  	bs := newChain(support)
   165  	wg := goWithWait(bs.main)
   166  	defer bs.Halt()
   167  
   168  	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
   169  	support.BlockCutterVal.IsolatedTx = true
   170  	syncQueueMessage(testMessage, bs, support.BlockCutterVal)
   171  
   172  	select {
   173  	case <-support.Batches:
   174  	case <-time.After(time.Second):
   175  		t.Fatalf("Expected two blocks to be cut but never got the first")
   176  	}
   177  
   178  	select {
   179  	case <-support.Batches:
   180  	case <-time.After(time.Second):
   181  		t.Fatalf("Expected the config type tx to create two blocks, but only go the first")
   182  	}
   183  
   184  	bs.Halt()
   185  	select {
   186  	case <-time.After(time.Second):
   187  		t.Fatalf("Should have exited")
   188  	case <-wg.done:
   189  	}
   190  }