github.com/ewagmig/fabric@v2.1.1+incompatible/core/ledger/util/couchdb/couchdbutil_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package couchdb
     8  
     9  import (
    10  	"encoding/hex"
    11  	"testing"
    12  
    13  	"github.com/hyperledger/fabric/common/metrics/disabled"
    14  	"github.com/hyperledger/fabric/common/util"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  //Unit test of couch db util functionality
    19  func TestCreateCouchDBConnectionAndDB(t *testing.T) {
    20  	startCouchDB()
    21  	database := "testcreatecouchdbconnectionanddb"
    22  	cleanup(database)
    23  	defer cleanup(database)
    24  	//create a new connection
    25  	couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{})
    26  	assert.NoError(t, err, "Error when trying to CreateCouchInstance")
    27  
    28  	_, err = CreateCouchDatabase(couchInstance, database)
    29  	assert.NoError(t, err, "Error when trying to CreateCouchDatabase")
    30  
    31  }
    32  
    33  //Unit test of couch db util functionality
    34  func TestNotCreateCouchGlobalChangesDB(t *testing.T) {
    35  	startCouchDB()
    36  	config := testConfig()
    37  	config.CreateGlobalChangesDB = false
    38  	database := "_global_changes"
    39  	cleanup(database)
    40  	defer cleanup(database)
    41  
    42  	//create a new connection
    43  	couchInstance, err := CreateCouchInstance(config, &disabled.Provider{})
    44  	assert.NoError(t, err, "Error when trying to CreateCouchInstance")
    45  
    46  	db := CouchDatabase{CouchInstance: couchInstance, DBName: database}
    47  
    48  	//Retrieve the info for the new database and make sure the name matches
    49  	_, _, errdb := db.GetDatabaseInfo()
    50  	assert.NotNil(t, errdb)
    51  }
    52  
    53  //Unit test of couch db util functionality
    54  func TestCreateCouchDBSystemDBs(t *testing.T) {
    55  	startCouchDB()
    56  	database := "testcreatecouchdbsystemdb"
    57  	cleanup(database)
    58  	defer cleanup(database)
    59  
    60  	//create a new connection
    61  	couchInstance, err := CreateCouchInstance(testConfig(), &disabled.Provider{})
    62  
    63  	assert.NoError(t, err, "Error when trying to CreateCouchInstance")
    64  
    65  	err = CreateSystemDatabasesIfNotExist(couchInstance)
    66  	assert.NoError(t, err, "Error when trying to create system databases")
    67  
    68  	db := CouchDatabase{CouchInstance: couchInstance, DBName: "_users"}
    69  
    70  	//Retrieve the info for the new database and make sure the name matches
    71  	dbResp, _, errdb := db.GetDatabaseInfo()
    72  	assert.NoError(t, errdb, "Error when trying to retrieve _users database information")
    73  	assert.Equal(t, "_users", dbResp.DbName)
    74  
    75  	db = CouchDatabase{CouchInstance: couchInstance, DBName: "_replicator"}
    76  
    77  	//Retrieve the info for the new database and make sure the name matches
    78  	dbResp, _, errdb = db.GetDatabaseInfo()
    79  	assert.NoError(t, errdb, "Error when trying to retrieve _replicator database information")
    80  	assert.Equal(t, "_replicator", dbResp.DbName)
    81  
    82  	db = CouchDatabase{CouchInstance: couchInstance, DBName: "_global_changes"}
    83  
    84  	//Retrieve the info for the new database and make sure the name matches
    85  	dbResp, _, errdb = db.GetDatabaseInfo()
    86  	assert.NoError(t, errdb, "Error when trying to retrieve _global_changes database information")
    87  	assert.Equal(t, "_global_changes", dbResp.DbName)
    88  
    89  }
    90  
    91  func TestDatabaseMapping(t *testing.T) {
    92  	//create a new instance and database object using a database name mixed case
    93  	_, err := mapAndValidateDatabaseName("testDB")
    94  	assert.Error(t, err, "Error expected because the name contains capital letters")
    95  
    96  	//create a new instance and database object using a database name with special characters
    97  	_, err = mapAndValidateDatabaseName("test1234/1")
    98  	assert.Error(t, err, "Error expected because the name contains illegal chars")
    99  
   100  	//create a new instance and database object using a database name with special characters
   101  	_, err = mapAndValidateDatabaseName("5test1234")
   102  	assert.Error(t, err, "Error expected because the name starts with a number")
   103  
   104  	//create a new instance and database object using an empty string
   105  	_, err = mapAndValidateDatabaseName("")
   106  	assert.Error(t, err, "Error should have been thrown for an invalid name")
   107  
   108  	_, err = mapAndValidateDatabaseName("a12345678901234567890123456789012345678901234" +
   109  		"56789012345678901234567890123456789012345678901234567890123456789012345678901234567890" +
   110  		"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456" +
   111  		"78901234567890123456789012345678901234567890")
   112  	assert.Error(t, err, "Error should have been thrown for an invalid name")
   113  
   114  	transformedName, err := mapAndValidateDatabaseName("test.my.db-1")
   115  	assert.NoError(t, err, "")
   116  	assert.Equal(t, "test$my$db-1", transformedName)
   117  }
   118  
   119  func TestConstructMetadataDBName(t *testing.T) {
   120  	// Allowed pattern for chainName: [a-z][a-z0-9.-]
   121  	chainName := "tob2g.y-z0f.qwp-rq5g4-ogid5g6oucyryg9sc16mz0t4vuake5q557esz7sn493nf0ghch0xih6dwuirokyoi4jvs67gh6r5v6mhz3-292un2-9egdcs88cstg3f7xa9m1i8v4gj0t3jedsm-woh3kgiqehwej6h93hdy5tr4v.1qmmqjzz0ox62k.507sh3fkw3-mfqh.ukfvxlm5szfbwtpfkd1r4j.cy8oft5obvwqpzjxb27xuw6"
   122  
   123  	truncatedChainName := "tob2g.y-z0f.qwp-rq5g4-ogid5g6oucyryg9sc16mz0t4vuak"
   124  	assert.Equal(t, chainNameAllowedLength, len(truncatedChainName))
   125  
   126  	// <first 50 chars (i.e., chainNameAllowedLength) of chainName> + 1 char for '(' + <64 chars for SHA256 hash
   127  	// (hex encoding) of untruncated chainName> + 1 char for ')' + 1 char for '_' = 117 chars
   128  	hash := hex.EncodeToString(util.ComputeSHA256([]byte(chainName)))
   129  	expectedDBName := truncatedChainName + "(" + hash + ")" + "_"
   130  	expectedDBNameLength := 117
   131  
   132  	constructedDBName := ConstructMetadataDBName(chainName)
   133  	assert.Equal(t, expectedDBNameLength, len(constructedDBName))
   134  	assert.Equal(t, expectedDBName, constructedDBName)
   135  }
   136  
   137  func TestConstructedNamespaceDBName(t *testing.T) {
   138  	// === SCENARIO 1: chainName_ns$$coll ===
   139  
   140  	// Allowed pattern for chainName: [a-z][a-z0-9.-]
   141  	chainName := "tob2g.y-z0f.qwp-rq5g4-ogid5g6oucyryg9sc16mz0t4vuake5q557esz7sn493nf0ghch0xih6dwuirokyoi4jvs67gh6r5v6mhz3-292un2-9egdcs88cstg3f7xa9m1i8v4gj0t3jedsm-woh3kgiqehwej6h93hdy5tr4v.1qmmqjzz0ox62k.507sh3fkw3-mfqh.ukfvxlm5szfbwtpfkd1r4j.cy8oft5obvwqpzjxb27xuw6"
   142  
   143  	// Allowed pattern for namespace and collection: [a-zA-Z0-9_-]
   144  	ns := "wMCnSXiV9YoIqNQyNvFVTdM8XnUtvrOFFIWsKelmP5NEszmNLl8YhtOKbFu3P_NgwgsYF8PsfwjYCD8f1XRpANQLoErDHwLlweryqXeJ6vzT2x0pS_GwSx0m6tBI0zOmHQOq_2De8A87x6zUOPwufC2T6dkidFxiuq8Sey2-5vUo_iNKCij3WTeCnKx78PUIg_U1gp4_0KTvYVtRBRvH0kz5usizBxPaiFu3TPhB9XLviScvdUVSbSYJ0Z"
   145  	// first letter 'p' denotes private data namespace. We can use 'h' to denote hashed data namespace as defined in
   146  	// privacyenabledstate/common_storage_db.go
   147  	coll := "pvWjtfSTXVK8WJus5s6zWoMIciXd7qHRZIusF9SkOS6m8XuHCiJDE9cCRuVerq22Na8qBL2ywDGFpVMIuzfyEXLjeJb0mMuH4cwewT6r1INOTOSYwrikwOLlT_fl0V1L7IQEwUBB8WCvRqSdj6j5-E5aGul_pv_0UeCdwWiyA_GrZmP7ocLzfj2vP8btigrajqdH-irLO2ydEjQUAvf8fiuxru9la402KmKRy457GgI98UHoUdqV3f3FCdR"
   148  
   149  	truncatedChainName := "tob2g.y-z0f.qwp-rq5g4-ogid5g6oucyryg9sc16mz0t4vuak"
   150  	truncatedEscapedNs := "w$m$cn$s$xi$v9$yo$iq$n$qy$nv$f$v$td$m8$xn$utvr$o$f"
   151  	truncatedEscapedColl := "pv$wjtf$s$t$x$v$k8$w$jus5s6z$wo$m$ici$xd7q$h$r$z$i"
   152  	assert.Equal(t, chainNameAllowedLength, len(truncatedChainName))
   153  	assert.Equal(t, namespaceNameAllowedLength, len(truncatedEscapedNs))
   154  	assert.Equal(t, collectionNameAllowedLength, len(truncatedEscapedColl))
   155  
   156  	untruncatedDBName := chainName + "_" + ns + "$$" + coll
   157  	hash := hex.EncodeToString(util.ComputeSHA256([]byte(untruncatedDBName)))
   158  	expectedDBName := truncatedChainName + "_" + truncatedEscapedNs + "$$" + truncatedEscapedColl + "(" + hash + ")"
   159  	// <first 50 chars (i.e., chainNameAllowedLength) of chainName> + 1 char for '_' + <first 50 chars
   160  	// (i.e., namespaceNameAllowedLength) of escaped namespace> + 2 chars for '$$' + <first 50 chars
   161  	// (i.e., collectionNameAllowedLength) of escaped collection> + 1 char for '(' + <64 chars for SHA256 hash
   162  	// (hex encoding) of untruncated chainName_ns$$coll> + 1 char for ')' = 219 chars
   163  	expectedDBNameLength := 219
   164  
   165  	namespace := ns + "$$" + coll
   166  	constructedDBName := ConstructNamespaceDBName(chainName, namespace)
   167  	assert.Equal(t, expectedDBNameLength, len(constructedDBName))
   168  	assert.Equal(t, expectedDBName, constructedDBName)
   169  
   170  	// === SCENARIO 2: chainName_ns ===
   171  
   172  	untruncatedDBName = chainName + "_" + ns
   173  	hash = hex.EncodeToString(util.ComputeSHA256([]byte(untruncatedDBName)))
   174  	expectedDBName = truncatedChainName + "_" + truncatedEscapedNs + "(" + hash + ")"
   175  	// <first 50 chars (i.e., chainNameAllowedLength) of chainName> + 1 char for '_' + <first 50 chars
   176  	// (i.e., namespaceNameAllowedLength) of escaped namespace> + 1 char for '(' + <64 chars for SHA256 hash
   177  	// (hex encoding) of untruncated chainName_ns> + 1 char for ')' = 167 chars
   178  	expectedDBNameLength = 167
   179  
   180  	namespace = ns
   181  	constructedDBName = ConstructNamespaceDBName(chainName, namespace)
   182  	assert.Equal(t, expectedDBNameLength, len(constructedDBName))
   183  	assert.Equal(t, expectedDBName, constructedDBName)
   184  }