Skip to content

Commit

Permalink
Enable additional ledger txmgr unit tests
Browse files Browse the repository at this point in the history
Some tests were disabled while CouchDB was getting fully functional.
This changeset re-enables all txmgr tests, fixes some of the
tests, and ensures that all tests are run against both LevelDB
and CouchDB environmnents, to ensure consistent results
against the different state databases.

Change-Id: I5fedbb1457bc45dfd1b33c950e1b4041b3749c64
Signed-off-by: denyeart <enyeart@us.ibm.com>
  • Loading branch information
denyeart committed Mar 3, 2017
1 parent 820e2cb commit f330daa
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 87 deletions.
56 changes: 24 additions & 32 deletions core/ledger/kvledger/txmgmt/txmgr/commontests/pkg_test.go
Expand Up @@ -25,8 +25,6 @@ import (
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb/stateleveldb"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/txmgr"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr"
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
ledgertestutil "github.com/hyperledger/fabric/core/ledger/testutil"
"github.com/hyperledger/fabric/core/ledger/util"
"github.com/hyperledger/fabric/protos/common"
"github.com/spf13/viper"
Expand All @@ -37,48 +35,40 @@ const (
)

type testEnv interface {
init(t *testing.T)
init(t *testing.T, testLedgerID string)
getName() string
getTxMgr() txmgr.TxMgr
getVDB() statedb.VersionedDB
cleanup()
}

var testEnvs = []testEnv{}

func init() {
//call a helper method to load the core.yaml so that we can detect whether couch is configured
ledgertestutil.SetupCoreYAMLConfig("./../../../../../../peer")

//Only run the tests if CouchDB is explitily enabled in the code,
//otherwise CouchDB may not be installed and all the tests would fail
if ledgerconfig.IsCouchDBEnabled() == true {
testEnvs = []testEnv{&levelDBLockBasedEnv{}, &couchDBLockBasedEnv{}}
} else {
testEnvs = []testEnv{&levelDBLockBasedEnv{}}
}

}
// Tests will be run against each environment in this array
// For example, to skip CouchDB tests, remove &couchDBLockBasedEnv{}
var testEnvs = []testEnv{&levelDBLockBasedEnv{}, &couchDBLockBasedEnv{}}

///////////// LevelDB Environment //////////////

const levelDBtestEnvName = "levelDB_LockBasedTxMgr"

type levelDBLockBasedEnv struct {
testDBEnv *stateleveldb.TestVDBEnv
testDB statedb.VersionedDB
txmgr txmgr.TxMgr
testLedgerID string
testDBEnv *stateleveldb.TestVDBEnv
testDB statedb.VersionedDB
txmgr txmgr.TxMgr
}

func (env *levelDBLockBasedEnv) getName() string {
return "levelDB_LockBasedTxMgr"
return levelDBtestEnvName
}

func (env *levelDBLockBasedEnv) init(t *testing.T) {
func (env *levelDBLockBasedEnv) init(t *testing.T, testLedgerID string) {
viper.Set("peer.fileSystemPath", testFilesystemPath)
testDBEnv := stateleveldb.NewTestVDBEnv(t)
testDB, err := testDBEnv.DBProvider.GetDBHandle("TestDB")
testDB, err := testDBEnv.DBProvider.GetDBHandle(testLedgerID)
testutil.AssertNoError(t, err, "")

txMgr := lockbasedtxmgr.NewLockBasedTxMgr(testDB)
env.testLedgerID = testLedgerID
env.testDBEnv = testDBEnv
env.testDB = testDB
env.txmgr = txMgr
Expand All @@ -99,27 +89,29 @@ func (env *levelDBLockBasedEnv) cleanup() {

///////////// CouchDB Environment //////////////

var couchTestChainID = "TxmgrTestDB"
const couchDBtestEnvName = "couchDB_LockBasedTxMgr"

type couchDBLockBasedEnv struct {
testDBEnv *statecouchdb.TestVDBEnv
testDB statedb.VersionedDB
txmgr txmgr.TxMgr
testLedgerID string
testDBEnv *statecouchdb.TestVDBEnv
testDB statedb.VersionedDB
txmgr txmgr.TxMgr
}

func (env *couchDBLockBasedEnv) getName() string {
return "couchDB_LockBasedTxMgr"
return couchDBtestEnvName
}

func (env *couchDBLockBasedEnv) init(t *testing.T) {
func (env *couchDBLockBasedEnv) init(t *testing.T, testLedgerID string) {
viper.Set("peer.fileSystemPath", testFilesystemPath)
// both vagrant and CI have couchdb configured at host "couchdb"
viper.Set("ledger.state.couchDBConfig.couchDBAddress", "couchdb:5984")
testDBEnv := statecouchdb.NewTestVDBEnv(t)
testDB, err := testDBEnv.DBProvider.GetDBHandle(couchTestChainID)
testDB, err := testDBEnv.DBProvider.GetDBHandle(testLedgerID)
testutil.AssertNoError(t, err, "")

txMgr := lockbasedtxmgr.NewLockBasedTxMgr(testDB)
env.testLedgerID = testLedgerID
env.testDBEnv = testDBEnv
env.testDB = testDB
env.txmgr = txMgr
Expand All @@ -135,7 +127,7 @@ func (env *couchDBLockBasedEnv) getVDB() statedb.VersionedDB {

func (env *couchDBLockBasedEnv) cleanup() {
defer env.txmgr.Shutdown()
defer env.testDBEnv.Cleanup(couchTestChainID)
defer env.testDBEnv.Cleanup(env.testLedgerID)
}

//////////// txMgrTestHelper /////////////
Expand Down
126 changes: 71 additions & 55 deletions core/ledger/kvledger/txmgmt/txmgr/commontests/txmgr_test.go
Expand Up @@ -24,13 +24,14 @@ import (
"github.com/hyperledger/fabric/common/ledger/testutil"
"github.com/hyperledger/fabric/core/ledger"
"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
)

func TestTxSimulatorWithNoExistingData(t *testing.T) {
// run the tests for each environment configured in pkg_test.go
for _, testEnv := range testEnvs {
t.Logf("Running test for TestEnv = %s", testEnv.getName())
testEnv.init(t)
testLedgerID := "testtxsimulatorwithnoexistingdata"
testEnv.init(t, testLedgerID)
testTxSimulatorWithNoExistingData(t, testEnv)
testEnv.cleanup()
}
Expand All @@ -55,7 +56,8 @@ func testTxSimulatorWithNoExistingData(t *testing.T, env testEnv) {
func TestTxSimulatorWithExistingData(t *testing.T) {
for _, testEnv := range testEnvs {
t.Run(testEnv.getName(), func(t *testing.T) {
testEnv.init(t)
testLedgerID := "testtxsimulatorwithexistingdata"
testEnv.init(t, testLedgerID)
testTxSimulatorWithExistingData(t, testEnv)
testEnv.cleanup()
})
Expand Down Expand Up @@ -99,16 +101,16 @@ func testTxSimulatorWithExistingData(t *testing.T, env testEnv) {

// verify the versions of keys in persistence
vv, _ := env.getVDB().GetState("ns1", "key1")
//TODO re-enable after adding couch version wrapper
//testutil.AssertEquals(t, vv.Version, version.NewHeight(2, 1))
testutil.AssertEquals(t, vv.Version, version.NewHeight(1, 1))
vv, _ = env.getVDB().GetState("ns1", "key2")
testutil.AssertEquals(t, vv.Version, version.NewHeight(0, 1))
}

func TestTxValidation(t *testing.T) {
for _, testEnv := range testEnvs {
t.Logf("Running test for TestEnv = %s", testEnv.getName())
testEnv.init(t)
testLedgerID := "testtxvalidation"
testEnv.init(t, testLedgerID)
testTxValidation(t, testEnv)
testEnv.cleanup()
}
Expand All @@ -128,7 +130,8 @@ func testTxValidation(t *testing.T, env testEnv) {
txRWSet1, _ := s1.GetTxSimulationResults()
txMgrHelper.validateAndCommitRWSet(txRWSet1)

// simulate tx2 that make changes to existing data
// simulate tx2 that make changes to existing data.
// tx2: Read/Update ns1:key1, Delete ns2:key3.
s2, _ := txMgr.NewTxSimulator()
value, _ := s2.GetState("ns1", "key1")
testutil.AssertEquals(t, value, []byte("value1"))
Expand All @@ -137,55 +140,64 @@ func testTxValidation(t *testing.T, env testEnv) {
s2.DeleteState("ns2", "key3")
s2.Done()

// simulate tx3 before committing tx2 changes. Reads and modifies the key changed by tx2
// simulate tx3 before committing tx2 changes. Reads and modifies the key changed by tx2.
// tx3: Read/Update ns1:key1
s3, _ := txMgr.NewTxSimulator()
s3.GetState("ns1", "key1")
s3.SetState("ns1", "key1", []byte("value1_3"))
s3.Done()

// simulate tx4 before committing tx2 changes. Reads and Deletes the key changed by tx2
// tx4: Read/Delete ns2:key3
s4, _ := txMgr.NewTxSimulator()
s4.GetState("ns2", "key3")
s4.DeleteState("ns2", "key3")
s4.Done()

// simulate tx5 before committing tx2 changes. Modifies and then Reads the key changed by tx2 and writes a new key
// tx5: Update/Read ns1:key1
s5, _ := txMgr.NewTxSimulator()
s5.SetState("ns1", "key1", []byte("new_value"))
s5.GetState("ns1", "key1")
s5.Done()

// simulate tx6 before committing tx2 changes. Only writes a new key, does not reads/writes a key changed by tx2
// tx6: Update ns1:new_key
s6, _ := txMgr.NewTxSimulator()
s6.SetState("ns1", "new_key", []byte("new_value"))
s6.Done()

// Summary of simulated transactions
// tx2: Read/Update ns1:key1, Delete ns2:key3.
// tx3: Read/Update ns1:key1
// tx4: Read/Delete ns2:key3
// tx5: Update/Read ns1:key1
// tx6: Update ns1:new_key

// validate and commit RWset for tx2
txRWSet2, _ := s2.GetTxSimulationResults()
txMgrHelper.validateAndCommitRWSet(txRWSet2)
//TODO re-enable after adding couch version wrapper
/*
//RWSet for tx3 and tx4 should not be invalid now
txRWSet3, _ := s3.GetTxSimulationResults()
txMgrHelper.checkRWsetInvalid(txRWSet3)
txRWSet4, _ := s4.GetTxSimulationResults()
txMgrHelper.checkRWsetInvalid(txRWSet4)
//tx5 shold still be valid as it over-writes the key first and then reads
txRWSet5, _ := s5.GetTxSimulationResults()
txMgrHelper.validateAndCommitRWSet(txRWSet5)
// tx6 should still be valid as it only writes a new key
txRWSet6, _ := s6.GetTxSimulationResults()
txMgrHelper.validateAndCommitRWSet(txRWSet6)
*/

//RWSet for tx3 and tx4 and tx5 should be invalid now due to read conflicts
txRWSet3, _ := s3.GetTxSimulationResults()
txMgrHelper.checkRWsetInvalid(txRWSet3)

txRWSet4, _ := s4.GetTxSimulationResults()
txMgrHelper.checkRWsetInvalid(txRWSet4)

txRWSet5, _ := s5.GetTxSimulationResults()
txMgrHelper.checkRWsetInvalid(txRWSet5)

// tx6 should still be valid as it only writes a new key
txRWSet6, _ := s6.GetTxSimulationResults()
txMgrHelper.validateAndCommitRWSet(txRWSet6)
}

func TestTxPhantomValidation(t *testing.T) {
for _, testEnv := range testEnvs {
t.Logf("Running test for TestEnv = %s", testEnv.getName())
testEnv.init(t)
testLedgerID := "testtxphantomvalidation"
testEnv.init(t, testLedgerID)
testTxPhantomValidation(t, testEnv)
testEnv.cleanup()
}
Expand Down Expand Up @@ -254,23 +266,29 @@ func testTxPhantomValidation(t *testing.T, env testEnv) {
func TestIterator(t *testing.T) {
for _, testEnv := range testEnvs {
t.Logf("Running test for TestEnv = %s", testEnv.getName())
testEnv.init(t)

testLedgerID := "testiterator_1"
testEnv.init(t, testLedgerID)
testIterator(t, testEnv, 10, 2, 7)
testEnv.cleanup()

testEnv.init(t)
testLedgerID = "testiterator_2"
testEnv.init(t, testLedgerID)
testIterator(t, testEnv, 10, 1, 11)
testEnv.cleanup()

testEnv.init(t)
testLedgerID = "testiterator_3"
testEnv.init(t, testLedgerID)
testIterator(t, testEnv, 10, 0, 0)
testEnv.cleanup()

testEnv.init(t)
testLedgerID = "testiterator_4"
testEnv.init(t, testLedgerID)
testIterator(t, testEnv, 10, 5, 0)
testEnv.cleanup()

testEnv.init(t)
testLedgerID = "testiterator_5"
testEnv.init(t, testLedgerID)
testIterator(t, testEnv, 10, 0, 5)
testEnv.cleanup()
}
Expand Down Expand Up @@ -337,7 +355,8 @@ func testIterator(t *testing.T, env testEnv, numKeys int, startKeyNum int, endKe
func TestIteratorWithDeletes(t *testing.T) {
for _, testEnv := range testEnvs {
t.Logf("Running test for TestEnv = %s", testEnv.getName())
testEnv.init(t)
testLedgerID := "testiteratorwithdeletes"
testEnv.init(t, testLedgerID)
testIteratorWithDeletes(t, testEnv)
testEnv.cleanup()
}
Expand Down Expand Up @@ -371,15 +390,16 @@ func testIteratorWithDeletes(t *testing.T, env testEnv) {
defer itr.Close()
kv, _ := itr.Next()
testutil.AssertEquals(t, kv.(*ledger.KV).Key, createTestKey(3))
//TODO re-enable after adding couch delete function
//kv, _ = itr.Next()
//testutil.AssertEquals(t, kv.(*ledger.KV).Key, createTestKey(5))

kv, _ = itr.Next()
testutil.AssertEquals(t, kv.(*ledger.KV).Key, createTestKey(5))
}

func TestTxValidationWithItr(t *testing.T) {
for _, testEnv := range testEnvs {
t.Logf("Running test for TestEnv = %s", testEnv.getName())
testEnv.init(t)
testLedgerID := "testtxvalidationwithitr"
testEnv.init(t, testLedgerID)
testTxValidationWithItr(t, testEnv)
testEnv.cleanup()
}
Expand Down Expand Up @@ -430,12 +450,9 @@ func testTxValidationWithItr(t *testing.T, env testEnv) {
txRWSet4, _ := s4.GetTxSimulationResults()
txMgrHelper.validateAndCommitRWSet(txRWSet4)

//TODO re-enable after adding couch version wrapper
/*
//RWSet tx3 should not be invalid now
txRWSet3, _ := s3.GetTxSimulationResults()
txMgrHelper.checkRWsetInvalid(txRWSet3)
*/
//RWSet tx3 should be invalid now
txRWSet3, _ := s3.GetTxSimulationResults()
txMgrHelper.checkRWsetInvalid(txRWSet3)

// tx2 should still be valid
txRWSet2, _ := s2.GetTxSimulationResults()
Expand All @@ -446,7 +463,8 @@ func testTxValidationWithItr(t *testing.T, env testEnv) {
func TestGetSetMultipeKeys(t *testing.T) {
for _, testEnv := range testEnvs {
t.Logf("Running test for TestEnv = %s", testEnv.getName())
testEnv.init(t)
testLedgerID := "testgetsetmultipekeys"
testEnv.init(t, testLedgerID)
testGetSetMultipeKeys(t, testEnv)
testEnv.cleanup()
}
Expand Down Expand Up @@ -504,18 +522,15 @@ func createTestValue(i int) []byte {
//TestExecuteQueryQuery is only tested on the CouchDB testEnv
func TestExecuteQuery(t *testing.T) {

// Query is only tested on the CouchDB testEnv
if ledgerconfig.IsCouchDBEnabled() == true {
testEnvs = []testEnv{&couchDBLockBasedEnv{}}
} else {
testEnvs = []testEnv{}
}

for _, testEnv := range testEnvs {
t.Logf("Running test for TestEnv = %s", testEnv.getName())
testEnv.init(t)
testExecuteQuery(t, testEnv)
testEnv.cleanup()
// Query is only supported and tested on the CouchDB testEnv
if testEnv.getName() == couchDBtestEnvName {
t.Logf("Running test for TestEnv = %s", testEnv.getName())
testLedgerID := "testexecutequery"
testEnv.init(t, testLedgerID)
testExecuteQuery(t, testEnv)
testEnv.cleanup()
}
}
}

Expand Down Expand Up @@ -560,7 +575,8 @@ func testExecuteQuery(t *testing.T, env testEnv) {
queryExecuter, _ := txMgr.NewQueryExecutor()
queryString := "{\"selector\":{\"owner\": {\"$eq\": \"bob\"}},\"limit\": 10,\"skip\": 0}"

itr, _ := queryExecuter.ExecuteQuery("ns1", queryString)
itr, err := queryExecuter.ExecuteQuery("ns1", queryString)
testutil.AssertNoError(t, err, "Error upon ExecuteQuery()")

counter := 0
for {
Expand Down

0 comments on commit f330daa

Please sign in to comment.