github.com/myafeier/fabric@v1.0.1-0.20170722181825-3a4b1f2bce86/orderer/common/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/common/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 defer it.Close() 117 if num != 0 { 118 t.Fatalf("Expected genesis block iterator, but got %d", num) 119 } 120 signal := it.ReadyChan() 121 select { 122 case <-signal: 123 default: 124 t.Fatalf("Should be ready for block read") 125 } 126 block, status := it.Next() 127 if status != cb.Status_SUCCESS { 128 t.Fatalf("Expected to successfully read the genesis block") 129 } 130 if block.Header.Number != 0 { 131 t.Fatalf("Expected to successfully retrieve the genesis block") 132 } 133 signal = it.ReadyChan() 134 select { 135 case <-signal: 136 default: 137 t.Fatalf("Should still be ready for block read") 138 } 139 block, status = it.Next() 140 if status != cb.Status_SUCCESS { 141 t.Fatalf("Expected to successfully read the second block") 142 } 143 if block.Header.Number != 1 { 144 t.Fatalf("Expected to successfully retrieve the second block but got block number %d", block.Header.Number) 145 } 146 } 147 148 func TestBlockedRetrieval(t *testing.T) { 149 rl := newTestChain(3) 150 it, num := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 151 defer it.Close() 152 if num != 1 { 153 t.Fatalf("Expected block iterator at 1, but got %d", num) 154 } 155 signal := it.ReadyChan() 156 select { 157 case <-signal: 158 t.Fatalf("Should not be ready for block read") 159 default: 160 } 161 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})) 162 select { 163 case <-signal: 164 default: 165 t.Fatalf("Should now be ready for block read") 166 } 167 block, status := it.Next() 168 if status != cb.Status_SUCCESS { 169 t.Fatalf("Expected to successfully read the second block") 170 } 171 if block.Header.Number != 1 { 172 t.Fatalf("Expected to successfully retrieve the second block") 173 } 174 } 175 176 func TestIteratorPastEnd(t *testing.T) { 177 rl := newTestChain(3) 178 it, _ := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 2}}}) 179 defer it.Close() 180 if _, status := it.Next(); status != cb.Status_NOT_FOUND { 181 t.Fatalf("Expected block with status NOT_FOUND, but got %d", status) 182 } 183 } 184 185 func TestIteratorOldest(t *testing.T) { 186 rl := newTestChain(3) 187 // add enough block to roll off the genesis block 188 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})) 189 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})) 190 rl.Append(ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}})) 191 it, num := rl.Iterator(&ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: 1}}}) 192 defer it.Close() 193 if num != 1 { 194 t.Fatalf("Expected block iterator at 1, but got %d", num) 195 } 196 } 197 198 func TestAppendBadBLock(t *testing.T) { 199 rl := newTestChain(3) 200 t.Run("BadBlockNumber", func(t *testing.T) { 201 nextBlock := ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}) 202 nextBlock.Header.Number = nextBlock.Header.Number + 1 203 if err := rl.Append(nextBlock); err == nil { 204 t.Fatalf("Expected Append to fail.") 205 } 206 }) 207 t.Run("BadPreviousHash", func(t *testing.T) { 208 nextBlock := ledger.CreateNextBlock(rl, []*cb.Envelope{&cb.Envelope{Payload: []byte("My Data")}}) 209 nextBlock.Header.PreviousHash = []byte("bad hash") 210 if err := rl.Append(nextBlock); err == nil { 211 t.Fatalf("Expected Append to fail.") 212 } 213 }) 214 }