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 }