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