github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/orderer/ledger/ram/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 ramledger 18 19 import ( 20 "testing" 21 22 "github.com/hyperledger/fabric/common/configtx/tool/provisional" 23 "github.com/hyperledger/fabric/orderer/ledger" 24 cb "github.com/hyperledger/fabric/protos/common" 25 ab "github.com/hyperledger/fabric/protos/orderer" 26 27 logging "github.com/op/go-logging" 28 ) 29 30 var genesisBlock = cb.NewBlock(0, nil) 31 32 func init() { 33 logging.SetLevel(logging.DEBUG, "") 34 } 35 36 func newTestChain(maxSize int) *ramLedger { 37 rlf := New(maxSize) 38 chain, err := rlf.GetOrCreate(provisional.TestChainID) 39 if err != nil { 40 panic(err) 41 } 42 chain.Append(genesisBlock) 43 return chain.(*ramLedger) 44 } 45 46 // TestAppend ensures that appending blocks stores only the maxSize most recent blocks 47 // Note that 'only' is applicable because the genesis block will be discarded 48 func TestAppend(t *testing.T) { 49 maxSize := 3 50 rl := newTestChain(maxSize) 51 var blocks []*cb.Block 52 for i := 0; i < 3; i++ { 53 blocks = append(blocks, &cb.Block{Header: &cb.BlockHeader{Number: uint64(i + 1)}}) 54 rl.appendBlock(blocks[i]) 55 } 56 item := rl.oldest 57 for i := 0; i < 3; i++ { 58 if item.block == nil { 59 t.Fatalf("Block for item %d should not be nil", i) 60 } 61 if item.block.Header.Number != blocks[i].Header.Number { 62 t.Errorf("Expected block %d to be %d but got %d", i, blocks[i].Header.Number, item.block.Header.Number) 63 } 64 if i != 2 && item.next == nil { 65 t.Fatalf("Next item should not be nil") 66 } else { 67 item = item.next 68 } 69 } 70 } 71 72 // TestSignal checks if the signal channel closes when an item is appended 73 func TestSignal(t *testing.T) { 74 maxSize := 3 75 rl := newTestChain(maxSize) 76 item := rl.newest 77 select { 78 case <-item.signal: 79 t.Fatalf("There is no successor, there should be no signal to continue") 80 default: 81 } 82 rl.appendBlock(&cb.Block{Header: &cb.BlockHeader{Number: 1}}) 83 select { 84 case <-item.signal: 85 default: 86 t.Fatalf("There is a successor, there should be a signal to continue") 87 } 88 } 89 90 // TestTruncatingSafety is intended to simulate a reader who fetches a reference to the oldest list item 91 // which is then pushed off the history by appending greater than the history size (here, 10 appends with 92 // a maxSize of 3). We let the go garbage collector ensure the references still exist 93 func TestTruncationSafety(t *testing.T) { 94 maxSize := 3 95 newBlocks := 10 96 rl := newTestChain(maxSize) 97 item := rl.newest 98 for i := 0; i < newBlocks; i++ { 99 rl.appendBlock(&cb.Block{Header: &cb.BlockHeader{Number: uint64(i + 1)}}) 100 } 101 count := 0 102 for item.next != nil { 103 item = item.next 104 count++ 105 } 106 107 if count != newBlocks { 108 t.Fatalf("The iterator should have found %d new blocks but found %d", newBlocks, count) 109 } 110 } 111 112 func TestRetrieval(t *testing.T) { 113 rl := newTestChain(3) 114 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})) 115 it, num := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Oldest{}}) 116 if num != 0 { 117 t.Fatalf("Expected genesis block iterator, but got %d", num) 118 } 119 signal := it.ReadyChan() 120 select { 121 case <-signal: 122 default: 123 t.Fatalf("Should be ready for block read") 124 } 125 block, status := it.Next() 126 if status != cb.Status_SUCCESS { 127 t.Fatalf("Expected to successfully read the genesis block") 128 } 129 if block.Header.Number != 0 { 130 t.Fatalf("Expected to successfully retrieve the genesis block") 131 } 132 signal = it.ReadyChan() 133 select { 134 case <-signal: 135 default: 136 t.Fatalf("Should still be ready for block read") 137 } 138 block, status = it.Next() 139 if status != cb.Status_SUCCESS { 140 t.Fatalf("Expected to successfully read the second block") 141 } 142 if block.Header.Number != 1 { 143 t.Fatalf("Expected to successfully retrieve the second block but got block number %d", block.Header.Number) 144 } 145 } 146 147 func TestBlockedRetrieval(t *testing.T) { 148 rl := newTestChain(3) 149 it, num := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 150 if num != 1 { 151 t.Fatalf("Expected block iterator at 1, but got %d", num) 152 } 153 signal := it.ReadyChan() 154 select { 155 case <-signal: 156 t.Fatalf("Should not be ready for block read") 157 default: 158 } 159 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})) 160 select { 161 case <-signal: 162 default: 163 t.Fatalf("Should now be ready for block read") 164 } 165 block, status := it.Next() 166 if status != cb.Status_SUCCESS { 167 t.Fatalf("Expected to successfully read the second block") 168 } 169 if block.Header.Number != 1 { 170 t.Fatalf("Expected to successfully retrieve the second block") 171 } 172 } 173 174 func TestIteratorPastEnd(t *testing.T) { 175 rl := newTestChain(3) 176 it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 2}}}) 177 if _, status := it.Next(); status != cb.Status_NOT_FOUND { 178 t.Fatalf("Expected block with status NOT_FOUND, but got %d", status) 179 } 180 } 181 182 func TestIteratorOldest(t *testing.T) { 183 rl := newTestChain(3) 184 // add enough block to roll off the genesis block 185 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})) 186 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})) 187 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})) 188 _, num := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 189 if num != 1 { 190 t.Fatalf("Expected block iterator at 1, but got %d", num) 191 } 192 } 193 194 func TestAppendBadBLock(t *testing.T) { 195 rl := newTestChain(3) 196 t.Run("BadBlockNumber", func(t *testing.T) { 197 nextBlock := ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}) 198 nextBlock.Header.Number = nextBlock.Header.Number + 1 199 if err := rl.Append(nextBlock); err == nil { 200 t.Fatalf("Expected Append to fail.") 201 } 202 }) 203 t.Run("BadPreviousHash", func(t *testing.T) { 204 nextBlock := ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}) 205 nextBlock.Header.PreviousHash = []byte("bad hash") 206 if err := rl.Append(nextBlock); err == nil { 207 t.Fatalf("Expected Append to fail.") 208 } 209 }) 210 }