github.com/ldc1995/fabric-ca@v2.0.0-alpha.0.20200422214819-8d49c278c386+incompatible/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 "github.com/hyperledger/fabric-ca/api" 16 . "github.com/hyperledger/fabric-ca/lib" 17 "github.com/hyperledger/fabric-ca/lib/server/db" 18 "github.com/hyperledger/fabric-ca/lib/server/db/sqlite" 19 cadbuser "github.com/hyperledger/fabric-ca/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 var sql []string 77 sql = []string{sqliteTruncateTables} 78 79 for _, expr := range sql { 80 if len(strings.TrimSpace(expr)) == 0 { 81 continue 82 } 83 if _, err := db.Exec("", expr); err != nil { 84 panic(err) 85 } 86 } 87 } 88 89 func TestEmptyAccessor(t *testing.T) { 90 a := &Accessor{} 91 ui := cadbuser.Info{} 92 err := a.InsertUser(nil) 93 if err == nil { 94 t.Error("Passing in nil should have resulted in an error") 95 } 96 97 err = a.InsertUser(&ui) 98 if err == nil { 99 t.Error("Empty Accessor InsertUser should have failed") 100 } 101 } 102 103 func TestDBCreation(t *testing.T) { 104 cleanTestSlateSQ(t) 105 defer cleanTestSlateSQ(t) 106 107 os.Mkdir(rootDir, 0755) 108 109 testWithExistingDbAndTablesAndUser(t) 110 testWithExistingDbAndTable(t) 111 testWithExistingDb(t) 112 } 113 114 func createSQLiteDB(path string, t *testing.T) (*db.DB, *TestAccessor) { 115 sqlxdb, err := sqlx.Open("sqlite3", path) 116 assert.NoError(t, err, "Failed to open SQLite database") 117 118 sqlitedb := db.New(sqlxdb, "", nil) 119 accessor := NewDBAccessor(sqlitedb) 120 121 ta := &TestAccessor{ 122 Accessor: accessor, 123 DB: sqlitedb, 124 } 125 126 return sqlitedb, ta 127 } 128 129 // Test that an already bootstrapped database properly get inspected and bootstrapped with any new identities on the 130 // next server start 131 func testWithExistingDbAndTablesAndUser(t *testing.T) { 132 var err error 133 134 err = os.RemoveAll(rootDB) 135 if err != nil { 136 t.Errorf("RemoveAll failed: %s", err) 137 } 138 db, acc := createSQLiteDB(rootDB, t) 139 140 _, 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)") 141 assert.NoError(t, err, "Error creating users table") 142 143 srv := TestGetServer2(false, rootPort, rootDir, "", -1, t) 144 srv.CA.Config.DB.Datasource = "fabric_ca.db" 145 146 err = srv.Start() 147 assert.NoError(t, err, "Failed to start server") 148 149 err = srv.Stop() 150 assert.NoError(t, err, "Failed to stop server") 151 152 // Add additional user to registry and start server and confirm that it correctly get added 153 srv.RegisterBootstrapUser("admin2", "admin2pw", "") 154 155 err = srv.Start() 156 assert.NoError(t, err, "Failed to start server") 157 158 _, err = acc.Accessor.GetUser("admin2", nil) 159 assert.NoError(t, err, "Failed to correctly insert 'admin2' during second server bootstrap") 160 161 err = srv.Stop() 162 assert.NoError(t, err, "Failed to stop server") 163 164 err = db.Close() 165 assert.NoError(t, err, "Failed to close DB") 166 } 167 168 // Test starting a server with an already existing database and tables, but not bootstrapped 169 func testWithExistingDbAndTable(t *testing.T) { 170 var err error 171 172 err = os.RemoveAll(rootDB) 173 if err != nil { 174 t.Errorf("RemoveAll failed: %s", err) 175 } 176 db, acc := createSQLiteDB(rootDB, t) 177 178 srv := TestGetServer2(false, rootPort, rootDir, "", -1, t) 179 srv.CA.Config.DB.Datasource = "fabric_ca.db" 180 181 _, 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)") 182 assert.NoError(t, err, "Error creating users table") 183 184 err = srv.Start() 185 assert.NoError(t, err, "Failed to start server") 186 187 _, err = acc.Accessor.GetUser("admin", nil) 188 assert.NoError(t, err, "Failed to correctly insert 'admin' during second server bootstrap") 189 190 err = srv.Stop() 191 assert.NoError(t, err, "Failed to stop server") 192 193 err = db.Close() 194 assert.NoError(t, err, "Failed to close DB") 195 } 196 197 // Test starting a server with an already existing database, but no tables or users 198 func testWithExistingDb(t *testing.T) { 199 var err error 200 201 err = os.RemoveAll(rootDB) 202 if err != nil { 203 t.Errorf("RemoveAll failed: %s", err) 204 } 205 db, acc := createSQLiteDB(rootDB, t) 206 207 srv := TestGetServer2(false, rootPort, rootDir, "", -1, t) 208 srv.CA.Config.DB.Datasource = "fabric_ca.db" 209 210 err = srv.Start() 211 assert.NoError(t, err, "Failed to start server") 212 213 _, err = acc.Accessor.GetUser("admin", nil) 214 assert.NoError(t, err, "Failed to correctly insert 'admin' during second server bootstrap") 215 216 err = srv.Stop() 217 assert.NoError(t, err, "Failed to stop server") 218 219 err = db.Close() 220 assert.NoError(t, err, "Failed to close DB") 221 } 222 223 func cleanTestSlateSQ(t *testing.T) { 224 err := os.RemoveAll(rootDir) 225 if err != nil { 226 t.Errorf("RemoveAll failed: %s", err) 227 } 228 err = os.RemoveAll(dbPath) 229 if err != nil { 230 t.Errorf("RemoveAll failed: %s", err) 231 } 232 } 233 234 func testEverything(ta TestAccessor, t *testing.T) { 235 testInsertAndGetUser(ta, t) 236 testModifyAttribute(ta, t) 237 testDeleteUser(ta, t) 238 testUpdateUser(ta, t) 239 testInsertAndGetAffiliation(ta, t) 240 testDeleteAffiliation(ta, t) 241 testInsertAndGetFilteredUsers(ta, t) 242 } 243 244 func testInsertAndGetUser(ta TestAccessor, t *testing.T) { 245 t.Log("TestInsertAndGetUser") 246 ta.Truncate() 247 248 insert := cadbuser.Info{ 249 Name: "testId", 250 Pass: "123456", 251 Type: "client", 252 Attributes: []api.Attribute{ 253 api.Attribute{ 254 Name: "hf.Registrar.Roles", 255 Value: "peer,client,orderer,user", 256 }, 257 api.Attribute{ 258 Name: "hf.Revoker", 259 Value: "false", 260 }, 261 api.Attribute{ 262 Name: "hf.Registrar.Attributes", 263 Value: "*", 264 }, 265 api.Attribute{ 266 Name: "xyz", 267 Value: "xyz", 268 }, 269 }, 270 } 271 272 err := ta.Accessor.InsertUser(&insert) 273 if err != nil { 274 t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err) 275 } 276 277 user, err := ta.Accessor.GetUser(insert.Name, nil) 278 if err != nil { 279 t.Errorf("Error occured during querying of id: %s, error: %s", insert.Name, err) 280 } 281 282 if user.GetName() != insert.Name { 283 t.Error("Incorrect ID retrieved") 284 } 285 } 286 287 func testInsertAndGetFilteredUsers(ta TestAccessor, t *testing.T) { 288 t.Log("TestInsertAndGetFilteredUsers") 289 ta.Truncate() 290 // test type=* and affiliation is not nil 291 // insert affiliation 292 err := ta.Accessor.InsertAffiliation("Bank1", "Banks", 0) 293 if err != nil { 294 t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank1", err) 295 } 296 // create user 297 insert := cadbuser.Info{ 298 Name: "testTypes", 299 Pass: "123456", 300 Type: "*", 301 Affiliation: "Bank1", 302 Attributes: []api.Attribute{ 303 api.Attribute{ 304 Name: "hf.Registrar.Roles", 305 Value: "peer,client,orderer,user", 306 }, 307 api.Attribute{ 308 Name: "hf.Revoker", 309 Value: "false", 310 }, 311 api.Attribute{ 312 Name: "hf.Registrar.Attributes", 313 Value: "*", 314 }, 315 api.Attribute{ 316 Name: "xyz", 317 Value: "xyz", 318 }, 319 }, 320 } 321 // insert user 322 err = ta.Accessor.InsertUser(&insert) 323 if err != nil { 324 t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err) 325 } 326 // test get the user 327 rows, err := ta.Accessor.GetFilteredUsers(insert.Affiliation, "*") 328 if err != nil { 329 t.Errorf("Error occured during querying of id: %s, error: %s", insert.Name, err) 330 } 331 // use the success flag to tag success 332 successFlag := false 333 for rows.Next() { 334 var id cadbuser.Record 335 err := rows.StructScan(&id) 336 if err != nil { 337 t.Errorf("Error occured during parser the rows data: %s, error: %s", insert.Name, err) 338 } 339 // get the target user 340 if id.Affiliation == "Bank1" && id.Name == insert.Name { 341 successFlag = true 342 } 343 } 344 // not success 345 if !successFlag { 346 t.Errorf("Test InsertAndGetFilteredUsers Failed!") 347 } 348 } 349 350 func testModifyAttribute(ta TestAccessor, t *testing.T) { 351 352 user, err := ta.Accessor.GetUser("testId", nil) 353 assert.NoError(t, err, "Failed to get user") 354 355 err = user.ModifyAttributes([]api.Attribute{ 356 api.Attribute{ 357 Name: "hf.Registrar.Roles", 358 Value: "peer", 359 }, 360 api.Attribute{ 361 Name: "hf.Revoker", 362 Value: "", 363 }, 364 api.Attribute{ 365 Name: "xyz", 366 Value: "", 367 }, 368 api.Attribute{ 369 Name: "hf.IntermediateCA", 370 Value: "true", 371 }, 372 }) 373 assert.NoError(t, err, "Failed to modify user's attributes") 374 375 user, err = ta.Accessor.GetUser("testId", nil) 376 assert.NoError(t, err, "Failed to get user") 377 378 _, err = user.GetAttribute("hf.Revoker") 379 assert.Error(t, err, "Should have returned an error, attribute should have been deleted") 380 381 // Removes last attribute in the slice, should have correctly removed it 382 _, err = user.GetAttribute("xyz") 383 assert.Error(t, err, "Should have returned an error, attribute should have been deleted") 384 385 attr, err := user.GetAttribute("hf.IntermediateCA") 386 assert.NoError(t, err, "Failed to add attribute") 387 assert.Equal(t, "true", attr.Value, "Incorrect value for attribute 'hf.IntermediateCA") 388 389 attr, err = user.GetAttribute("hf.Registrar.Roles") 390 assert.NoError(t, err, "Failed to get attribute") 391 assert.Equal(t, "peer", attr.Value, "Incorrect value for attribute 'hf.Registrar.Roles") 392 393 // Test to make sure that any existing attributes that were not modified continue to exist in there original state 394 attr, err = user.GetAttribute("hf.Registrar.Attributes") 395 assert.NoError(t, err, "Failed to get attribute") 396 assert.Equal(t, "*", attr.Value) 397 } 398 399 func testDeleteUser(ta TestAccessor, t *testing.T) { 400 t.Log("TestDeleteUser") 401 ta.Truncate() 402 403 insert := cadbuser.Info{ 404 Name: "testId", 405 Pass: "123456", 406 Type: "client", 407 Attributes: []api.Attribute{}, 408 } 409 410 err := ta.Accessor.InsertUser(&insert) 411 if err != nil { 412 t.Errorf("Error occured during insert query of id: %s, error: %s", insert.Name, err) 413 } 414 415 _, err = ta.Accessor.DeleteUser(insert.Name) 416 if err != nil { 417 t.Errorf("Error occured during deletion of ID: %s, error: %s", insert.Name, err) 418 } 419 420 _, err = ta.Accessor.GetUser(insert.Name, nil) 421 if err == nil { 422 t.Error("Should have errored, and not returned any results") 423 } 424 } 425 426 func testUpdateUser(ta TestAccessor, t *testing.T) { 427 t.Log("TestUpdateUser") 428 ta.Truncate() 429 430 insert := cadbuser.Info{ 431 Name: "testId", 432 Pass: "123456", 433 Type: "client", 434 Attributes: []api.Attribute{}, 435 MaxEnrollments: 1, 436 } 437 438 err := ta.Accessor.InsertUser(&insert) 439 if err != nil { 440 t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err) 441 } 442 443 insert.Pass = "654321" 444 445 err = ta.Accessor.UpdateUser(nil, true) 446 if err == nil { 447 t.Error("Passing in nil should have resulted in an error") 448 } 449 450 err = ta.Accessor.UpdateUser(&insert, true) 451 if err != nil { 452 t.Errorf("Error occured during update query of ID: %s, error: %s", insert.Name, err) 453 } 454 455 user, err := ta.Accessor.GetUser(insert.Name, nil) 456 if err != nil { 457 t.Errorf("Error occured during querying of ID: %s, error: %s", insert.Name, err) 458 } 459 460 err = user.Login(insert.Pass, -1) 461 if err != nil { 462 t.Error("Failed to login in user: ", err) 463 } 464 465 } 466 467 func testInsertAndGetAffiliation(ta TestAccessor, t *testing.T) { 468 ta.Truncate() 469 470 err := ta.Accessor.InsertAffiliation("Bank1", "Banks", 0) 471 if err != nil { 472 t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank1", err) 473 } 474 475 group, err := ta.Accessor.GetAffiliation("Bank1") 476 if err != nil { 477 t.Errorf("Error occured during querying of name: %s, error: %s", "Bank1", err) 478 } 479 480 if group.GetName() != "Bank1" { 481 t.Error("Failed to query") 482 } 483 484 } 485 486 func testDeleteAffiliation(ta TestAccessor, t *testing.T) { 487 ta.Truncate() 488 489 err := ta.Accessor.InsertAffiliation("Banks.Bank2", "Banks", 0) 490 if err != nil { 491 t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank2", err) 492 } 493 494 _, err = ta.Accessor.DeleteAffiliation("Banks.Bank2", true, true, true) 495 if err != nil { 496 t.Errorf("Error occured during deletion of group: %s, error: %s", "Bank2", err) 497 } 498 499 _, err = ta.Accessor.GetAffiliation("Banks.Bank2") 500 if err == nil { 501 t.Error("Should have errored, and not returned any results") 502 } 503 } 504 505 func TestDBErrorMessages(t *testing.T) { 506 var err error 507 508 cleanTestSlateSQ(t) 509 defer cleanTestSlateSQ(t) 510 511 if _, err = os.Stat(dbPath); err != nil { 512 if os.IsNotExist(err) { 513 os.MkdirAll(dbPath, 0755) 514 } 515 } else { 516 err = os.RemoveAll(dbPath) 517 if err != nil { 518 t.Errorf("RemoveAll failed: %s", err) 519 } 520 os.MkdirAll(dbPath, 0755) 521 } 522 523 dataSource := dbPath + "/fabric-ca.db" 524 sqlitedb, err := getSqliteDb(dataSource) 525 if err != nil { 526 t.Error("Failed to open connection to DB") 527 } 528 accessor := NewDBAccessor(sqlitedb) 529 530 ta := TestAccessor{ 531 Accessor: accessor, 532 DB: sqlitedb, 533 } 534 535 expectedErr := "Failed to get %s" 536 _, err = ta.Accessor.GetAffiliation("hyperledger") 537 if assert.Error(t, err, "Should have errored, and not returned any results") { 538 assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "affiliation")) 539 } 540 541 _, err = ta.Accessor.GetUser("testuser", []string{}) 542 if assert.Error(t, err, "Should have errored, and not returned any results") { 543 assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "User")) 544 } 545 546 newCertDBAcc := NewCertDBAccessor(sqlitedb, 0) 547 _, err = newCertDBAcc.GetCertificateWithID("serial", "aki") 548 if assert.Error(t, err, "Should have errored, and not returned any results") { 549 assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Certificate")) 550 } 551 } 552 553 func getSqliteDb(datasource string) (*db.DB, error) { 554 sqliteDB := sqlite.NewDB(datasource, "", nil) 555 err := sqliteDB.Connect() 556 if err != nil { 557 return nil, err 558 } 559 testdb, err := sqliteDB.Create() 560 if err != nil { 561 return nil, err 562 } 563 return testdb, nil 564 }