github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/orderer/ledger/file/impl_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 fileledger
    18  
    19  import (
    20  	"fmt"
    21  	"io/ioutil"
    22  	"os"
    23  	"testing"
    24  
    25  	"github.com/hyperledger/fabric/common/configtx/tool/provisional"
    26  	cl "github.com/hyperledger/fabric/common/ledger"
    27  	"github.com/hyperledger/fabric/orderer/ledger"
    28  	cb "github.com/hyperledger/fabric/protos/common"
    29  	ab "github.com/hyperledger/fabric/protos/orderer"
    30  	"github.com/hyperledger/fabric/protos/peer"
    31  	logging "github.com/op/go-logging"
    32  	"github.com/stretchr/testify/assert"
    33  )
    34  
    35  var genesisBlock = cb.NewBlock(0, nil)
    36  
    37  func init() {
    38  	logging.SetLevel(logging.DEBUG, "")
    39  }
    40  
    41  type testEnv struct {
    42  	t        *testing.T
    43  	location string
    44  	flf      ledger.Factory
    45  }
    46  
    47  func initialize(t *testing.T) (*testEnv, *fileLedger) {
    48  	name, err := ioutil.TempDir("", "hyperledger_fabric")
    49  	assert.NoError(t, err, "Error creating temp dir: %s", err)
    50  
    51  	flf := New(name).(*fileLedgerFactory)
    52  	fl, err := flf.GetOrCreate(provisional.TestChainID)
    53  	assert.NoError(t, err, "Error GetOrCreate chain")
    54  
    55  	fl.Append(genesisBlock)
    56  	return &testEnv{location: name, t: t, flf: flf}, fl.(*fileLedger)
    57  }
    58  
    59  func (tev *testEnv) tearDown() {
    60  	tev.shutDown()
    61  	err := os.RemoveAll(tev.location)
    62  	if err != nil {
    63  		tev.t.Fatalf("Error tearing down env: %s", err)
    64  	}
    65  }
    66  
    67  func (tev *testEnv) shutDown() {
    68  	tev.flf.Close()
    69  }
    70  
    71  type mockBlockStore struct {
    72  	blockchainInfo             *cb.BlockchainInfo
    73  	resultsIterator            cl.ResultsIterator
    74  	block                      *cb.Block
    75  	envelope                   *cb.Envelope
    76  	txValidationCode           peer.TxValidationCode
    77  	defaultError               error
    78  	getBlockchainInfoError     error
    79  	retrieveBlockByNumberError error
    80  }
    81  
    82  func (mbs *mockBlockStore) AddBlock(block *cb.Block) error {
    83  	return mbs.defaultError
    84  }
    85  
    86  func (mbs *mockBlockStore) GetBlockchainInfo() (*cb.BlockchainInfo, error) {
    87  	return mbs.blockchainInfo, mbs.getBlockchainInfoError
    88  }
    89  
    90  func (mbs *mockBlockStore) RetrieveBlocks(startNum uint64) (cl.ResultsIterator, error) {
    91  	return mbs.resultsIterator, mbs.defaultError
    92  }
    93  
    94  func (mbs *mockBlockStore) RetrieveBlockByHash(blockHash []byte) (*cb.Block, error) {
    95  	return mbs.block, mbs.defaultError
    96  }
    97  
    98  func (mbs *mockBlockStore) RetrieveBlockByNumber(blockNum uint64) (*cb.Block, error) {
    99  	return mbs.block, mbs.retrieveBlockByNumberError
   100  }
   101  
   102  func (mbs *mockBlockStore) RetrieveTxByID(txID string) (*cb.Envelope, error) {
   103  	return mbs.envelope, mbs.defaultError
   104  }
   105  
   106  func (mbs *mockBlockStore) RetrieveTxByBlockNumTranNum(blockNum uint64, tranNum uint64) (*cb.Envelope, error) {
   107  	return mbs.envelope, mbs.defaultError
   108  }
   109  
   110  func (mbs *mockBlockStore) RetrieveBlockByTxID(txID string) (*cb.Block, error) {
   111  	return mbs.block, mbs.defaultError
   112  }
   113  
   114  func (mbs *mockBlockStore) RetrieveTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) {
   115  	return mbs.txValidationCode, mbs.defaultError
   116  }
   117  
   118  func (*mockBlockStore) Shutdown() {
   119  }
   120  
   121  func TestInitialization(t *testing.T) {
   122  	tev, fl := initialize(t)
   123  	defer tev.tearDown()
   124  
   125  	assert.Equal(t, uint64(1), fl.Height(), "Block height should be 1")
   126  
   127  	block := ledger.GetBlock(fl, 0)
   128  	assert.NotNil(t, block, "Error retrieving genesis block")
   129  	assert.Equal(t, genesisBlock.Header.Hash(), block.Header.Hash(), "Block hashes did no match")
   130  }
   131  
   132  func TestReinitialization(t *testing.T) {
   133  	tev, ledger1 := initialize(t)
   134  	defer tev.tearDown()
   135  
   136  	// create a block to add to the ledger
   137  	b1 := ledger.CreateNextBlock(ledger1, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})
   138  
   139  	// add the block to the ledger
   140  	ledger1.Append(b1)
   141  
   142  	fl, err := tev.flf.GetOrCreate(provisional.TestChainID)
   143  	ledger1, ok := fl.(*fileLedger)
   144  	assert.NoError(t, err, "Expected to sucessfully get test chain")
   145  	assert.Equal(t, 1, len(tev.flf.ChainIDs()), "Exptected not new chain to be created")
   146  	assert.True(t, ok, "Exptected type assertion to succeed")
   147  
   148  	// shutdown the ledger
   149  	ledger1.blockStore.Shutdown()
   150  
   151  	// shut down the ledger provider
   152  	tev.shutDown()
   153  
   154  	// re-initialize the ledger provider (not the test ledger itself!)
   155  	provider2 := New(tev.location)
   156  
   157  	// assert expected ledgers exist
   158  	chains := provider2.ChainIDs()
   159  	assert.Equal(t, 1, len(chains), "Should have recovered the chain")
   160  
   161  	// get the existing test chain ledger
   162  	ledger2, err := provider2.GetOrCreate(chains[0])
   163  	assert.NoError(t, err, "Unexpected error: %s", err)
   164  
   165  	fl = ledger2.(*fileLedger)
   166  	assert.Equal(t, uint64(2), fl.Height(), "Block height should be 2. Got %v", fl.Height())
   167  
   168  	block := ledger.GetBlock(fl, 1)
   169  	assert.NotNil(t, block, "Error retrieving block 1")
   170  	assert.Equal(t, b1.Header.Hash(), block.Header.Hash(), "Block hashes did no match")
   171  }
   172  
   173  func TestAddition(t *testing.T) {
   174  	tev, fl := initialize(t)
   175  	defer tev.tearDown()
   176  	info, _ := fl.blockStore.GetBlockchainInfo()
   177  	prevHash := info.CurrentBlockHash
   178  	fl.Append(ledger.CreateNextBlock(fl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}))
   179  	assert.Equal(t, uint64(2), fl.Height(), "Block height should be 2")
   180  
   181  	block := ledger.GetBlock(fl, 1)
   182  	assert.NotNil(t, block, "Error retrieving genesis block")
   183  	assert.Equal(t, prevHash, block.Header.PreviousHash, "Block hashes did no match")
   184  }
   185  
   186  func TestRetrieval(t *testing.T) {
   187  	tev, fl := initialize(t)
   188  	defer tev.tearDown()
   189  	fl.Append(ledger.CreateNextBlock(fl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}))
   190  	it, num := fl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Oldest{}})
   191  	assert.Zero(t, num, "Expected genesis block iterator, but got %d", num)
   192  
   193  	signal := it.ReadyChan()
   194  	select {
   195  	case <-signal:
   196  	default:
   197  		t.Fatalf("Should be ready for block read")
   198  	}
   199  
   200  	block, status := it.Next()
   201  	assert.Equal(t, cb.Status_SUCCESS, status, "Expected to successfully read the genesis block")
   202  	assert.Zero(t, block.Header.Number, "Expected to successfully retrieve the genesis block")
   203  
   204  	signal = it.ReadyChan()
   205  	select {
   206  	case <-signal:
   207  	default:
   208  		t.Fatalf("Should still be ready for block read")
   209  	}
   210  
   211  	block, status = it.Next()
   212  	assert.Equal(t, cb.Status_SUCCESS, status, "Expected to successfully read the second block")
   213  	assert.Equal(
   214  		t,
   215  		uint64(1),
   216  		block.Header.Number,
   217  		"Expected to successfully retrieve the second block but got block number %d", block.Header.Number)
   218  }
   219  
   220  func TestBlockedRetrieval(t *testing.T) {
   221  	tev, fl := initialize(t)
   222  	defer tev.tearDown()
   223  	it, num := fl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}})
   224  	if num != 1 {
   225  		t.Fatalf("Expected block iterator at 1, but got %d", num)
   226  	}
   227  	assert.Equal(t, uint64(1), num, "Expected block iterator at 1, but got %d", num)
   228  
   229  	signal := it.ReadyChan()
   230  	select {
   231  	case <-signal:
   232  		t.Fatalf("Should not be ready for block read")
   233  	default:
   234  	}
   235  
   236  	fl.Append(ledger.CreateNextBlock(fl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}))
   237  	select {
   238  	case <-signal:
   239  	default:
   240  		t.Fatalf("Should now be ready for block read")
   241  	}
   242  
   243  	block, status := it.Next()
   244  	assert.Equal(t, cb.Status_SUCCESS, status, "Expected to successfully read the second block")
   245  	assert.Equal(
   246  		t,
   247  		uint64(1),
   248  		block.Header.Number,
   249  		"Expected to successfully retrieve the second block but got block number %d", block.Header.Number)
   250  
   251  	go func() {
   252  		fl.Append(ledger.CreateNextBlock(fl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}))
   253  	}()
   254  	select {
   255  	case <-it.ReadyChan():
   256  		t.Fatalf("Should not be ready for block read")
   257  	default:
   258  		block, status = it.Next()
   259  		assert.Equal(t, cb.Status_SUCCESS, status, "Expected to successfully read the third block")
   260  		assert.Equal(t, uint64(2), block.Header.Number, "Expected to successfully retrieve the third block")
   261  	}
   262  }
   263  
   264  func TestBlockstoreError(t *testing.T) {
   265  	// Since this test only ensures failed GetBlockchainInfo
   266  	// is properly handled. We don't bother creating fully
   267  	// legit ledgers here (without genesis block).
   268  	{
   269  		fl := &fileLedger{
   270  			blockStore: &mockBlockStore{
   271  				blockchainInfo:         nil,
   272  				getBlockchainInfoError: fmt.Errorf("Error getting blockchain info"),
   273  			},
   274  			signal: make(chan struct{}),
   275  		}
   276  		assert.Panics(
   277  			t,
   278  			func() {
   279  				fl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Newest{}})
   280  			},
   281  			"Expected Iterator() to panic if blockstore operation fails")
   282  
   283  		assert.Panics(
   284  			t,
   285  			func() { fl.Height() },
   286  			"Expected Height() to panic if blockstore operation fails ")
   287  	}
   288  
   289  	{
   290  		fl := &fileLedger{
   291  			blockStore: &mockBlockStore{
   292  				blockchainInfo:             &cb.BlockchainInfo{Height: uint64(1)},
   293  				getBlockchainInfoError:     nil,
   294  				retrieveBlockByNumberError: fmt.Errorf("Error retrieving block by number"),
   295  			},
   296  			signal: make(chan struct{}),
   297  		}
   298  		it, _ := fl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 42}}})
   299  		assert.IsType(
   300  			t,
   301  			&ledger.NotFoundErrorIterator{},
   302  			it,
   303  			"Expected Not Found Error if seek number is greater than ledger height")
   304  
   305  		it, _ = fl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Oldest{}})
   306  		_, status := it.Next()
   307  		assert.Equal(t, cb.Status_SERVICE_UNAVAILABLE, status, "Expected service unavailable error")
   308  	}
   309  }