gitee.com/zhaochuninhefei/fabric-ca-gm@v0.0.2/lib/dbaccessor_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package lib_test
     8  
     9  import (
    10  	"fmt"
    11  	"os"
    12  	"strings"
    13  	"testing"
    14  
    15  	"gitee.com/zhaochuninhefei/fabric-ca-gm/internal/pkg/api"
    16  	. "gitee.com/zhaochuninhefei/fabric-ca-gm/lib"
    17  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/db"
    18  	"gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/db/sqlite"
    19  	cadbuser "gitee.com/zhaochuninhefei/fabric-ca-gm/lib/server/user"
    20  	"github.com/jmoiron/sqlx"
    21  	_ "github.com/mattn/go-sqlite3"
    22  	"github.com/stretchr/testify/assert"
    23  )
    24  
    25  const (
    26  	dbPath = "/tmp/dbtesting"
    27  
    28  	sqliteTruncateTables = `
    29  DELETE FROM Users;
    30  DELETE FROM affiliations;
    31  `
    32  
    33  	rootDB = "rootDir/fabric_ca.db"
    34  )
    35  
    36  type TestAccessor struct {
    37  	Accessor *Accessor
    38  	DB       *db.DB
    39  }
    40  
    41  func (ta *TestAccessor) Truncate() {
    42  	Truncate(ta.DB)
    43  }
    44  
    45  func TestSQLite(t *testing.T) {
    46  	cleanTestSlateSQ(t)
    47  	defer cleanTestSlateSQ(t)
    48  
    49  	if _, err := os.Stat(dbPath); err != nil {
    50  		if os.IsNotExist(err) {
    51  			os.MkdirAll(dbPath, 0755)
    52  		}
    53  	} else {
    54  		err = os.RemoveAll(dbPath)
    55  		if err != nil {
    56  			t.Errorf("RemoveAll failed: %s", err)
    57  		}
    58  		os.MkdirAll(dbPath, 0755)
    59  	}
    60  	dataSource := dbPath + "/fabric-ca.db"
    61  	sqlitedb, err := getSqliteDb(dataSource)
    62  	if err != nil {
    63  		t.Error("Failed to open connection to DB")
    64  	}
    65  	accessor := NewDBAccessor(sqlitedb)
    66  
    67  	ta := TestAccessor{
    68  		Accessor: accessor,
    69  		DB:       sqlitedb,
    70  	}
    71  	testEverything(ta, t)
    72  }
    73  
    74  // Truncate truncates the DB
    75  func Truncate(db *db.DB) {
    76  	if len(strings.TrimSpace(sqliteTruncateTables)) == 0 {
    77  		return
    78  	}
    79  	if _, err := db.Exec("", sqliteTruncateTables); err != nil {
    80  		panic(err)
    81  	}
    82  }
    83  
    84  func TestEmptyAccessor(t *testing.T) {
    85  	a := &Accessor{}
    86  	ui := cadbuser.Info{}
    87  	err := a.InsertUser(nil)
    88  	if err == nil {
    89  		t.Error("Passing in nil should have resulted in an error")
    90  	}
    91  
    92  	err = a.InsertUser(&ui)
    93  	if err == nil {
    94  		t.Error("Empty Accessor InsertUser should have failed")
    95  	}
    96  }
    97  
    98  func TestDBCreation(t *testing.T) {
    99  	cleanTestSlateSQ(t)
   100  	defer cleanTestSlateSQ(t)
   101  
   102  	os.Mkdir(rootDir, 0755)
   103  
   104  	testWithExistingDbAndTablesAndUser(t)
   105  	testWithExistingDbAndTable(t)
   106  	testWithExistingDb(t)
   107  }
   108  
   109  func createSQLiteDB(path string, t *testing.T) (*db.DB, *TestAccessor) {
   110  	sqlxdb, err := sqlx.Open("sqlite3", path)
   111  	assert.NoError(t, err, "Failed to open SQLite database")
   112  
   113  	sqlitedb := db.New(sqlxdb, "", nil)
   114  	accessor := NewDBAccessor(sqlitedb)
   115  
   116  	ta := &TestAccessor{
   117  		Accessor: accessor,
   118  		DB:       sqlitedb,
   119  	}
   120  
   121  	return sqlitedb, ta
   122  }
   123  
   124  // Test that an already bootstrapped database properly get inspected and bootstrapped with any new identities on the
   125  // next server start
   126  func testWithExistingDbAndTablesAndUser(t *testing.T) {
   127  	var err error
   128  
   129  	err = os.RemoveAll(rootDB)
   130  	if err != nil {
   131  		t.Errorf("RemoveAll failed: %s", err)
   132  	}
   133  	db, acc := createSQLiteDB(rootDB, t)
   134  
   135  	_, err = db.Exec("", "CREATE TABLE IF NOT EXISTS users (id VARCHAR(64), token bytea, type VARCHAR(64), affiliation VARCHAR(64), attributes VARCHAR(256), state INTEGER,  max_enrollments INTEGER, level INTEGER DEFAULT 0)")
   136  	assert.NoError(t, err, "Error creating users table")
   137  
   138  	srv := TestGetServer2(false, rootPort, rootDir, "", -1, t)
   139  	srv.CA.Config.DB.Datasource = "fabric_ca.db"
   140  
   141  	err = srv.Start()
   142  	assert.NoError(t, err, "Failed to start server")
   143  
   144  	err = srv.Stop()
   145  	assert.NoError(t, err, "Failed to stop server")
   146  
   147  	// Add additional user to registry and start server and confirm that it correctly get added
   148  	srv.RegisterBootstrapUser("admin2", "admin2pw", "")
   149  
   150  	err = srv.Start()
   151  	assert.NoError(t, err, "Failed to start server")
   152  
   153  	_, err = acc.Accessor.GetUser("admin2", nil)
   154  	assert.NoError(t, err, "Failed to correctly insert 'admin2' during second server bootstrap")
   155  
   156  	err = srv.Stop()
   157  	assert.NoError(t, err, "Failed to stop server")
   158  
   159  	err = db.Close()
   160  	assert.NoError(t, err, "Failed to close DB")
   161  }
   162  
   163  // Test starting a server with an already existing database and tables, but not bootstrapped
   164  func testWithExistingDbAndTable(t *testing.T) {
   165  	var err error
   166  
   167  	err = os.RemoveAll(rootDB)
   168  	if err != nil {
   169  		t.Errorf("RemoveAll failed: %s", err)
   170  	}
   171  	db, acc := createSQLiteDB(rootDB, t)
   172  
   173  	srv := TestGetServer2(false, rootPort, rootDir, "", -1, t)
   174  	srv.CA.Config.DB.Datasource = "fabric_ca.db"
   175  
   176  	_, err = db.Exec("", "CREATE TABLE IF NOT EXISTS users (id VARCHAR(64), token bytea, type VARCHAR(64), affiliation VARCHAR(64), attributes VARCHAR(256), state INTEGER,  max_enrollments INTEGER, level INTEGER DEFAULT 0)")
   177  	assert.NoError(t, err, "Error creating users table")
   178  
   179  	err = srv.Start()
   180  	assert.NoError(t, err, "Failed to start server")
   181  
   182  	_, err = acc.Accessor.GetUser("admin", nil)
   183  	assert.NoError(t, err, "Failed to correctly insert 'admin' during second server bootstrap")
   184  
   185  	err = srv.Stop()
   186  	assert.NoError(t, err, "Failed to stop server")
   187  
   188  	err = db.Close()
   189  	assert.NoError(t, err, "Failed to close DB")
   190  }
   191  
   192  // Test starting a server with an already existing database, but no tables or users
   193  func testWithExistingDb(t *testing.T) {
   194  	var err error
   195  
   196  	err = os.RemoveAll(rootDB)
   197  	if err != nil {
   198  		t.Errorf("RemoveAll failed: %s", err)
   199  	}
   200  	db, acc := createSQLiteDB(rootDB, t)
   201  
   202  	srv := TestGetServer2(false, rootPort, rootDir, "", -1, t)
   203  	srv.CA.Config.DB.Datasource = "fabric_ca.db"
   204  
   205  	err = srv.Start()
   206  	assert.NoError(t, err, "Failed to start server")
   207  
   208  	_, err = acc.Accessor.GetUser("admin", nil)
   209  	assert.NoError(t, err, "Failed to correctly insert 'admin' during second server bootstrap")
   210  
   211  	err = srv.Stop()
   212  	assert.NoError(t, err, "Failed to stop server")
   213  
   214  	err = db.Close()
   215  	assert.NoError(t, err, "Failed to close DB")
   216  }
   217  
   218  func cleanTestSlateSQ(t *testing.T) {
   219  	err := os.RemoveAll(rootDir)
   220  	if err != nil {
   221  		t.Errorf("RemoveAll failed: %s", err)
   222  	}
   223  	err = os.RemoveAll(dbPath)
   224  	if err != nil {
   225  		t.Errorf("RemoveAll failed: %s", err)
   226  	}
   227  }
   228  
   229  func testEverything(ta TestAccessor, t *testing.T) {
   230  	testInsertAndGetUser(ta, t)
   231  	testModifyAttribute(ta, t)
   232  	testDeleteUser(ta, t)
   233  	testUpdateUser(ta, t)
   234  	testInsertAndGetAffiliation(ta, t)
   235  	testDeleteAffiliation(ta, t)
   236  	testInsertAndGetFilteredUsers(ta, t)
   237  }
   238  
   239  func testInsertAndGetUser(ta TestAccessor, t *testing.T) {
   240  	t.Log("TestInsertAndGetUser")
   241  	ta.Truncate()
   242  
   243  	insert := cadbuser.Info{
   244  		Name: "testId",
   245  		Pass: "123456",
   246  		Type: "client",
   247  		Attributes: []api.Attribute{
   248  			api.Attribute{
   249  				Name:  "hf.Registrar.Roles",
   250  				Value: "peer,client,orderer,user",
   251  			},
   252  			api.Attribute{
   253  				Name:  "hf.Revoker",
   254  				Value: "false",
   255  			},
   256  			api.Attribute{
   257  				Name:  "hf.Registrar.Attributes",
   258  				Value: "*",
   259  			},
   260  			api.Attribute{
   261  				Name:  "xyz",
   262  				Value: "xyz",
   263  			},
   264  		},
   265  	}
   266  
   267  	err := ta.Accessor.InsertUser(&insert)
   268  	if err != nil {
   269  		t.Errorf("Error occurred during insert query of ID: %s, error: %s", insert.Name, err)
   270  	}
   271  
   272  	user, err := ta.Accessor.GetUser(insert.Name, nil)
   273  	if err != nil {
   274  		t.Errorf("Error occurred during querying of id: %s, error: %s", insert.Name, err)
   275  	}
   276  
   277  	if user.GetName() != insert.Name {
   278  		t.Error("Incorrect ID retrieved")
   279  	}
   280  }
   281  
   282  func testInsertAndGetFilteredUsers(ta TestAccessor, t *testing.T) {
   283  	t.Log("TestInsertAndGetFilteredUsers")
   284  	ta.Truncate()
   285  	// create user
   286  	insert := cadbuser.Info{
   287  		Name: "testTypesClient",
   288  		Pass: "123456",
   289  		Type: "client",
   290  		Attributes: []api.Attribute{
   291  			api.Attribute{
   292  				Name:  "hf.Registrar.Roles",
   293  				Value: "peer,client,orderer,user",
   294  			},
   295  			api.Attribute{
   296  				Name:  "hf.Revoker",
   297  				Value: "false",
   298  			},
   299  			api.Attribute{
   300  				Name:  "hf.Registrar.Attributes",
   301  				Value: "*",
   302  			},
   303  			api.Attribute{
   304  				Name:  "xyz",
   305  				Value: "xyz",
   306  			},
   307  		},
   308  	}
   309  	// insert user
   310  	err := ta.Accessor.InsertUser(&insert)
   311  	if err != nil {
   312  		t.Errorf("Error occurred during insert query of ID: %s, error: %s", insert.Name, err)
   313  	}
   314  	// test get the user
   315  	rows, err := ta.Accessor.GetFilteredUsers("", "client,orderer")
   316  	if err != nil {
   317  		t.Errorf("Failed to get users by affiliation: %s, and type: %s, error: %s", "", "client,orderer", err)
   318  	}
   319  
   320  	typesClientSuccessFlag := false
   321  	for rows.Next() {
   322  		var id cadbuser.Record
   323  		err := rows.StructScan(&id)
   324  		if err != nil {
   325  			t.Errorf("Failed to get read row! error: %s", err)
   326  		}
   327  		// get the target user
   328  		if id.Name == "testTypesClient" && id.Type == "client" {
   329  			typesClientSuccessFlag = true
   330  		}
   331  	}
   332  	// not success
   333  	if !typesClientSuccessFlag {
   334  		t.Errorf("Test InsertAndGetFilteredUsers Failed!")
   335  	}
   336  
   337  	// test type=* and affiliation is not nil
   338  	// insert affiliation
   339  	err = ta.Accessor.InsertAffiliation("Bank1", "Banks", 0)
   340  	if err != nil {
   341  		t.Errorf("Error occurred during insert query of group: %s, error: %s", "Bank1", err)
   342  	}
   343  	// change user info
   344  	insert.Name = "testTypesStar"
   345  	insert.Type = "*"
   346  	insert.Affiliation = "Bank1"
   347  	// insert user
   348  	err = ta.Accessor.InsertUser(&insert)
   349  	if err != nil {
   350  		t.Errorf("Error occurred during insert query of ID: %s, error: %s", insert.Name, err)
   351  	}
   352  	// test get the user
   353  	rows, err = ta.Accessor.GetFilteredUsers("Bank1", "*")
   354  	if err != nil {
   355  		t.Errorf("Failed to get users by affiliation: %s, and type: %s, error: %s", "Bank1", "*", err)
   356  	}
   357  	// use the success flag to tag success
   358  	affiliationsTypeStarSuccessFlag := false
   359  	for rows.Next() {
   360  		var id cadbuser.Record
   361  		err := rows.StructScan(&id)
   362  		if err != nil {
   363  			t.Errorf("Failed to get read row! error: %s", err)
   364  		}
   365  		// get the target user
   366  		if id.Affiliation == "Bank1" && id.Name == "testTypesStar" {
   367  			affiliationsTypeStarSuccessFlag = true
   368  		}
   369  	}
   370  	// not success
   371  	if !affiliationsTypeStarSuccessFlag {
   372  		t.Errorf("Test InsertAndGetFilteredUsers Failed!")
   373  	}
   374  
   375  	// test get all user
   376  	affiliationsTypeStarSuccessFlag = false
   377  	typesClientSuccessFlag = false
   378  	// test get all users
   379  	rows, err = ta.Accessor.GetFilteredUsers("", "*")
   380  	if err != nil {
   381  		t.Errorf("Failed to get users by affiliation: %s, and type: %s, error: %s", "", "*", err)
   382  	}
   383  	for rows.Next() {
   384  		var id cadbuser.Record
   385  		err := rows.StructScan(&id)
   386  		if err != nil {
   387  			t.Errorf("Failed to get read row! error: %s", err)
   388  		}
   389  		// get the target user
   390  		if id.Affiliation == "Bank1" && id.Name == "testTypesStar" {
   391  			affiliationsTypeStarSuccessFlag = true
   392  		}
   393  		if id.Name == "testTypesClient" && id.Type == "client" {
   394  			typesClientSuccessFlag = true
   395  		}
   396  	}
   397  	// not success
   398  	if !(affiliationsTypeStarSuccessFlag && typesClientSuccessFlag) {
   399  		t.Errorf("Test InsertAndGetFilteredUsers Failed!")
   400  	}
   401  }
   402  
   403  func testModifyAttribute(ta TestAccessor, t *testing.T) {
   404  
   405  	user, err := ta.Accessor.GetUser("testId", nil)
   406  	assert.NoError(t, err, "Failed to get user")
   407  
   408  	err = user.ModifyAttributes([]api.Attribute{
   409  		api.Attribute{
   410  			Name:  "hf.Registrar.Roles",
   411  			Value: "peer",
   412  		},
   413  		api.Attribute{
   414  			Name:  "hf.Revoker",
   415  			Value: "",
   416  		},
   417  		api.Attribute{
   418  			Name:  "xyz",
   419  			Value: "",
   420  		},
   421  		api.Attribute{
   422  			Name:  "hf.IntermediateCA",
   423  			Value: "true",
   424  		},
   425  	})
   426  	assert.NoError(t, err, "Failed to modify user's attributes")
   427  
   428  	user, err = ta.Accessor.GetUser("testId", nil)
   429  	assert.NoError(t, err, "Failed to get user")
   430  
   431  	_, err = user.GetAttribute("hf.Revoker")
   432  	assert.Error(t, err, "Should have returned an error, attribute should have been deleted")
   433  
   434  	// Removes last attribute in the slice, should have correctly removed it
   435  	_, err = user.GetAttribute("xyz")
   436  	assert.Error(t, err, "Should have returned an error, attribute should have been deleted")
   437  
   438  	attr, err := user.GetAttribute("hf.IntermediateCA")
   439  	assert.NoError(t, err, "Failed to add attribute")
   440  	assert.Equal(t, "true", attr.Value, "Incorrect value for attribute 'hf.IntermediateCA")
   441  
   442  	attr, err = user.GetAttribute("hf.Registrar.Roles")
   443  	assert.NoError(t, err, "Failed to get attribute")
   444  	assert.Equal(t, "peer", attr.Value, "Incorrect value for attribute 'hf.Registrar.Roles")
   445  
   446  	// Test to make sure that any existing attributes that were not modified continue to exist in there original state
   447  	attr, err = user.GetAttribute("hf.Registrar.Attributes")
   448  	assert.NoError(t, err, "Failed to get attribute")
   449  	assert.Equal(t, "*", attr.Value)
   450  }
   451  
   452  func testDeleteUser(ta TestAccessor, t *testing.T) {
   453  	t.Log("TestDeleteUser")
   454  	ta.Truncate()
   455  
   456  	insert := cadbuser.Info{
   457  		Name:       "testId",
   458  		Pass:       "123456",
   459  		Type:       "client",
   460  		Attributes: []api.Attribute{},
   461  	}
   462  
   463  	err := ta.Accessor.InsertUser(&insert)
   464  	if err != nil {
   465  		t.Errorf("Error occurred during insert query of id: %s, error: %s", insert.Name, err)
   466  	}
   467  
   468  	_, err = ta.Accessor.DeleteUser(insert.Name)
   469  	if err != nil {
   470  		t.Errorf("Error occurred during deletion of ID: %s, error: %s", insert.Name, err)
   471  	}
   472  
   473  	_, err = ta.Accessor.GetUser(insert.Name, nil)
   474  	if err == nil {
   475  		t.Error("Should have errored, and not returned any results")
   476  	}
   477  }
   478  
   479  func testUpdateUser(ta TestAccessor, t *testing.T) {
   480  	t.Log("TestUpdateUser")
   481  	ta.Truncate()
   482  
   483  	insert := cadbuser.Info{
   484  		Name:           "testId",
   485  		Pass:           "123456",
   486  		Type:           "client",
   487  		Attributes:     []api.Attribute{},
   488  		MaxEnrollments: 1,
   489  	}
   490  
   491  	err := ta.Accessor.InsertUser(&insert)
   492  	if err != nil {
   493  		t.Errorf("Error occurred during insert query of ID: %s, error: %s", insert.Name, err)
   494  	}
   495  
   496  	insert.Pass = "654321"
   497  
   498  	err = ta.Accessor.UpdateUser(nil, true)
   499  	if err == nil {
   500  		t.Error("Passing in nil should have resulted in an error")
   501  	}
   502  
   503  	err = ta.Accessor.UpdateUser(&insert, true)
   504  	if err != nil {
   505  		t.Errorf("Error occurred during update query of ID: %s, error: %s", insert.Name, err)
   506  	}
   507  
   508  	user, err := ta.Accessor.GetUser(insert.Name, nil)
   509  	if err != nil {
   510  		t.Errorf("Error occurred during querying of ID: %s, error: %s", insert.Name, err)
   511  	}
   512  
   513  	err = user.Login(insert.Pass, -1)
   514  	if err != nil {
   515  		t.Error("Failed to login in user: ", err)
   516  	}
   517  
   518  }
   519  
   520  func testInsertAndGetAffiliation(ta TestAccessor, t *testing.T) {
   521  	ta.Truncate()
   522  
   523  	err := ta.Accessor.InsertAffiliation("Bank1", "Banks", 0)
   524  	if err != nil {
   525  		t.Errorf("Error occurred during insert query of group: %s, error: %s", "Bank1", err)
   526  	}
   527  
   528  	group, err := ta.Accessor.GetAffiliation("Bank1")
   529  	if err != nil {
   530  		t.Errorf("Error occurred during querying of name: %s, error: %s", "Bank1", err)
   531  	}
   532  
   533  	if group.GetName() != "Bank1" {
   534  		t.Error("Failed to query")
   535  	}
   536  
   537  }
   538  
   539  func testDeleteAffiliation(ta TestAccessor, t *testing.T) {
   540  	ta.Truncate()
   541  
   542  	err := ta.Accessor.InsertAffiliation("Banks.Bank2", "Banks", 0)
   543  	if err != nil {
   544  		t.Errorf("Error occurred during insert query of group: %s, error: %s", "Bank2", err)
   545  	}
   546  
   547  	_, err = ta.Accessor.DeleteAffiliation("Banks.Bank2", true, true, true)
   548  	if err != nil {
   549  		t.Errorf("Error occurred during deletion of group: %s, error: %s", "Bank2", err)
   550  	}
   551  
   552  	_, err = ta.Accessor.GetAffiliation("Banks.Bank2")
   553  	if err == nil {
   554  		t.Error("Should have errored, and not returned any results")
   555  	}
   556  }
   557  
   558  func TestDBErrorMessages(t *testing.T) {
   559  	var err error
   560  
   561  	cleanTestSlateSQ(t)
   562  	defer cleanTestSlateSQ(t)
   563  
   564  	if _, err = os.Stat(dbPath); err != nil {
   565  		if os.IsNotExist(err) {
   566  			os.MkdirAll(dbPath, 0755)
   567  		}
   568  	} else {
   569  		err = os.RemoveAll(dbPath)
   570  		if err != nil {
   571  			t.Errorf("RemoveAll failed: %s", err)
   572  		}
   573  		os.MkdirAll(dbPath, 0755)
   574  	}
   575  
   576  	dataSource := dbPath + "/fabric-ca.db"
   577  	sqlitedb, err := getSqliteDb(dataSource)
   578  	if err != nil {
   579  		t.Error("Failed to open connection to DB")
   580  	}
   581  	accessor := NewDBAccessor(sqlitedb)
   582  
   583  	ta := TestAccessor{
   584  		Accessor: accessor,
   585  		DB:       sqlitedb,
   586  	}
   587  
   588  	expectedErr := "Failed to get %s"
   589  	_, err = ta.Accessor.GetAffiliation("hyperledger")
   590  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   591  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "affiliation"))
   592  	}
   593  
   594  	_, err = ta.Accessor.GetUser("testuser", []string{})
   595  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   596  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "User"))
   597  	}
   598  
   599  	newCertDBAcc := NewCertDBAccessor(sqlitedb, 0)
   600  	_, err = newCertDBAcc.GetCertificateWithID("serial", "aki")
   601  	if assert.Error(t, err, "Should have errored, and not returned any results") {
   602  		assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Certificate"))
   603  	}
   604  }
   605  
   606  func getSqliteDb(datasource string) (*db.DB, error) {
   607  	sqliteDB := sqlite.NewDB(datasource, "", nil)
   608  	err := sqliteDB.Connect()
   609  	if err != nil {
   610  		return nil, err
   611  	}
   612  	testdb, err := sqliteDB.Create()
   613  	if err != nil {
   614  		return nil, err
   615  	}
   616  	return testdb, nil
   617  }