github.com/yacovm/fabric@v2.0.0-alpha.0.20191128145320-c5d4087dc723+incompatible/core/ledger/kvledger/tests/v1x_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package tests 8 9 import ( 10 "fmt" 11 "os" 12 "path" 13 "path/filepath" 14 "testing" 15 "time" 16 17 protopeer "github.com/hyperledger/fabric-protos-go/peer" 18 "github.com/hyperledger/fabric/common/ledger/testutil" 19 "github.com/hyperledger/fabric/core/ledger/kvledger" 20 "github.com/hyperledger/fabric/core/ledger/mock" 21 "github.com/hyperledger/fabric/core/ledger/util/couchdb" 22 "github.com/stretchr/testify/require" 23 ) 24 25 // TestV11 tests that a ledgersData folder created by v1.1 can be used with future releases in a backward compatible way 26 // The test data was generated by v1.1 code https://github.com/hyperledger/fabric/blob/release-1.1/core/ledger/kvledger/tests/v11_generate_test.go#L22 27 func TestV11(t *testing.T) { 28 env := newEnv(t) 29 defer env.cleanup() 30 31 ledgerFSRoot := env.initializer.Config.RootFSPath 32 // pass false so that 'ledgersData' directory will not be created when unzipped to ledgerFSRoot 33 require.NoError(t, testutil.Unzip("testdata/v11/sample_ledgers/ledgersData.zip", ledgerFSRoot, false)) 34 35 // verify init ledger panic and drop the corresponding db after each panic 36 checkInitLedgerPanicAndDropDBs(t, env, ledgerFSRoot, nil) 37 38 t.Logf("All stores are reformatted/dropped, now ledgermgmt initialization should not panic") 39 env.initLedgerMgmt() 40 41 h1, h2 := env.newTestHelperOpenLgr("ledger1", t), env.newTestHelperOpenLgr("ledger2", t) 42 dataHelper := &v1xSampleDataHelper{sampleDataVersion: "v1.1", t: t} 43 44 dataHelper.verify(h1) 45 dataHelper.verify(h2) 46 47 env.closeAllLedgersAndDrop(rebuildableStatedb + rebuildableBlockIndex + rebuildableConfigHistory + rebuildableHistoryDB) 48 h1, h2 = env.newTestHelperOpenLgr("ledger1", t), env.newTestHelperOpenLgr("ledger2", t) 49 dataHelper.verify(h1) 50 dataHelper.verify(h2) 51 } 52 53 // TestV13WithStateCouchdb tests that a ledgersData folder and couchdb data created by v1.3 can be read by latest fabric version in a backward compatible way 54 // The test data was generated by v1.3 code https://gerrit.hyperledger.org/r/#/c/fabric/+/34078/3/core/ledger/kvledger/tests/v13_generate_test.go@60 55 func TestV13WithStateCouchdb(t *testing.T) { 56 env := newEnv(t) 57 defer env.cleanup() 58 59 ledgerFSRoot := env.initializer.Config.RootFSPath 60 // pass false so that 'ledgersData' directory will not be created when unzipped to ledgerFSRoot 61 require.NoError(t, testutil.Unzip("testdata/v13_statecouchdb/sample_ledgers/ledgersData.zip", ledgerFSRoot, false)) 62 63 // unzip couchdb data to prepare the mount dir 64 couchdbDataUnzipDir := filepath.Join(ledgerFSRoot, "couchdbData") 65 require.NoError(t, os.Mkdir(couchdbDataUnzipDir, os.ModePerm)) 66 require.NoError(t, testutil.Unzip("testdata/v13_statecouchdb/sample_ledgers/couchdbData.zip", couchdbDataUnzipDir, false)) 67 68 // prepare the local.d mount dir to overwrite the number of shards and nodes so that they match the couchdb data generated from v1.3 69 localdHostDir := filepath.Join(ledgerFSRoot, "local.d") 70 require.NoError(t, os.MkdirAll(localdHostDir, os.ModePerm)) 71 testutil.CopyDir("testdata/v13_statecouchdb/couchdb_etc/local.d", localdHostDir, true) 72 73 // start couchdb using couchdbDataUnzipDir and localdHostDir as mount dirs 74 couchAddress, cleanup := couchDBSetup(t, couchdbDataUnzipDir, localdHostDir) 75 defer cleanup() 76 77 // set required config data to use state couchdb 78 couchdbConfig := &couchdb.Config{ 79 Address: couchAddress, 80 Username: "", 81 Password: "", 82 MaxRetries: 3, 83 MaxRetriesOnStartup: 3, 84 RequestTimeout: 10 * time.Second, 85 RedoLogPath: filepath.Join(ledgerFSRoot, "couchdbRedoLogs"), 86 } 87 env.initializer.Config.StateDBConfig.StateDatabase = "CouchDB" 88 env.initializer.Config.StateDBConfig.CouchDB = couchdbConfig 89 env.initializer.HealthCheckRegistry = &mock.HealthCheckRegistry{} 90 env.initializer.ChaincodeLifecycleEventProvider = &mock.ChaincodeLifecycleEventProvider{} 91 92 // verify init ledger panic and drop the corresponding db after each panic 93 checkInitLedgerPanicAndDropDBs(t, env, ledgerFSRoot, couchdbConfig) 94 95 t.Logf("All stores are reformatted/dropped, now ledgermgmt initialization should not panic") 96 env.initLedgerMgmt() 97 98 h1, h2 := env.newTestHelperOpenLgr("ledger1", t), env.newTestHelperOpenLgr("ledger2", t) 99 dataHelper := &v1xSampleDataHelper{sampleDataVersion: "v1.3", t: t} 100 101 dataHelper.verify(h1) 102 dataHelper.verify(h2) 103 104 // drop couchDB and other rebuildable dbs to test db rebuild 105 dropCouchDBs(t, couchdbConfig) 106 env.closeAllLedgersAndDrop(rebuildableBlockIndex + rebuildableConfigHistory + rebuildableHistoryDB) 107 h1, h2 = env.newTestHelperOpenLgr("ledger1", t), env.newTestHelperOpenLgr("ledger2", t) 108 dataHelper.verify(h1) 109 dataHelper.verify(h2) 110 } 111 112 func checkInitLedgerPanicAndDropDBs(t *testing.T, env *env, ledgerFSRoot string, couchdbConfig *couchdb.Config) { 113 t.Logf("verifying that a panic occurs because idStore has old format and then reformat the idstore to proceed") 114 idStorePath := kvledger.LedgerProviderPath(ledgerFSRoot) 115 require.PanicsWithValue( 116 t, 117 fmt.Sprintf("Error in instantiating ledger provider: unexpected format. db info = [leveldb for channel-IDs at [%s]], data format = [], expected format = [2.0]", 118 idStorePath), 119 func() { env.initLedgerMgmt() }, 120 "A panic should occur because idstore is in format 1.x", 121 ) 122 require.NoError(t, kvledger.UpgradeIDStoreFormat(ledgerFSRoot)) 123 124 t.Logf("verifying that a panic occurs because blockstore index has old format and then drop the idstore to proceed") 125 blkIndexPath := path.Join(kvledger.BlockStorePath(ledgerFSRoot), "index") 126 require.PanicsWithValue( 127 t, 128 fmt.Sprintf("Error in instantiating ledger provider: unexpected format. db info = [leveldb at [%s]], data format = [], expected format = [2.0]", 129 blkIndexPath), 130 func() { env.initLedgerMgmt() }, 131 "A panic should occur because block store index is in format 1.x", 132 ) 133 require.NoError(t, os.RemoveAll(blkIndexPath)) 134 135 t.Logf("verifying that a panic occurs because historydb has old format and then drop the historydb to proceed") 136 historyDBPath := kvledger.HistoryDBPath(ledgerFSRoot) 137 require.PanicsWithValue( 138 t, 139 fmt.Sprintf("Error in instantiating ledger provider: unexpected format. db info = [leveldb at [%s]], data format = [], expected format = [2.0]", 140 historyDBPath), 141 func() { env.initLedgerMgmt() }, 142 "A panic should occur because history is in format 1.x", 143 ) 144 require.NoError(t, os.RemoveAll(historyDBPath)) 145 146 if couchdbConfig == nil { 147 t.Logf("verifying that a panic occurs because stateleveldb has old format and then drop the statedb to proceed") 148 stateLevelDBPath := kvledger.StateDBPath(ledgerFSRoot) 149 require.PanicsWithValue( 150 t, 151 fmt.Sprintf( 152 "Error in instantiating ledger provider: unexpected format. db info = [leveldb at [%s]], data format = [], expected format = [2.0]", 153 stateLevelDBPath, 154 ), 155 func() { env.initLedgerMgmt() }, 156 "A panic should occur because statedb is in format 1.x", 157 ) 158 require.NoError(t, os.RemoveAll(stateLevelDBPath)) 159 } else { 160 t.Logf("verifying that a panic occurs because statecouchdb has old format and then drop the statedb to proceed") 161 require.PanicsWithValue( 162 t, 163 fmt.Sprintf( 164 "Error in instantiating ledger provider: unexpected format. db info = [CouchDB for state database], data format = [], expected format = [2.0]"), 165 func() { env.initLedgerMgmt() }, 166 "A panic should occur because statedb is in format 1.x", 167 ) 168 dropCouchDBs(t, couchdbConfig) 169 } 170 } 171 172 // v1xSampleDataHelper provides a set of functions to verify the ledger (after upgraded to latest data format). 173 // It verifies the ledger under the assumption that the ledger was generated by the specific generation code from v1.1 or v1.3. 174 // For v1.1, the sample ledger data was generated by https://github.com/hyperledger/fabric/blob/release-1.1/core/ledger/kvledger/tests/v11_generate_test.go#L22 175 // This generate function constructed two ledgers and populateed the ledgers using this code 176 // (https://github.com/hyperledger/fabric/blob/release-1.1/core/ledger/kvledger/tests/sample_data_helper.go#L55) 177 // For v1.3, the sample ledger data was generated by CR (https://gerrit.hyperledger.org/r/#/c/fabric/+/34078/3/core/ledger/kvledger/tests/v13_generate_test.go@60). 178 // This generate function constructed two ledgers and populated the ledgers using this code 179 // (https://github.com/hyperledger/fabric/blob/release-1.3/core/ledger/kvledger/tests/sample_data_helper.go#L55) 180 type v1xSampleDataHelper struct { 181 sampleDataVersion string 182 t *testing.T 183 } 184 185 func (d *v1xSampleDataHelper) verify(h *testhelper) { 186 d.verifyState(h) 187 d.verifyBlockAndPvtdata(h) 188 d.verifyGetTransactionByID(h) 189 d.verifyConfigHistory(h) 190 d.verifyHistory(h) 191 } 192 193 func (d *v1xSampleDataHelper) verifyState(h *testhelper) { 194 lgrid := h.lgrid 195 h.verifyPubState("cc1", "key1", d.sampleVal("value13", lgrid)) 196 h.verifyPubState("cc1", "key2", "") 197 h.verifyPvtState("cc1", "coll1", "key3", d.sampleVal("value14", lgrid)) 198 h.verifyPvtState("cc1", "coll1", "key4", "") 199 h.verifyPvtState("cc1", "coll2", "key3", d.sampleVal("value09", lgrid)) 200 h.verifyPvtState("cc1", "coll2", "key4", d.sampleVal("value10", lgrid)) 201 202 h.verifyPubState("cc2", "key1", d.sampleVal("value03", lgrid)) 203 h.verifyPubState("cc2", "key2", d.sampleVal("value04", lgrid)) 204 h.verifyPvtState("cc2", "coll1", "key3", d.sampleVal("value07", lgrid)) 205 h.verifyPvtState("cc2", "coll1", "key4", d.sampleVal("value08", lgrid)) 206 h.verifyPvtState("cc2", "coll2", "key3", d.sampleVal("value11", lgrid)) 207 h.verifyPvtState("cc2", "coll2", "key4", d.sampleVal("value12", lgrid)) 208 } 209 210 func (d *v1xSampleDataHelper) verifyHistory(h *testhelper) { 211 lgrid := h.lgrid 212 expectedHistoryCC1Key1 := []string{ 213 d.sampleVal("value13", lgrid), 214 d.sampleVal("value01", lgrid), 215 } 216 h.verifyHistory("cc1", "key1", expectedHistoryCC1Key1) 217 } 218 219 func (d *v1xSampleDataHelper) verifyConfigHistory(h *testhelper) { 220 lgrid := h.lgrid 221 h.verifyMostRecentCollectionConfigBelow(10, "cc1", 222 &expectedCollConfInfo{5, d.sampleCollConf2(lgrid, "cc1")}) 223 224 h.verifyMostRecentCollectionConfigBelow(5, "cc1", 225 &expectedCollConfInfo{3, d.sampleCollConf1(lgrid, "cc1")}) 226 227 h.verifyMostRecentCollectionConfigBelow(10, "cc2", 228 &expectedCollConfInfo{5, d.sampleCollConf2(lgrid, "cc2")}) 229 230 h.verifyMostRecentCollectionConfigBelow(5, "cc2", 231 &expectedCollConfInfo{3, d.sampleCollConf1(lgrid, "cc2")}) 232 } 233 234 func (d *v1xSampleDataHelper) verifyConfigHistoryDoesNotExist(h *testhelper) { 235 h.verifyMostRecentCollectionConfigBelow(10, "cc1", nil) 236 h.verifyMostRecentCollectionConfigBelow(10, "cc2", nil) 237 } 238 239 func (d *v1xSampleDataHelper) verifyBlockAndPvtdata(h *testhelper) { 240 lgrid := h.lgrid 241 h.verifyBlockAndPvtData(2, nil, func(r *retrievedBlockAndPvtdata) { 242 r.hasNumTx(2) 243 r.hasNoPvtdata() 244 }) 245 246 h.verifyBlockAndPvtData(4, nil, func(r *retrievedBlockAndPvtdata) { 247 r.hasNumTx(2) 248 r.pvtdataShouldContain(0, "cc1", "coll1", "key3", d.sampleVal("value05", lgrid)) 249 r.pvtdataShouldContain(1, "cc2", "coll1", "key3", d.sampleVal("value07", lgrid)) 250 }) 251 } 252 253 func (d *v1xSampleDataHelper) verifyGetTransactionByID(h *testhelper) { 254 h.verifyTxValidationCode("txid7", protopeer.TxValidationCode_VALID) 255 h.verifyTxValidationCode("txid8", protopeer.TxValidationCode_MVCC_READ_CONFLICT) 256 } 257 258 func (d *v1xSampleDataHelper) sampleVal(val, ledgerid string) string { 259 return fmt.Sprintf("%s:%s", val, ledgerid) 260 } 261 262 func (d *v1xSampleDataHelper) sampleCollConf1(ledgerid, ccName string) []*collConf { 263 switch d.sampleDataVersion { 264 case "v1.1": 265 return []*collConf{ 266 {name: "coll1", members: []string{"org1", "org2"}}, 267 {name: ledgerid, members: []string{"org1", "org2"}}, 268 {name: ccName, members: []string{"org1", "org2"}}, 269 } 270 case "v1.3": 271 return []*collConf{ 272 {name: "coll1"}, 273 {name: ledgerid}, 274 {name: ccName}, 275 } 276 default: 277 // should not happen 278 require.Failf(d.t, "sample data version %s is wrong", d.sampleDataVersion) 279 return nil 280 } 281 } 282 283 func (d *v1xSampleDataHelper) sampleCollConf2(ledgerid string, ccName string) []*collConf { 284 switch d.sampleDataVersion { 285 case "v1.1": 286 return []*collConf{ 287 {name: "coll1", members: []string{"org1", "org2"}}, 288 {name: "coll2", members: []string{"org1", "org2"}}, 289 {name: ledgerid, members: []string{"org1", "org2"}}, 290 {name: ccName, members: []string{"org1", "org2"}}, 291 } 292 case "v1.3": 293 return []*collConf{ 294 {name: "coll1"}, 295 {name: "coll2"}, 296 {name: ledgerid}, 297 {name: ccName}, 298 } 299 default: 300 // should not happen 301 require.Failf(d.t, "sample data version %s is wrong", d.sampleDataVersion) 302 return nil 303 } 304 }