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