github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/orderer/multichain/manager_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 multichain
    18  
    19  import (
    20  	"reflect"
    21  	"testing"
    22  	"time"
    23  
    24  	"github.com/hyperledger/fabric/common/configtx"
    25  	configtxtest "github.com/hyperledger/fabric/common/configtx/test"
    26  	genesisconfig "github.com/hyperledger/fabric/common/configtx/tool/localconfig"
    27  	"github.com/hyperledger/fabric/common/configtx/tool/provisional"
    28  	mockcrypto "github.com/hyperledger/fabric/common/mocks/crypto"
    29  	ordererledger "github.com/hyperledger/fabric/orderer/ledger"
    30  	ramledger "github.com/hyperledger/fabric/orderer/ledger/ram"
    31  	cb "github.com/hyperledger/fabric/protos/common"
    32  	ab "github.com/hyperledger/fabric/protos/orderer"
    33  	"github.com/hyperledger/fabric/protos/utils"
    34  
    35  	"errors"
    36  
    37  	logging "github.com/op/go-logging"
    38  	"github.com/stretchr/testify/assert"
    39  )
    40  
    41  var conf *genesisconfig.Profile
    42  var genesisBlock = cb.NewBlock(0, nil) // *cb.Block
    43  
    44  func init() {
    45  	conf = genesisconfig.Load(genesisconfig.SampleInsecureProfile)
    46  	logging.SetLevel(logging.DEBUG, "")
    47  	genesisBlock = provisional.New(conf).GenesisBlock()
    48  }
    49  
    50  func mockCrypto() *mockCryptoHelper {
    51  	return &mockCryptoHelper{LocalSigner: mockcrypto.FakeLocalSigner}
    52  }
    53  
    54  type mockCryptoHelper struct {
    55  	*mockcrypto.LocalSigner
    56  }
    57  
    58  func (mch mockCryptoHelper) VerifySignature(sd *cb.SignedData) error {
    59  	return nil
    60  }
    61  
    62  func mockCryptoRejector() *mockCryptoRejectorHelper {
    63  	return &mockCryptoRejectorHelper{LocalSigner: mockcrypto.FakeLocalSigner}
    64  }
    65  
    66  type mockCryptoRejectorHelper struct {
    67  	*mockcrypto.LocalSigner
    68  }
    69  
    70  func (mch mockCryptoRejectorHelper) VerifySignature(sd *cb.SignedData) error {
    71  	return errors.New("Nope")
    72  }
    73  
    74  func NewRAMLedgerAndFactory(maxSize int) (ordererledger.Factory, ordererledger.ReadWriter) {
    75  	rlf := ramledger.New(10)
    76  	rl, err := rlf.GetOrCreate(provisional.TestChainID)
    77  	if err != nil {
    78  		panic(err)
    79  	}
    80  	err = rl.Append(genesisBlock)
    81  	if err != nil {
    82  		panic(err)
    83  	}
    84  	return rlf, rl
    85  }
    86  
    87  func NewRAMLedger(maxSize int) ordererledger.ReadWriter {
    88  	_, rl := NewRAMLedgerAndFactory(maxSize)
    89  	return rl
    90  }
    91  
    92  // Tests for a normal chain which contains 3 config transactions and other normal transactions to make sure the right one returned
    93  func TestGetConfigTx(t *testing.T) {
    94  	rl := NewRAMLedger(10)
    95  	for i := 0; i < 5; i++ {
    96  		rl.Append(ordererledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, i)}))
    97  	}
    98  	rl.Append(ordererledger.CreateNextBlock(rl, []*cb.Envelope{makeConfigTx(provisional.TestChainID, 5)}))
    99  	ctx := makeConfigTx(provisional.TestChainID, 6)
   100  	rl.Append(ordererledger.CreateNextBlock(rl, []*cb.Envelope{ctx}))
   101  
   102  	block := ordererledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 7)})
   103  	block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{Value: utils.MarshalOrPanic(&cb.LastConfig{Index: 7})})
   104  	rl.Append(block)
   105  
   106  	pctx := getConfigTx(rl)
   107  
   108  	if !reflect.DeepEqual(ctx, pctx) {
   109  		t.Fatalf("Did not select most recent config transaction")
   110  	}
   111  }
   112  
   113  // Tests a chain which contains blocks with multi-transactions mixed with config txs, and a single tx which is not a config tx, none count as config blocks so nil should return
   114  func TestGetConfigTxFailure(t *testing.T) {
   115  	rl := NewRAMLedger(10)
   116  	for i := 0; i < 10; i++ {
   117  		rl.Append(ordererledger.CreateNextBlock(rl, []*cb.Envelope{
   118  			makeNormalTx(provisional.TestChainID, i),
   119  			makeConfigTx(provisional.TestChainID, i),
   120  		}))
   121  	}
   122  	rl.Append(ordererledger.CreateNextBlock(rl, []*cb.Envelope{makeNormalTx(provisional.TestChainID, 11)}))
   123  	defer func() {
   124  		if recover() == nil {
   125  			t.Fatalf("Should have panic-ed because there was no config tx")
   126  		}
   127  	}()
   128  	getConfigTx(rl)
   129  
   130  }
   131  
   132  // This test essentially brings the entire system up and is ultimately what main.go will replicate
   133  func TestNoSystemChain(t *testing.T) {
   134  	defer func() {
   135  		if recover() == nil {
   136  			t.Fatalf("Should have panicked when starting without a system chain")
   137  		}
   138  	}()
   139  
   140  	lf := ramledger.New(10)
   141  
   142  	consenters := make(map[string]Consenter)
   143  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   144  
   145  	NewManagerImpl(lf, consenters, mockCrypto())
   146  }
   147  
   148  // This test essentially brings the entire system up and is ultimately what main.go will replicate
   149  func TestManagerImpl(t *testing.T) {
   150  	lf, rl := NewRAMLedgerAndFactory(10)
   151  
   152  	consenters := make(map[string]Consenter)
   153  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   154  
   155  	manager := NewManagerImpl(lf, consenters, mockCrypto())
   156  
   157  	_, ok := manager.GetChain("Fake")
   158  	if ok {
   159  		t.Errorf("Should not have found a chain that was not created")
   160  	}
   161  
   162  	chainSupport, ok := manager.GetChain(provisional.TestChainID)
   163  
   164  	if !ok {
   165  		t.Fatalf("Should have gotten chain which was initialized by ramledger")
   166  	}
   167  
   168  	messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount)
   169  	for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   170  		messages[i] = makeNormalTx(provisional.TestChainID, i)
   171  	}
   172  
   173  	for _, message := range messages {
   174  		chainSupport.Enqueue(message)
   175  	}
   176  
   177  	it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   178  	select {
   179  	case <-it.ReadyChan():
   180  		block, status := it.Next()
   181  		if status != cb.Status_SUCCESS {
   182  			t.Fatalf("Could not retrieve block")
   183  		}
   184  		for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   185  			if !reflect.DeepEqual(utils.ExtractEnvelopeOrPanic(block, i), messages[i]) {
   186  				t.Errorf("Block contents wrong at index %d", i)
   187  			}
   188  		}
   189  	case <-time.After(time.Second):
   190  		t.Fatalf("Block 1 not produced after timeout")
   191  	}
   192  }
   193  
   194  /*
   195  // This test makes sure that the signature filter works
   196  func TestSignatureFilter(t *testing.T) {
   197  	lf, rl := NewRAMLedgerAndFactory(10)
   198  
   199  	consenters := make(map[string]Consenter)
   200  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   201  
   202  	manager := NewManagerImpl(lf, consenters, mockCryptoRejector())
   203  
   204  	cs, ok := manager.GetChain(provisional.TestChainID)
   205  
   206  	if !ok {
   207  		t.Fatalf("Should have gotten chain which was initialized by ramledger")
   208  	}
   209  
   210  	messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount)
   211  	for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   212  		messages[i] = makeSignaturelessTx(provisional.TestChainID, i)
   213  	}
   214  
   215  	for _, message := range messages {
   216  		cs.Enqueue(message)
   217  	}
   218  
   219  	// Causes the consenter thread to exit after it processes all messages
   220  	close(cs.(*chainSupport).chain.(*mockChain).queue)
   221  
   222  	it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   223  	select {
   224  	case <-it.ReadyChan():
   225  		// Will unblock if a block is created
   226  		t.Fatalf("Block 1 should not have been created")
   227  	case <-cs.(*chainSupport).chain.(*mockChain).done:
   228  		// Will unblock once the consenter thread has exited
   229  	}
   230  }
   231  */
   232  
   233  // This test brings up the entire system, with the mock consenter, including the broadcasters etc. and creates a new chain
   234  func TestNewChain(t *testing.T) {
   235  	lf, rl := NewRAMLedgerAndFactory(10)
   236  
   237  	consenters := make(map[string]Consenter)
   238  	consenters[conf.Orderer.OrdererType] = &mockConsenter{}
   239  
   240  	manager := NewManagerImpl(lf, consenters, mockCrypto())
   241  
   242  	newChainID := "TestNewChain"
   243  
   244  	configEnv, err := configtx.NewChainCreationTemplate(provisional.AcceptAllPolicyKey, configtxtest.CompositeTemplate()).Envelope(newChainID)
   245  	if err != nil {
   246  		t.Fatalf("Error constructing configtx")
   247  	}
   248  	ingressTx := makeConfigTxFromConfigUpdateEnvelope(newChainID, configEnv)
   249  	wrapped := wrapConfigTx(ingressTx)
   250  
   251  	chainSupport, ok := manager.GetChain(manager.SystemChannelID())
   252  	assert.True(t, ok, "Could not find system channel")
   253  	chainSupport.Enqueue(wrapped)
   254  
   255  	it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   256  	select {
   257  	case <-it.ReadyChan():
   258  		block, status := it.Next()
   259  		if status != cb.Status_SUCCESS {
   260  			t.Fatalf("Could not retrieve block")
   261  		}
   262  		if len(block.Data.Data) != 1 {
   263  			t.Fatalf("Should have had only one message in the orderer transaction block")
   264  		}
   265  
   266  		assert.Equal(t, wrapped, utils.UnmarshalEnvelopeOrPanic(block.Data.Data[0]), "Orderer config block contains wrong transaction")
   267  	case <-time.After(time.Second):
   268  		t.Fatalf("Block 1 not produced after timeout in system chain")
   269  	}
   270  
   271  	chainSupport, ok = manager.GetChain(newChainID)
   272  
   273  	if !ok {
   274  		t.Fatalf("Should have gotten new chain which was created")
   275  	}
   276  
   277  	messages := make([]*cb.Envelope, conf.Orderer.BatchSize.MaxMessageCount)
   278  	for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   279  		messages[i] = makeNormalTx(newChainID, i)
   280  	}
   281  
   282  	for _, message := range messages {
   283  		chainSupport.Enqueue(message)
   284  	}
   285  
   286  	it, _ = chainSupport.Reader().Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 0}}})
   287  	select {
   288  	case <-it.ReadyChan():
   289  		block, status := it.Next()
   290  		if status != cb.Status_SUCCESS {
   291  			t.Fatalf("Could not retrieve new chain genesis block")
   292  		}
   293  		if len(block.Data.Data) != 1 {
   294  			t.Fatalf("Should have had only one message in the new genesis block")
   295  		}
   296  
   297  		assert.Equal(t, ingressTx, utils.UnmarshalEnvelopeOrPanic(block.Data.Data[0]), "Genesis block contains wrong transaction")
   298  	case <-time.After(time.Second):
   299  		t.Fatalf("Block 1 not produced after timeout in system chain")
   300  	}
   301  
   302  	select {
   303  	case <-it.ReadyChan():
   304  		block, status := it.Next()
   305  		if status != cb.Status_SUCCESS {
   306  			t.Fatalf("Could not retrieve block on new chain")
   307  		}
   308  		for i := 0; i < int(conf.Orderer.BatchSize.MaxMessageCount); i++ {
   309  			if !reflect.DeepEqual(utils.ExtractEnvelopeOrPanic(block, i), messages[i]) {
   310  				t.Errorf("Block contents wrong at index %d in new chain", i)
   311  			}
   312  		}
   313  	case <-time.After(time.Second):
   314  		t.Fatalf("Block 1 not produced after timeout on new chain")
   315  	}
   316  }