Skip to content

Commit f9cc350

Browse files
committed
[FAB-3407] Increase test coverage for mvcc validation
This CR - Introduces unit tests to improve the code coverage for package /fabric/core/ledger/kvledger/txmgmt/validator/statebasedval - Fixes a bug that was discovered by the new unit test for a boundary condition Change-Id: I2d7b41e3d721bfe6f4fc5869d22ffc7db66dc884 Signed-off-by: manish <[email protected]>
1 parent ecc29dd commit f9cc350

File tree

3 files changed

+121
-18
lines changed

3 files changed

+121
-18
lines changed

core/ledger/kvledger/txmgmt/validator/statebasedval/range_query_validator.go

-3
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,6 @@ func (v *rangeQueryResultsValidator) validate() (bool, error) {
7676
return false, err
7777
}
7878
}
79-
if result, err = itr.Next(); err != nil {
80-
return false, err
81-
}
8279
if result != nil {
8380
// iterator is not exhausted - which means that there are extra results in the given range
8481
logger.Debugf("Extra result = [%#v]", result)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
Copyright IBM Corp. 2017 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 statebasedval
18+
19+
import (
20+
"testing"
21+
22+
"github.com/hyperledger/fabric/common/ledger/testutil"
23+
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
24+
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb"
25+
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb/stateleveldb"
26+
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
27+
"github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset"
28+
)
29+
30+
func TestRangeQueryBoundaryConditions(t *testing.T) {
31+
batch := statedb.NewUpdateBatch()
32+
batch.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 0))
33+
batch.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 1))
34+
batch.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 2))
35+
batch.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 3))
36+
batch.Put("ns1", "key5", []byte("value5"), version.NewHeight(1, 4))
37+
38+
testcase1 := "NoResults"
39+
rqi1 := &kvrwset.RangeQueryInfo{StartKey: "key7", EndKey: "key10", ItrExhausted: true}
40+
rqi1.SetRawReads([]*kvrwset.KVRead{})
41+
testRangeQuery(t, testcase1, batch, version.NewHeight(1, 4), "ns1", rqi1, true)
42+
43+
testcase2 := "NoResultsDuringValidation"
44+
rqi2 := &kvrwset.RangeQueryInfo{StartKey: "key7", EndKey: "key10", ItrExhausted: true}
45+
rqi2.SetRawReads([]*kvrwset.KVRead{rwsetutil.NewKVRead("key8", version.NewHeight(1, 8))})
46+
testRangeQuery(t, testcase2, batch, version.NewHeight(1, 4), "ns1", rqi2, false)
47+
48+
testcase3 := "OneExtraTailingResultsDuringValidation"
49+
rqi3 := &kvrwset.RangeQueryInfo{StartKey: "key1", EndKey: "key4", ItrExhausted: true}
50+
rqi3.SetRawReads([]*kvrwset.KVRead{
51+
rwsetutil.NewKVRead("key1", version.NewHeight(1, 0)),
52+
rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
53+
})
54+
testRangeQuery(t, testcase3, batch, version.NewHeight(1, 4), "ns1", rqi3, false)
55+
56+
testcase4 := "TwoExtraTailingResultsDuringValidation"
57+
rqi4 := &kvrwset.RangeQueryInfo{StartKey: "key1", EndKey: "key5", ItrExhausted: true}
58+
rqi4.SetRawReads([]*kvrwset.KVRead{
59+
rwsetutil.NewKVRead("key1", version.NewHeight(1, 0)),
60+
rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
61+
})
62+
testRangeQuery(t, testcase4, batch, version.NewHeight(1, 4), "ns1", rqi4, false)
63+
}
64+
65+
func testRangeQuery(t *testing.T, testcase string, stateData *statedb.UpdateBatch, savepoint *version.Height,
66+
ns string, rqi *kvrwset.RangeQueryInfo, expectedResult bool) {
67+
t.Run(testcase, func(t *testing.T) {
68+
testDBEnv := stateleveldb.NewTestVDBEnv(t)
69+
defer testDBEnv.Cleanup()
70+
db, err := testDBEnv.DBProvider.GetDBHandle("TestDB")
71+
testutil.AssertNoError(t, err, "")
72+
if stateData != nil {
73+
db.ApplyUpdates(stateData, savepoint)
74+
}
75+
76+
itr, err := db.GetStateRangeScanIterator(ns, rqi.StartKey, rqi.EndKey)
77+
testutil.AssertNoError(t, err, "")
78+
validator := &rangeQueryResultsValidator{}
79+
validator.init(rqi, itr)
80+
isValid, err := validator.validate()
81+
testutil.AssertNoError(t, err, "")
82+
testutil.AssertEquals(t, isValid, expectedResult)
83+
})
84+
}

core/ledger/kvledger/txmgmt/validator/statebasedval/state_based_validator_test.go

+37-15
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/hyperledger/fabric/core/ledger/util"
2929
"github.com/hyperledger/fabric/protos/common"
3030
"github.com/hyperledger/fabric/protos/ledger/rwset/kvrwset"
31+
"github.com/hyperledger/fabric/protos/peer"
3132
"github.com/spf13/viper"
3233
)
3334

@@ -58,17 +59,17 @@ func TestValidator(t *testing.T) {
5859
rwsetBuilder1 := rwsetutil.NewRWSetBuilder()
5960
rwsetBuilder1.AddToReadSet("ns1", "key1", version.NewHeight(1, 0))
6061
rwsetBuilder1.AddToReadSet("ns2", "key2", nil)
61-
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet()}, []int{})
62+
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet()}, nil, []int{})
6263

6364
//rwset2 should not be valid
6465
rwsetBuilder2 := rwsetutil.NewRWSetBuilder()
6566
rwsetBuilder2.AddToReadSet("ns1", "key1", version.NewHeight(1, 1))
66-
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder2.GetTxReadWriteSet()}, []int{0})
67+
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder2.GetTxReadWriteSet()}, nil, []int{0})
6768

6869
//rwset3 should not be valid
6970
rwsetBuilder3 := rwsetutil.NewRWSetBuilder()
7071
rwsetBuilder3.AddToReadSet("ns1", "key1", nil)
71-
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder3.GetTxReadWriteSet()}, []int{0})
72+
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder3.GetTxReadWriteSet()}, nil, []int{0})
7273

7374
// rwset4 and rwset5 within same block - rwset4 should be valid and makes rwset5 as invalid
7475
rwsetBuilder4 := rwsetutil.NewRWSetBuilder()
@@ -78,7 +79,27 @@ func TestValidator(t *testing.T) {
7879
rwsetBuilder5 := rwsetutil.NewRWSetBuilder()
7980
rwsetBuilder5.AddToReadSet("ns1", "key1", version.NewHeight(1, 0))
8081
checkValidation(t, validator,
81-
[]*rwsetutil.TxRwSet{rwsetBuilder4.GetTxReadWriteSet(), rwsetBuilder5.GetTxReadWriteSet()}, []int{1})
82+
[]*rwsetutil.TxRwSet{rwsetBuilder4.GetTxReadWriteSet(), rwsetBuilder5.GetTxReadWriteSet()}, nil, []int{1})
83+
}
84+
85+
func TestValidatorSkipInvalidTxs(t *testing.T) {
86+
testDBEnv := stateleveldb.NewTestVDBEnv(t)
87+
defer testDBEnv.Cleanup()
88+
db, err := testDBEnv.DBProvider.GetDBHandle("TestDB")
89+
testutil.AssertNoError(t, err, "")
90+
validator := NewValidator(db)
91+
92+
rwsetBuilder1 := rwsetutil.NewRWSetBuilder()
93+
rwsetBuilder1.AddToWriteSet("ns1", "key1", []byte("value1"))
94+
rwsetBuilder2 := rwsetutil.NewRWSetBuilder()
95+
rwsetBuilder2.AddToWriteSet("ns1", "key2", []byte("value2"))
96+
rwsetBuilder3 := rwsetutil.NewRWSetBuilder()
97+
rwsetBuilder3.AddToWriteSet("ns1", "key3", []byte("value3"))
98+
flags := util.NewTxValidationFlags(4)
99+
flags.SetFlag(1, peer.TxValidationCode_BAD_CREATOR_SIGNATURE)
100+
checkValidation(t, validator,
101+
[]*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet(), rwsetBuilder2.GetTxReadWriteSet(), rwsetBuilder3.GetTxReadWriteSet()},
102+
flags, []int{1})
82103
}
83104

84105
func TestPhantomValidation(t *testing.T) {
@@ -106,7 +127,7 @@ func TestPhantomValidation(t *testing.T) {
106127
rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
107128
rwsetutil.NewKVRead("key3", version.NewHeight(1, 2))})
108129
rwsetBuilder1.AddToRangeQuerySet("ns1", rqi1)
109-
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet()}, []int{})
130+
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet()}, nil, []int{})
110131

111132
//rwset2 should not be valid - Version of key4 changed
112133
rwsetBuilder2 := rwsetutil.NewRWSetBuilder()
@@ -116,7 +137,7 @@ func TestPhantomValidation(t *testing.T) {
116137
rwsetutil.NewKVRead("key3", version.NewHeight(1, 2)),
117138
rwsetutil.NewKVRead("key4", version.NewHeight(1, 2))})
118139
rwsetBuilder2.AddToRangeQuerySet("ns1", rqi2)
119-
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder2.GetTxReadWriteSet()}, []int{0})
140+
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder2.GetTxReadWriteSet()}, nil, []int{0})
120141

121142
//rwset3 should not be valid - simulate key3 got commited to db
122143
rwsetBuilder3 := rwsetutil.NewRWSetBuilder()
@@ -125,7 +146,7 @@ func TestPhantomValidation(t *testing.T) {
125146
rwsetutil.NewKVRead("key2", version.NewHeight(1, 1)),
126147
rwsetutil.NewKVRead("key4", version.NewHeight(1, 3))})
127148
rwsetBuilder3.AddToRangeQuerySet("ns1", rqi3)
128-
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder3.GetTxReadWriteSet()}, []int{0})
149+
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder3.GetTxReadWriteSet()}, nil, []int{0})
129150

130151
// //Remove a key in rwset4 and rwset5 should become invalid
131152
rwsetBuilder4 := rwsetutil.NewRWSetBuilder()
@@ -138,7 +159,7 @@ func TestPhantomValidation(t *testing.T) {
138159
rwsetutil.NewKVRead("key4", version.NewHeight(1, 3))})
139160
rwsetBuilder5.AddToRangeQuerySet("ns1", rqi5)
140161
checkValidation(t, validator, []*rwsetutil.TxRwSet{
141-
rwsetBuilder4.GetTxReadWriteSet(), rwsetBuilder5.GetTxReadWriteSet()}, []int{1})
162+
rwsetBuilder4.GetTxReadWriteSet(), rwsetBuilder5.GetTxReadWriteSet()}, nil, []int{1})
142163

143164
//Add a key in rwset6 and rwset7 should become invalid
144165
rwsetBuilder6 := rwsetutil.NewRWSetBuilder()
@@ -152,7 +173,7 @@ func TestPhantomValidation(t *testing.T) {
152173
rwsetutil.NewKVRead("key4", version.NewHeight(1, 3))})
153174
rwsetBuilder7.AddToRangeQuerySet("ns1", rqi7)
154175
checkValidation(t, validator, []*rwsetutil.TxRwSet{
155-
rwsetBuilder6.GetTxReadWriteSet(), rwsetBuilder7.GetTxReadWriteSet()}, []int{1})
176+
rwsetBuilder6.GetTxReadWriteSet(), rwsetBuilder7.GetTxReadWriteSet()}, nil, []int{1})
156177
}
157178

158179
func TestPhantomHashBasedValidation(t *testing.T) {
@@ -190,7 +211,7 @@ func TestPhantomHashBasedValidation(t *testing.T) {
190211
}
191212
rqi1.SetMerkelSummary(buildTestHashResults(t, 2, kvReadsDuringSimulation1))
192213
rwsetBuilder1.AddToRangeQuerySet("ns1", rqi1)
193-
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet()}, []int{})
214+
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder1.GetTxReadWriteSet()}, nil, []int{})
194215

195216
rwsetBuilder2 := rwsetutil.NewRWSetBuilder()
196217
rqi2 := &kvrwset.RangeQueryInfo{StartKey: "key1", EndKey: "key9", ItrExhausted: false}
@@ -207,18 +228,19 @@ func TestPhantomHashBasedValidation(t *testing.T) {
207228
}
208229
rqi2.SetMerkelSummary(buildTestHashResults(t, 2, kvReadsDuringSimulation2))
209230
rwsetBuilder2.AddToRangeQuerySet("ns1", rqi2)
210-
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder2.GetTxReadWriteSet()}, []int{0})
231+
checkValidation(t, validator, []*rwsetutil.TxRwSet{rwsetBuilder2.GetTxReadWriteSet()}, nil, []int{0})
211232
}
212233

213-
func checkValidation(t *testing.T, validator *Validator, rwsets []*rwsetutil.TxRwSet, invalidTxIndexes []int) {
234+
func checkValidation(t *testing.T, validator *Validator, rwsets []*rwsetutil.TxRwSet,
235+
alreadyMarkedFlags util.TxValidationFlags, expectedInvalidTxIndexes []int) {
214236
simulationResults := [][]byte{}
215237
for _, txRWS := range rwsets {
216238
sr, err := txRWS.ToProtoBytes()
217239
testutil.AssertNoError(t, err, "")
218240
simulationResults = append(simulationResults, sr)
219241
}
220242
block := testutil.ConstructBlock(t, 1, []byte("dummyPreviousHash"), simulationResults, false)
221-
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = util.NewTxValidationFlags(len(block.Data.Data))
243+
block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = alreadyMarkedFlags
222244
_, err := validator.ValidateAndPrepareBatch(block, true)
223245
txsFltr := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
224246
invalidTxs := make([]int, 0)
@@ -228,8 +250,8 @@ func checkValidation(t *testing.T, validator *Validator, rwsets []*rwsetutil.TxR
228250
}
229251
}
230252
testutil.AssertNoError(t, err, "")
231-
testutil.AssertEquals(t, len(invalidTxs), len(invalidTxIndexes))
232-
testutil.AssertContainsAll(t, invalidTxs, invalidTxIndexes)
253+
testutil.AssertEquals(t, len(invalidTxs), len(expectedInvalidTxIndexes))
254+
testutil.AssertContainsAll(t, invalidTxs, expectedInvalidTxIndexes)
233255
}
234256

235257
func buildTestHashResults(t *testing.T, maxDegree int, kvReads []*kvrwset.KVRead) *kvrwset.QueryReadsMerkleSummary {

0 commit comments

Comments
 (0)