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  }