diff --git a/core/ledger/history/couchdb_histmgr.go b/core/ledger/history/couchdb_histmgr.go new file mode 100644 index 00000000000..1ae0f03b95d --- /dev/null +++ b/core/ledger/history/couchdb_histmgr.go @@ -0,0 +1,52 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package history + +import ( + "github.com/hyperledger/fabric/core/ledger/util/couchdb" + "github.com/hyperledger/fabric/protos/common" + logging "github.com/op/go-logging" +) + +var logger = logging.MustGetLogger("txhistorymgmt") + +// CouchDBHistMgr a simple implementation of interface `histmgmt.TxHistMgr'. +// TODO This implementation does not currently use a lock but may need one to insure query's are consistent +type CouchDBHistMgr struct { + couchDB *couchdb.CouchDBConnectionDef // COUCHDB new properties for CouchDB +} + +// NewCouchDBHistMgr constructs a new `CouchDBTxHistMgr` +func NewCouchDBHistMgr(couchDBConnectURL string, dbName string, id string, pw string) *CouchDBHistMgr { + + //TODO locking has not been implemented but may need some sort of locking to insure queries are valid data. + + couchDB, err := couchdb.CreateCouchDBConnectionAndDB(couchDBConnectURL, dbName, id, pw) + if err != nil { + logger.Errorf("Error during NewCouchDBHistMgr(): %s\n", err.Error()) + return nil + } + + // db and stateIndexCF will not be used for CouchDB. TODO to cleanup + return &CouchDBHistMgr{couchDB: couchDB} +} + +// Commit implements method in interface `txhistorymgmt.TxMgr` +func (histmgr *CouchDBHistMgr) Commit(block *common.Block) error { + logger.Debugf("===HISTORYDB=== Entering CouchDBTxHistMgr.Commit()") + return nil +} diff --git a/core/ledger/history/couchdb_histmgr_test.go b/core/ledger/history/couchdb_histmgr_test.go new file mode 100644 index 00000000000..9237abe08ca --- /dev/null +++ b/core/ledger/history/couchdb_histmgr_test.go @@ -0,0 +1,102 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package history + +import ( + "fmt" + "os" + "testing" + + "github.com/hyperledger/fabric/core/ledger/ledgerconfig" + "github.com/hyperledger/fabric/core/ledger/testutil" + "github.com/hyperledger/fabric/core/ledger/util/couchdb" +) + +//Complex setup to test the use of couch in ledger +type testEnvCouch struct { + couchDBPath string + couchDBAddress string + couchDatabaseName string + couchUsername string + couchPassword string +} + +func newTestEnvCouch(t testing.TB, dbPath string, dbName string) *testEnvCouch { + + couchDBDef := ledgerconfig.GetCouchDBDefinition() + os.RemoveAll(dbPath) + + return &testEnvCouch{ + couchDBPath: dbPath, + couchDBAddress: couchDBDef.URL, + couchDatabaseName: dbName, + couchUsername: couchDBDef.Username, + couchPassword: couchDBDef.Password, + } +} + +func (env *testEnvCouch) cleanup() { + os.RemoveAll(env.couchDBPath) + //create a new connection + couchDB, _ := couchdb.CreateConnectionDefinition(env.couchDBAddress, env.couchDatabaseName, env.couchUsername, env.couchPassword) + //drop the test database if it already existed + couchDB.DropDatabase() +} + +// couchdb_test.go tests couchdb functions already. This test just tests that a CouchDB history database is auto-created +// upon creating a new history transaction manager +func TestHistoryDatabaseAutoCreate(t *testing.T) { + + //call a helper method to load the core.yaml + testutil.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 + //TODO replace this with external config property rather than config within the code + if ledgerconfig.IsCouchDBEnabled() == true { + + env := newTestEnvCouch(t, "/tmp/tests/ledger/history", "history-test") + env.cleanup() //cleanup at the beginning to ensure the database doesn't exist already + defer env.cleanup() //and cleanup at the end + + histMgr := NewCouchDBHistMgr( + env.couchDBAddress, //couchDB Address + env.couchDatabaseName, //couchDB db name + env.couchUsername, //enter couchDB id + env.couchPassword) //enter couchDB pw + + //NewCouchDBhistMgr should have automatically created the database, let's make sure it has been created + //Retrieve the info for the new database and make sure the name matches + dbResp, _, errdb := histMgr.couchDB.GetDatabaseInfo() + testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information")) + testutil.AssertEquals(t, dbResp.DbName, env.couchDatabaseName) + + //Call NewCouchDBhistMgr again, this time the database will already exist from last time + histMgr2 := NewCouchDBHistMgr( + env.couchDBAddress, //couchDB Address + env.couchDatabaseName, //couchDB db name + env.couchUsername, //enter couchDB id + env.couchPassword) //enter couchDB pw + + //Retrieve the info for the database again, and make sure the name still matches + dbResp2, _, errdb2 := histMgr2.couchDB.GetDatabaseInfo() + testutil.AssertNoError(t, errdb2, fmt.Sprintf("Error when trying to retrieve database information")) + testutil.AssertEquals(t, dbResp2.DbName, env.couchDatabaseName) + + } + +} diff --git a/core/ledger/history/histmgmt.go b/core/ledger/history/histmgmt.go new file mode 100644 index 00000000000..b6c47bda0c9 --- /dev/null +++ b/core/ledger/history/histmgmt.go @@ -0,0 +1,24 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package history + +import "github.com/hyperledger/fabric/protos/common" + +// TxHistMgr - an interface that a transaction history manager should implement +type TxHistMgr interface { + Commit(block *common.Block) error +} diff --git a/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb_txmgmt_test.go b/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb_txmgmt_test.go index 6b38b1f037b..25ef9c05840 100644 --- a/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb_txmgmt_test.go +++ b/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb_txmgmt_test.go @@ -21,9 +21,9 @@ import ( "os" "testing" - "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb" "github.com/hyperledger/fabric/core/ledger/ledgerconfig" "github.com/hyperledger/fabric/core/ledger/testutil" + "github.com/hyperledger/fabric/core/ledger/util/couchdb" ) type testEnv struct { @@ -97,7 +97,7 @@ func TestDatabaseAutoCreate(t *testing.T) { env.couchPassword) //enter couchDB pw //Retrieve the info for the database again, and make sure the name still matches - dbResp2, _, errdb2 := txMgr.couchDB.GetDatabaseInfo() + dbResp2, _, errdb2 := txMgr2.couchDB.GetDatabaseInfo() testutil.AssertNoError(t, errdb2, fmt.Sprintf("Error when trying to retrieve database information")) testutil.AssertEquals(t, dbResp2.DbName, env.couchDatabaseName) diff --git a/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb_txmgr.go b/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb_txmgr.go index f9a6f2bebd6..3528b3d79e4 100644 --- a/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb_txmgr.go +++ b/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb_txmgr.go @@ -22,7 +22,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt" - "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb" + "github.com/hyperledger/fabric/core/ledger/util/couchdb" "github.com/hyperledger/fabric/core/ledger/util/db" "github.com/op/go-logging" @@ -74,6 +74,7 @@ type CouchDBTxMgr struct { } // CouchConnection provides connection info for CouchDB +//TODO not currently used type CouchConnection struct { host string port int @@ -89,18 +90,10 @@ func NewCouchDBTxMgr(conf *Conf, couchDBConnectURL string, dbName string, id str db := db.CreateDB(&db.Conf{DBPath: conf.DBPath}) db.Open() - couchDB, err := couchdb.CreateConnectionDefinition(couchDBConnectURL, - dbName, - id, - pw) + couchDB, err := couchdb.CreateCouchDBConnectionAndDB(couchDBConnectURL, dbName, id, pw) if err != nil { - logger.Errorf("===COUCHDB=== Error during CreateConnectionDefinition(): %s\n", err.Error()) - } - - // Create CouchDB database upon ledger startup, if it doesn't already exist - _, err = couchDB.CreateDatabaseIfNotExist() - if err != nil { - logger.Errorf("===COUCHDB=== Error during CreateDatabaseIfNotExist(): %s\n", err.Error()) + logger.Errorf("Error during NewCouchDBTxMgr(): %s\n", err.Error()) + return nil } // db and stateIndexCF will not be used for CouchDB. TODO to cleanup diff --git a/core/ledger/ledgerconfig/ledger_config_test.go b/core/ledger/ledgerconfig/ledger_config_test.go index 94b3fc1d172..3180c0f387c 100644 --- a/core/ledger/ledgerconfig/ledger_config_test.go +++ b/core/ledger/ledgerconfig/ledger_config_test.go @@ -25,6 +25,14 @@ import ( func TestIsCouchDBEnabledDefault(t *testing.T) { setUpCoreYAMLConfig() + // During a build the default values should be false. + + // If the ledger test are run with CouchDb enabled, need to provide a mechanism + // To let this test run but still test default values. + if IsCouchDBEnabled() == true { + testutil.ResetConfigToDefaultValues() + defer viper.Set("ledger.state.stateDatabase", "CouchDB") + } defaultValue := IsCouchDBEnabled() testutil.AssertEquals(t, defaultValue, false) //test default config is false } diff --git a/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb/couchdb.go b/core/ledger/util/couchdb/couchdb.go similarity index 100% rename from core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb/couchdb.go rename to core/ledger/util/couchdb/couchdb.go diff --git a/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb/couchdb_test.go b/core/ledger/util/couchdb/couchdb_test.go similarity index 99% rename from core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb/couchdb_test.go rename to core/ledger/util/couchdb/couchdb_test.go index 74f7a194834..bddae95c1d8 100644 --- a/core/ledger/kvledger/txmgmt/couchdbtxmgmt/couchdb/couchdb_test.go +++ b/core/ledger/util/couchdb/couchdb_test.go @@ -25,6 +25,20 @@ import ( "github.com/hyperledger/fabric/core/ledger/testutil" ) +//Basic setup to test couch +var connectURL = "localhost:5984" +var badConnectURL = "localhost:5990" +var database = "testdb1" +var username = "" +var password = "" + +func cleanup() { + //create a new connection + db, _ := CreateConnectionDefinition(connectURL, database, username, password) + //drop the test database + db.DropDatabase() +} + type Asset struct { ID string `json:"_id"` Rev string `json:"_rev"` @@ -34,18 +48,12 @@ type Asset struct { Owner string `json:"owner"` } -var connectURL = "localhost:5984" -var badConnectURL = "localhost:5990" -var database = "testdb1" -var username = "" -var password = "" - var assetJSON = []byte(`{"asset_name":"marble1","color":"blue","size":"35","owner":"jerry"}`) func TestDBConnectionDef(t *testing.T) { //call a helper method to load the core.yaml - testutil.SetupCoreYAMLConfig("./../../../../../../peer") + testutil.SetupCoreYAMLConfig("./../../../../peer") //create a new connection _, err := CreateConnectionDefinition(connectURL, "database", "", "") @@ -317,13 +325,3 @@ func TestDBTestDropDatabaseBadConnection(t *testing.T) { } } - -func cleanup() { - - //create a new connection - db, _ := CreateConnectionDefinition(connectURL, database, username, password) - - //drop the test database - db.DropDatabase() - -} diff --git a/core/ledger/util/couchdb/couchdbutil.go b/core/ledger/util/couchdb/couchdbutil.go new file mode 100644 index 00000000000..5b22c6c4d95 --- /dev/null +++ b/core/ledger/util/couchdb/couchdbutil.go @@ -0,0 +1,39 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package couchdb + +//CreateCouchDBConnectionAndDB creates a CouchDB Connection and the database if it does not exist +func CreateCouchDBConnectionAndDB(couchDBConnectURL string, dbName string, id string, pw string) (*CouchDBConnectionDef, error) { + couchDB, err := CreateConnectionDefinition(couchDBConnectURL, + dbName, + id, + pw) + if err != nil { + logger.Errorf("Error during CouchDB CreateConnectionDefinition() to dbName: %s error: %s\n", dbName, err.Error()) + return nil, err + } + + // Create CouchDB database upon ledger startup, if it doesn't already exist + _, err = couchDB.CreateDatabaseIfNotExist() + if err != nil { + logger.Errorf("Error during CouchDB CreateDatabaseIfNotExist() to dbName: %s error: %s\n", dbName, err.Error()) + return nil, err + } + + //return the couch db connection + return couchDB, nil +} diff --git a/core/ledger/util/couchdb/couchdbutil_test.go b/core/ledger/util/couchdb/couchdbutil_test.go new file mode 100644 index 00000000000..35d46ff2558 --- /dev/null +++ b/core/ledger/util/couchdb/couchdbutil_test.go @@ -0,0 +1,42 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package couchdb + +import ( + "fmt" + "testing" + + "github.com/hyperledger/fabric/core/ledger/ledgerconfig" + "github.com/hyperledger/fabric/core/ledger/testutil" +) + +//Unit test of couch db util functionality +func TestCreateCouchDBConnectionAndDB(t *testing.T) { + + //call a helper method to load the core.yaml + testutil.SetupCoreYAMLConfig("./../../../../peer") + + if ledgerconfig.IsCouchDBEnabled() == true { + + cleanup() + defer cleanup() + //create a new connection + _, err := CreateCouchDBConnectionAndDB(connectURL, database, "", "") + testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to CreateCouchDBConnectionAndDB")) + } + +}