Skip to content

Commit be768c7

Browse files
author
Jason Yellick
committed
Add generic blackbox rawledger tests
This changeset adds tests which are generally applicable to rawledger implementations. It enables these tests for both ramledger and for fileledger. You may notice that these tests are substantially similar to the tests in file ledger and were derived from there, substituting black box equivalents for the implementation details of fileledger. This new suite of tests also caught a bug in the ramledger implementation which could result in a crash when the specified block was exactly the block number of the oldest block in storage. A fix is included. Change-Id: I76813c8ba7853d47fa6ffa89b16ffc66b8ddfd5f Signed-off-by: Jason Yellick <[email protected]>
1 parent 987b757 commit be768c7

File tree

4 files changed

+333
-2
lines changed

4 files changed

+333
-2
lines changed

orderer/rawledger/blackbox_test.go

+207
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
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 rawledger_test
18+
19+
import (
20+
"bytes"
21+
"testing"
22+
23+
ab "github.com/hyperledger/fabric/orderer/atomicbroadcast"
24+
. "github.com/hyperledger/fabric/orderer/rawledger"
25+
)
26+
27+
type ledgerTestable interface {
28+
Initialize() (ledgerFactory, error)
29+
Name() string
30+
}
31+
32+
type ledgerFactory interface {
33+
New() ReadWriter
34+
Destroy() error
35+
Persistent() bool
36+
}
37+
38+
var testables []ledgerTestable
39+
40+
func getBlock(number uint64, li ReadWriter) *ab.Block {
41+
i, _ := li.Iterator(ab.SeekInfo_SPECIFIED, number)
42+
select {
43+
case <-i.ReadyChan():
44+
block, status := i.Next()
45+
if status != ab.Status_SUCCESS {
46+
return nil
47+
}
48+
return block
49+
default:
50+
return nil
51+
}
52+
}
53+
54+
func allTest(t *testing.T, test func(ledgerFactory, *testing.T)) {
55+
for _, lt := range testables {
56+
57+
t.Log("Running test for", lt.Name())
58+
59+
func() {
60+
lf, err := lt.Initialize()
61+
if err != nil {
62+
t.Fatalf("Error initializing %s: %s", lt.Name(), err)
63+
}
64+
test(lf, t)
65+
err = lf.Destroy()
66+
if err != nil {
67+
t.Fatalf("Error destroying %s: %s", lt.Name(), err)
68+
}
69+
}()
70+
71+
t.Log("Completed test successfully for", lt.Name())
72+
}
73+
}
74+
75+
func TestInitialization(t *testing.T) {
76+
allTest(t, testInitialization)
77+
}
78+
79+
func testInitialization(lf ledgerFactory, t *testing.T) {
80+
li := lf.New()
81+
if li.Height() != 1 {
82+
t.Fatalf("Block height should be 1")
83+
}
84+
block := getBlock(0, li)
85+
if block == nil {
86+
t.Fatalf("Error retrieving genesis block")
87+
}
88+
}
89+
90+
func TestReinitialization(t *testing.T) {
91+
allTest(t, testReinitialization)
92+
}
93+
94+
func testReinitialization(lf ledgerFactory, t *testing.T) {
95+
if !lf.Persistent() {
96+
t.Log("Skipping test as persistence is not available for this ledger type")
97+
return
98+
}
99+
oli := lf.New()
100+
aBlock := oli.Append([]*ab.BroadcastMessage{&ab.BroadcastMessage{Data: []byte("My Data")}}, nil)
101+
li := lf.New()
102+
if li.Height() != 2 {
103+
t.Fatalf("Block height should be 2")
104+
}
105+
block := getBlock(1, li)
106+
if block == nil {
107+
t.Fatalf("Error retrieving block 1")
108+
}
109+
if !bytes.Equal(block.Hash(), aBlock.Hash()) {
110+
t.Fatalf("Block hashes did no match")
111+
}
112+
}
113+
114+
func TestAddition(t *testing.T) {
115+
allTest(t, testAddition)
116+
}
117+
118+
func testAddition(lf ledgerFactory, t *testing.T) {
119+
li := lf.New()
120+
genesis := getBlock(0, li)
121+
if genesis == nil {
122+
t.Fatalf("Could not retrieve genesis block")
123+
}
124+
prevHash := genesis.Hash()
125+
126+
li.Append([]*ab.BroadcastMessage{&ab.BroadcastMessage{Data: []byte("My Data")}}, nil)
127+
if li.Height() != 2 {
128+
t.Fatalf("Block height should be 2")
129+
}
130+
block := getBlock(1, li)
131+
if block == nil {
132+
t.Fatalf("Error retrieving genesis block")
133+
}
134+
if !bytes.Equal(block.PrevHash, prevHash) {
135+
t.Fatalf("Block hashes did no match")
136+
}
137+
}
138+
139+
func TestRetrieval(t *testing.T) {
140+
allTest(t, testRetrieval)
141+
}
142+
143+
func testRetrieval(lf ledgerFactory, t *testing.T) {
144+
li := lf.New()
145+
li.Append([]*ab.BroadcastMessage{&ab.BroadcastMessage{Data: []byte("My Data")}}, nil)
146+
it, num := li.Iterator(ab.SeekInfo_OLDEST, 99)
147+
if num != 0 {
148+
t.Fatalf("Expected genesis block iterator, but got %d", num)
149+
}
150+
signal := it.ReadyChan()
151+
select {
152+
case <-signal:
153+
default:
154+
t.Fatalf("Should be ready for block read")
155+
}
156+
block, status := it.Next()
157+
if status != ab.Status_SUCCESS {
158+
t.Fatalf("Expected to successfully read the genesis block")
159+
}
160+
if block.Number != 0 {
161+
t.Fatalf("Expected to successfully retrieve the genesis block")
162+
}
163+
signal = it.ReadyChan()
164+
select {
165+
case <-signal:
166+
default:
167+
t.Fatalf("Should still be ready for block read")
168+
}
169+
block, status = it.Next()
170+
if status != ab.Status_SUCCESS {
171+
t.Fatalf("Expected to successfully read the second block")
172+
}
173+
if block.Number != 1 {
174+
t.Fatalf("Expected to successfully retrieve the second block but got block number %d", block.Number)
175+
}
176+
}
177+
178+
func TestBlockedRetrieval(t *testing.T) {
179+
allTest(t, testBlockedRetrieval)
180+
}
181+
182+
func testBlockedRetrieval(lf ledgerFactory, t *testing.T) {
183+
li := lf.New()
184+
it, num := li.Iterator(ab.SeekInfo_SPECIFIED, 1)
185+
if num != 1 {
186+
t.Fatalf("Expected block iterator at 1, but got %d", num)
187+
}
188+
signal := it.ReadyChan()
189+
select {
190+
case <-signal:
191+
t.Fatalf("Should not be ready for block read")
192+
default:
193+
}
194+
li.Append([]*ab.BroadcastMessage{&ab.BroadcastMessage{Data: []byte("My Data")}}, nil)
195+
select {
196+
case <-signal:
197+
default:
198+
t.Fatalf("Should now be ready for block read")
199+
}
200+
block, status := it.Next()
201+
if status != ab.Status_SUCCESS {
202+
t.Fatalf("Expected to successfully read the second block")
203+
}
204+
if block.Number != 1 {
205+
t.Fatalf("Expected to successfully retrieve the second block")
206+
}
207+
}

orderer/rawledger/fileledger_test.go

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
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 rawledger_test
18+
19+
import (
20+
"io/ioutil"
21+
"os"
22+
23+
. "github.com/hyperledger/fabric/orderer/rawledger"
24+
"github.com/hyperledger/fabric/orderer/rawledger/fileledger"
25+
)
26+
27+
func init() {
28+
testables = append(testables, &fileLedgerTestEnv{})
29+
}
30+
31+
type fileLedgerFactory struct {
32+
location string
33+
}
34+
35+
type fileLedgerTestEnv struct {
36+
}
37+
38+
func (env *fileLedgerTestEnv) Initialize() (ledgerFactory, error) {
39+
var err error
40+
location, err := ioutil.TempDir("", "hyperledger")
41+
if err != nil {
42+
return nil, err
43+
}
44+
return &fileLedgerFactory{location: location}, nil
45+
}
46+
47+
func (env *fileLedgerTestEnv) Name() string {
48+
return "fileledger"
49+
}
50+
51+
func (env *fileLedgerFactory) Destroy() error {
52+
err := os.RemoveAll(env.location)
53+
return err
54+
}
55+
56+
func (env *fileLedgerFactory) Persistent() bool {
57+
return true
58+
}
59+
60+
func (env *fileLedgerFactory) New() ReadWriter {
61+
return fileledger.New(env.location)
62+
}

orderer/rawledger/ramledger/ramledger.go

+13-2
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,22 @@ func (rl *ramLedger) Iterator(startType ab.SeekInfo_StartType, specified uint64)
8989
}
9090
close(list.signal)
9191
case ab.SeekInfo_SPECIFIED:
92-
list = rl.oldest
93-
if specified < list.block.Number || specified > rl.newest.block.Number+1 {
92+
oldest := rl.oldest
93+
if specified < oldest.block.Number || specified > rl.newest.block.Number+1 {
9494
return &rawledger.NotFoundErrorIterator{}, 0
9595
}
9696

97+
if specified == oldest.block.Number {
98+
list = &simpleList{
99+
block: &ab.Block{Number: oldest.block.Number - 1},
100+
next: oldest,
101+
signal: make(chan struct{}),
102+
}
103+
close(list.signal)
104+
break
105+
}
106+
107+
list = oldest
97108
for {
98109
if list.block.Number == specified-1 {
99110
break

orderer/rawledger/ramledger_test.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
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 rawledger_test
18+
19+
import (
20+
. "github.com/hyperledger/fabric/orderer/rawledger"
21+
"github.com/hyperledger/fabric/orderer/rawledger/ramledger"
22+
)
23+
24+
func init() {
25+
testables = append(testables, &ramLedgerTestEnv{})
26+
}
27+
28+
type ramLedgerFactory struct{}
29+
30+
type ramLedgerTestEnv struct{}
31+
32+
func (env *ramLedgerTestEnv) Initialize() (ledgerFactory, error) {
33+
return &ramLedgerFactory{}, nil
34+
}
35+
36+
func (env *ramLedgerTestEnv) Name() string {
37+
return "ramledger"
38+
}
39+
40+
func (env *ramLedgerFactory) Destroy() error {
41+
return nil
42+
}
43+
44+
func (env *ramLedgerFactory) Persistent() bool {
45+
return false
46+
}
47+
48+
func (env *ramLedgerFactory) New() ReadWriter {
49+
historySize := 10
50+
return ramledger.New(historySize)
51+
}

0 commit comments

Comments
 (0)