github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/core/ledger/util/couchdb/couchdb_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2016, 2017 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package couchdb
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"os"
    23  	"testing"
    24  	"unicode/utf8"
    25  
    26  	"github.com/hyperledger/fabric/common/ledger/testutil"
    27  	"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
    28  	ledgertestutil "github.com/hyperledger/fabric/core/ledger/testutil"
    29  	"github.com/spf13/viper"
    30  )
    31  
    32  //Basic setup to test couch
    33  var connectURL = "couchdb:5984"
    34  var badConnectURL = "couchdb:5990"
    35  var username = ""
    36  var password = ""
    37  
    38  func cleanup(database string) error {
    39  	//create a new connection
    40  	couchInstance, err := CreateCouchInstance(connectURL, username, password)
    41  	if err != nil {
    42  		fmt.Println("Unexpected error", err)
    43  		return err
    44  	}
    45  	db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
    46  	//drop the test database
    47  	db.DropDatabase()
    48  	return nil
    49  }
    50  
    51  type Asset struct {
    52  	ID        string `json:"_id"`
    53  	Rev       string `json:"_rev"`
    54  	AssetName string `json:"asset_name"`
    55  	Color     string `json:"color"`
    56  	Size      string `json:"size"`
    57  	Owner     string `json:"owner"`
    58  }
    59  
    60  var assetJSON = []byte(`{"asset_name":"marble1","color":"blue","size":"35","owner":"jerry"}`)
    61  
    62  func TestMain(m *testing.M) {
    63  	ledgertestutil.SetupCoreYAMLConfig("./../../../../peer")
    64  	viper.Set("ledger.state.stateDatabase", "CouchDB")
    65  	result := m.Run()
    66  	viper.Set("ledger.state.stateDatabase", "goleveldb")
    67  	os.Exit(result)
    68  }
    69  
    70  func TestDBConnectionDef(t *testing.T) {
    71  
    72  	//call a helper method to load the core.yaml
    73  	ledgertestutil.SetupCoreYAMLConfig("./../../../../peer")
    74  
    75  	//create a new connection
    76  	_, err := CreateConnectionDefinition(connectURL, "", "")
    77  	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create database connection definition"))
    78  
    79  }
    80  
    81  func TestDBBadConnectionDef(t *testing.T) {
    82  
    83  	//create a new connection
    84  	_, err := CreateConnectionDefinition("^^^localhost:5984", "", "")
    85  	testutil.AssertError(t, err, fmt.Sprintf("Did not receive error when trying to create database connection definition with a bad hostname"))
    86  
    87  }
    88  
    89  func TestDBCreateSaveWithoutRevision(t *testing.T) {
    90  
    91  	if ledgerconfig.IsCouchDBEnabled() == true {
    92  
    93  		database := "testdbcreatesavewithoutrevision"
    94  		err := cleanup(database)
    95  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup  Error: %s", err))
    96  		defer cleanup(database)
    97  
    98  		if err == nil {
    99  			//create a new instance and database object
   100  			couchInstance, err := CreateCouchInstance(connectURL, username, password)
   101  			testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   102  			db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
   103  
   104  			//create a new database
   105  			_, errdb := db.CreateDatabaseIfNotExist()
   106  			testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database"))
   107  
   108  			//Save the test document
   109  			_, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil})
   110  			testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document"))
   111  		}
   112  	}
   113  }
   114  
   115  func TestDBBadDatabaseName(t *testing.T) {
   116  
   117  	if ledgerconfig.IsCouchDBEnabled() == true {
   118  
   119  		//create a new instance and database object using a valid database name mixed case
   120  		couchInstance, err := CreateCouchInstance(connectURL, username, password)
   121  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   122  		_, dberr := CreateCouchDatabase(*couchInstance, "testDB")
   123  		testutil.AssertNoError(t, dberr, fmt.Sprintf("Error when testing a valid database name"))
   124  
   125  		//create a new instance and database object using a valid database name letters and numbers
   126  		couchInstance, err = CreateCouchInstance(connectURL, username, password)
   127  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   128  		_, dberr = CreateCouchDatabase(*couchInstance, "test132")
   129  		testutil.AssertNoError(t, dberr, fmt.Sprintf("Error when testing a valid database name"))
   130  
   131  		//create a new instance and database object using a valid database name - special characters
   132  		couchInstance, err = CreateCouchInstance(connectURL, username, password)
   133  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   134  		_, dberr = CreateCouchDatabase(*couchInstance, "test1234~!@#$%^&*()[]{}.")
   135  		testutil.AssertNoError(t, dberr, fmt.Sprintf("Error when testing a valid database name"))
   136  
   137  		//create a new instance and database object using a invalid database name - too long	/*
   138  		couchInstance, err = CreateCouchInstance(connectURL, username, password)
   139  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   140  		_, dberr = CreateCouchDatabase(*couchInstance, "A12345678901234567890123456789012345678901234"+
   141  			"56789012345678901234567890123456789012345678901234567890123456789012345678901234567890"+
   142  			"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456"+
   143  			"78901234567890123456789012345678901234567890")
   144  		testutil.AssertError(t, dberr, fmt.Sprintf("Error should have been thrown for invalid database name"))
   145  
   146  	}
   147  
   148  }
   149  
   150  func TestDBBadConnection(t *testing.T) {
   151  
   152  	if ledgerconfig.IsCouchDBEnabled() == true {
   153  
   154  		//create a new instance and database object
   155  		_, err := CreateCouchInstance(badConnectURL, username, password)
   156  		testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for a bad connection"))
   157  	}
   158  }
   159  
   160  func TestDBCreateDatabaseAndPersist(t *testing.T) {
   161  
   162  	if ledgerconfig.IsCouchDBEnabled() == true {
   163  
   164  		database := "testdbcreatedatabaseandpersist"
   165  		err := cleanup(database)
   166  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup  Error: %s", err))
   167  		defer cleanup(database)
   168  
   169  		if err == nil {
   170  			//create a new instance and database object
   171  			couchInstance, err := CreateCouchInstance(connectURL, username, password)
   172  			testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   173  			db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
   174  
   175  			//create a new database
   176  			_, errdb := db.CreateDatabaseIfNotExist()
   177  			testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database"))
   178  
   179  			//Retrieve the info for the new database and make sure the name matches
   180  			dbResp, _, errdb := db.GetDatabaseInfo()
   181  			testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information"))
   182  			testutil.AssertEquals(t, dbResp.DbName, database)
   183  
   184  			//Save the test document
   185  			_, saveerr := db.SaveDoc("idWith/slash", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil})
   186  			testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document"))
   187  
   188  			//Retrieve the test document
   189  			dbGetResp, _, geterr := db.ReadDoc("idWith/slash")
   190  			testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document"))
   191  
   192  			//Unmarshal the document to Asset structure
   193  			assetResp := &Asset{}
   194  			geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp)
   195  			testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document"))
   196  
   197  			//Verify the owner retrieved matches
   198  			testutil.AssertEquals(t, assetResp.Owner, "jerry")
   199  
   200  			//Save the test document
   201  			_, saveerr = db.SaveDoc("1", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil})
   202  			testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document"))
   203  
   204  			//Retrieve the test document
   205  			dbGetResp, _, geterr = db.ReadDoc("1")
   206  			testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document"))
   207  
   208  			//Unmarshal the document to Asset structure
   209  			assetResp = &Asset{}
   210  			geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp)
   211  			testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document"))
   212  
   213  			//Verify the owner retrieved matches
   214  			testutil.AssertEquals(t, assetResp.Owner, "jerry")
   215  
   216  			//Change owner to bob
   217  			assetResp.Owner = "bob"
   218  
   219  			//create a byte array of the JSON
   220  			assetDocUpdated, _ := json.Marshal(assetResp)
   221  
   222  			//Save the updated test document
   223  			_, saveerr = db.SaveDoc("1", "", &CouchDoc{JSONValue: assetDocUpdated, Attachments: nil})
   224  			testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save the updated document"))
   225  
   226  			//Retrieve the updated test document
   227  			dbGetResp, _, geterr = db.ReadDoc("1")
   228  			testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document"))
   229  
   230  			//Unmarshal the document to Asset structure
   231  			assetResp = &Asset{}
   232  			json.Unmarshal(dbGetResp.JSONValue, &assetResp)
   233  
   234  			//Assert that the update was saved and retrieved
   235  			testutil.AssertEquals(t, assetResp.Owner, "bob")
   236  
   237  			//Drop the database
   238  			_, errdbdrop := db.DropDatabase()
   239  			testutil.AssertNoError(t, errdbdrop, fmt.Sprintf("Error dropping database"))
   240  
   241  			//Retrieve the info for the new database and make sure the name matches
   242  			_, _, errdbinfo := db.GetDatabaseInfo()
   243  			testutil.AssertError(t, errdbinfo, fmt.Sprintf("Error should have been thrown for missing database"))
   244  		}
   245  	}
   246  
   247  }
   248  
   249  func TestDBBadJSON(t *testing.T) {
   250  
   251  	if ledgerconfig.IsCouchDBEnabled() == true {
   252  
   253  		database := "testdbbadjson"
   254  		err := cleanup(database)
   255  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup  Error: %s", err))
   256  		defer cleanup(database)
   257  
   258  		if err == nil {
   259  
   260  			//create a new instance and database object
   261  			couchInstance, err := CreateCouchInstance(connectURL, username, password)
   262  			testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   263  			db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
   264  
   265  			//create a new database
   266  			_, errdb := db.CreateDatabaseIfNotExist()
   267  			testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database"))
   268  
   269  			//Retrieve the info for the new database and make sure the name matches
   270  			dbResp, _, errdb := db.GetDatabaseInfo()
   271  			testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information"))
   272  			testutil.AssertEquals(t, dbResp.DbName, database)
   273  
   274  			badJSON := []byte(`{"asset_name"}`)
   275  
   276  			//Save the test document
   277  			_, saveerr := db.SaveDoc("1", "", &CouchDoc{JSONValue: badJSON, Attachments: nil})
   278  			testutil.AssertError(t, saveerr, fmt.Sprintf("Error should have been thrown for a bad JSON"))
   279  
   280  		}
   281  
   282  	}
   283  
   284  }
   285  
   286  func TestPrefixScan(t *testing.T) {
   287  	if !ledgerconfig.IsCouchDBEnabled() {
   288  		return
   289  	}
   290  	database := "testprefixscan"
   291  	err := cleanup(database)
   292  	testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup  Error: %s", err))
   293  	defer cleanup(database)
   294  
   295  	if err == nil {
   296  		//create a new instance and database object
   297  		couchInstance, err := CreateCouchInstance(connectURL, username, password)
   298  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   299  		db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
   300  
   301  		//create a new database
   302  		_, errdb := db.CreateDatabaseIfNotExist()
   303  		testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database"))
   304  
   305  		//Retrieve the info for the new database and make sure the name matches
   306  		dbResp, _, errdb := db.GetDatabaseInfo()
   307  		testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to retrieve database information"))
   308  		testutil.AssertEquals(t, dbResp.DbName, database)
   309  
   310  		//Save documents
   311  		for i := 0; i < 20; i++ {
   312  			id1 := string(0) + string(i) + string(0)
   313  			id2 := string(0) + string(i) + string(1)
   314  			id3 := string(0) + string(i) + string(utf8.MaxRune-1)
   315  			_, saveerr := db.SaveDoc(id1, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil})
   316  			testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document"))
   317  			_, saveerr = db.SaveDoc(id2, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil})
   318  			testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document"))
   319  			_, saveerr = db.SaveDoc(id3, "", &CouchDoc{JSONValue: assetJSON, Attachments: nil})
   320  			testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document"))
   321  
   322  		}
   323  		startKey := string(0) + string(10)
   324  		endKey := startKey + string(utf8.MaxRune)
   325  		_, _, geterr := db.ReadDoc(endKey)
   326  		testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to get lastkey"))
   327  
   328  		resultsPtr, geterr := db.ReadDocRange(startKey, endKey, 1000, 0)
   329  		testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to perform a range scan"))
   330  		testutil.AssertNotNil(t, resultsPtr)
   331  		results := *resultsPtr
   332  		testutil.AssertEquals(t, len(results), 3)
   333  		testutil.AssertEquals(t, results[0].ID, string(0)+string(10)+string(0))
   334  		testutil.AssertEquals(t, results[1].ID, string(0)+string(10)+string(1))
   335  		testutil.AssertEquals(t, results[2].ID, string(0)+string(10)+string(utf8.MaxRune-1))
   336  
   337  		//Drop the database
   338  		_, errdbdrop := db.DropDatabase()
   339  		testutil.AssertNoError(t, errdbdrop, fmt.Sprintf("Error dropping database"))
   340  
   341  		//Retrieve the info for the new database and make sure the name matches
   342  		_, _, errdbinfo := db.GetDatabaseInfo()
   343  		testutil.AssertError(t, errdbinfo, fmt.Sprintf("Error should have been thrown for missing database"))
   344  	}
   345  }
   346  
   347  func TestDBSaveAttachment(t *testing.T) {
   348  
   349  	if ledgerconfig.IsCouchDBEnabled() == true {
   350  
   351  		database := "testdbsaveattachment"
   352  		err := cleanup(database)
   353  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup  Error: %s", err))
   354  		defer cleanup(database)
   355  
   356  		if err == nil {
   357  
   358  			byteText := []byte(`This is a test document.  This is only a test`)
   359  
   360  			attachment := Attachment{}
   361  			attachment.AttachmentBytes = byteText
   362  			attachment.ContentType = "text/plain"
   363  			attachment.Name = "valueBytes"
   364  
   365  			attachments := []Attachment{}
   366  			attachments = append(attachments, attachment)
   367  
   368  			//create a new instance and database object
   369  			couchInstance, err := CreateCouchInstance(connectURL, username, password)
   370  			testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   371  			db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
   372  
   373  			//create a new database
   374  			_, errdb := db.CreateDatabaseIfNotExist()
   375  			testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database"))
   376  
   377  			//Save the test document
   378  			_, saveerr := db.SaveDoc("10", "", &CouchDoc{JSONValue: nil, Attachments: attachments})
   379  			testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document"))
   380  
   381  			//Attempt to retrieve the updated test document with attachments
   382  			couchDoc, _, geterr2 := db.ReadDoc("10")
   383  			testutil.AssertNoError(t, geterr2, fmt.Sprintf("Error when trying to retrieve a document with attachment"))
   384  			testutil.AssertNotNil(t, couchDoc.Attachments)
   385  			testutil.AssertEquals(t, couchDoc.Attachments[0].AttachmentBytes, byteText)
   386  		}
   387  
   388  	}
   389  }
   390  
   391  func TestDBDeleteDocument(t *testing.T) {
   392  
   393  	if ledgerconfig.IsCouchDBEnabled() == true {
   394  
   395  		database := "testdbdeletedocument"
   396  		err := cleanup(database)
   397  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup  Error: %s", err))
   398  		defer cleanup(database)
   399  
   400  		if err == nil {
   401  			//create a new instance and database object
   402  			couchInstance, err := CreateCouchInstance(connectURL, username, password)
   403  			testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   404  			db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
   405  
   406  			//create a new database
   407  			_, errdb := db.CreateDatabaseIfNotExist()
   408  			testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database"))
   409  
   410  			//Save the test document
   411  			_, saveerr := db.SaveDoc("2", "", &CouchDoc{JSONValue: assetJSON, Attachments: nil})
   412  			testutil.AssertNoError(t, saveerr, fmt.Sprintf("Error when trying to save a document"))
   413  
   414  			//Attempt to retrieve the test document
   415  			_, _, readErr := db.ReadDoc("2")
   416  			testutil.AssertNoError(t, readErr, fmt.Sprintf("Error when trying to retrieve a document with attachment"))
   417  
   418  			//Delete the test document
   419  			deleteErr := db.DeleteDoc("2", "")
   420  			testutil.AssertNoError(t, deleteErr, fmt.Sprintf("Error when trying to delete a document"))
   421  
   422  			//Attempt to retrieve the test document
   423  			readValue, _, _ := db.ReadDoc("2")
   424  			testutil.AssertNil(t, readValue)
   425  		}
   426  	}
   427  }
   428  
   429  func TestDBDeleteNonExistingDocument(t *testing.T) {
   430  
   431  	if ledgerconfig.IsCouchDBEnabled() == true {
   432  
   433  		database := "testdbdeletenonexistingdocument"
   434  		err := cleanup(database)
   435  		testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup  Error: %s", err))
   436  		defer cleanup(database)
   437  
   438  		if err == nil {
   439  			//create a new instance and database object
   440  			couchInstance, err := CreateCouchInstance(connectURL, username, password)
   441  			testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to create couch instance"))
   442  			db := CouchDatabase{couchInstance: *couchInstance, dbName: database}
   443  
   444  			//create a new database
   445  			_, errdb := db.CreateDatabaseIfNotExist()
   446  			testutil.AssertNoError(t, errdb, fmt.Sprintf("Error when trying to create database"))
   447  
   448  			//Save the test document
   449  			deleteErr := db.DeleteDoc("2", "")
   450  			testutil.AssertNoError(t, deleteErr, fmt.Sprintf("Error when trying to delete a non existing document"))
   451  		}
   452  	}
   453  }
   454  
   455  func TestCouchDBVersion(t *testing.T) {
   456  
   457  	err := checkCouchDBVersion("2.0.0")
   458  	testutil.AssertNoError(t, err, fmt.Sprintf("Error should not have been thrown for valid version"))
   459  
   460  	err = checkCouchDBVersion("4.5.0")
   461  	testutil.AssertNoError(t, err, fmt.Sprintf("Error should not have been thrown for valid version"))
   462  
   463  	err = checkCouchDBVersion("1.6.5.4")
   464  	testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for invalid version"))
   465  
   466  	err = checkCouchDBVersion("0.0.0.0")
   467  	testutil.AssertError(t, err, fmt.Sprintf("Error should have been thrown for invalid version"))
   468  
   469  }