github.com/dddengyunjie/fabric-ca@v0.0.0-20190606043049-92df60ae2f0f/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/hyperledger/fabric/common/metrics/disabled" 21 "github.com/jmoiron/sqlx" 22 _ "github.com/mattn/go-sqlite3" 23 "github.com/stretchr/testify/assert" 24 ) 25 26 const ( 27 dbPath = "/tmp/dbtesting" 28 29 sqliteTruncateTables = ` 30 DELETE FROM Users; 31 DELETE FROM affiliations; 32 ` 33 34 rootDB = "rootDir/fabric_ca.db" 35 ) 36 37 type TestAccessor struct { 38 Accessor *Accessor 39 DB *db.DB 40 } 41 42 func (ta *TestAccessor) Truncate() { 43 Truncate(ta.DB) 44 } 45 46 func TestSQLite(t *testing.T) { 47 cleanTestSlateSQ(t) 48 defer cleanTestSlateSQ(t) 49 50 if _, err := os.Stat(dbPath); err != nil { 51 if os.IsNotExist(err) { 52 os.MkdirAll(dbPath, 0755) 53 } 54 } else { 55 err = os.RemoveAll(dbPath) 56 if err != nil { 57 t.Errorf("RemoveAll failed: %s", err) 58 } 59 os.MkdirAll(dbPath, 0755) 60 } 61 dataSource := dbPath + "/fabric-ca.db" 62 sqlitedb, err := getSqliteDb(dataSource) 63 if err != nil { 64 t.Error("Failed to open connection to DB") 65 } 66 accessor := NewDBAccessor(sqlitedb) 67 68 ta := TestAccessor{ 69 Accessor: accessor, 70 DB: sqlitedb, 71 } 72 testEverything(ta, t) 73 } 74 75 // Truncate truncates the DB 76 func Truncate(db *db.DB) { 77 var sql []string 78 sql = []string{sqliteTruncateTables} 79 80 for _, expr := range sql { 81 if len(strings.TrimSpace(expr)) == 0 { 82 continue 83 } 84 if _, err := db.Exec("", expr); err != nil { 85 panic(err) 86 } 87 } 88 } 89 90 func TestEmptyAccessor(t *testing.T) { 91 a := &Accessor{} 92 ui := cadbuser.Info{} 93 err := a.InsertUser(nil) 94 if err == nil { 95 t.Error("Passing in nil should have resulted in an error") 96 } 97 98 err = a.InsertUser(&ui) 99 if err == nil { 100 t.Error("Empty Accessor InsertUser should have failed") 101 } 102 } 103 104 func TestDBCreation(t *testing.T) { 105 cleanTestSlateSQ(t) 106 defer cleanTestSlateSQ(t) 107 108 os.Mkdir(rootDir, 0755) 109 110 testWithExistingDbAndTablesAndUser(t) 111 testWithExistingDbAndTable(t) 112 testWithExistingDb(t) 113 } 114 115 func createSQLiteDB(path string, t *testing.T) (*db.DB, *TestAccessor) { 116 sqlxdb, err := sqlx.Open("sqlite3", path) 117 assert.NoError(t, err, "Failed to open SQLite database") 118 119 sqlitedb := db.New(sqlxdb, "", &disabled.Provider{}) 120 accessor := NewDBAccessor(sqlitedb) 121 122 ta := &TestAccessor{ 123 Accessor: accessor, 124 DB: sqlitedb, 125 } 126 127 return sqlitedb, ta 128 } 129 130 // Test that an already bootstrapped database properly get inspected and bootstrapped with any new identities on the 131 // next server start 132 func testWithExistingDbAndTablesAndUser(t *testing.T) { 133 var err error 134 135 err = os.RemoveAll(rootDB) 136 if err != nil { 137 t.Errorf("RemoveAll failed: %s", err) 138 } 139 db, acc := createSQLiteDB(rootDB, t) 140 141 _, 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)") 142 assert.NoError(t, err, "Error creating users table") 143 144 srv := TestGetServer2(false, rootPort, rootDir, "", -1, t) 145 srv.CA.Config.DB.Datasource = "fabric_ca.db" 146 147 err = srv.Start() 148 assert.NoError(t, err, "Failed to start server") 149 150 err = srv.Stop() 151 assert.NoError(t, err, "Failed to stop server") 152 153 // Add additional user to registry and start server and confirm that it correctly get added 154 srv.RegisterBootstrapUser("admin2", "admin2pw", "") 155 156 err = srv.Start() 157 assert.NoError(t, err, "Failed to start server") 158 159 _, err = acc.Accessor.GetUser("admin2", nil) 160 assert.NoError(t, err, "Failed to correctly insert 'admin2' during second server bootstrap") 161 162 err = srv.Stop() 163 assert.NoError(t, err, "Failed to stop server") 164 165 err = db.Close() 166 assert.NoError(t, err, "Failed to close DB") 167 } 168 169 // Test starting a server with an already existing database and tables, but not bootstrapped 170 func testWithExistingDbAndTable(t *testing.T) { 171 var err error 172 173 err = os.RemoveAll(rootDB) 174 if err != nil { 175 t.Errorf("RemoveAll failed: %s", err) 176 } 177 db, acc := createSQLiteDB(rootDB, t) 178 179 srv := TestGetServer2(false, rootPort, rootDir, "", -1, t) 180 srv.CA.Config.DB.Datasource = "fabric_ca.db" 181 182 _, 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)") 183 assert.NoError(t, err, "Error creating users table") 184 185 err = srv.Start() 186 assert.NoError(t, err, "Failed to start server") 187 188 _, err = acc.Accessor.GetUser("admin", nil) 189 assert.NoError(t, err, "Failed to correctly insert 'admin' during second server bootstrap") 190 191 err = srv.Stop() 192 assert.NoError(t, err, "Failed to stop server") 193 194 err = db.Close() 195 assert.NoError(t, err, "Failed to close DB") 196 } 197 198 // Test starting a server with an already existing database, but no tables or users 199 func testWithExistingDb(t *testing.T) { 200 var err error 201 202 err = os.RemoveAll(rootDB) 203 if err != nil { 204 t.Errorf("RemoveAll failed: %s", err) 205 } 206 db, acc := createSQLiteDB(rootDB, t) 207 208 srv := TestGetServer2(false, rootPort, rootDir, "", -1, t) 209 srv.CA.Config.DB.Datasource = "fabric_ca.db" 210 211 err = srv.Start() 212 assert.NoError(t, err, "Failed to start server") 213 214 _, err = acc.Accessor.GetUser("admin", nil) 215 assert.NoError(t, err, "Failed to correctly insert 'admin' during second server bootstrap") 216 217 err = srv.Stop() 218 assert.NoError(t, err, "Failed to stop server") 219 220 err = db.Close() 221 assert.NoError(t, err, "Failed to close DB") 222 } 223 224 func cleanTestSlateSQ(t *testing.T) { 225 err := os.RemoveAll(rootDir) 226 if err != nil { 227 t.Errorf("RemoveAll failed: %s", err) 228 } 229 err = os.RemoveAll(dbPath) 230 if err != nil { 231 t.Errorf("RemoveAll failed: %s", err) 232 } 233 } 234 235 func testEverything(ta TestAccessor, t *testing.T) { 236 testInsertAndGetUser(ta, t) 237 testModifyAttribute(ta, t) 238 testDeleteUser(ta, t) 239 testUpdateUser(ta, t) 240 testInsertAndGetAffiliation(ta, t) 241 testDeleteAffiliation(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 testModifyAttribute(ta TestAccessor, t *testing.T) { 288 289 user, err := ta.Accessor.GetUser("testId", nil) 290 assert.NoError(t, err, "Failed to get user") 291 292 err = user.ModifyAttributes([]api.Attribute{ 293 api.Attribute{ 294 Name: "hf.Registrar.Roles", 295 Value: "peer", 296 }, 297 api.Attribute{ 298 Name: "hf.Revoker", 299 Value: "", 300 }, 301 api.Attribute{ 302 Name: "xyz", 303 Value: "", 304 }, 305 api.Attribute{ 306 Name: "hf.IntermediateCA", 307 Value: "true", 308 }, 309 }) 310 assert.NoError(t, err, "Failed to modify user's attributes") 311 312 user, err = ta.Accessor.GetUser("testId", nil) 313 assert.NoError(t, err, "Failed to get user") 314 315 _, err = user.GetAttribute("hf.Revoker") 316 assert.Error(t, err, "Should have returned an error, attribute should have been deleted") 317 318 // Removes last attribute in the slice, should have correctly removed it 319 _, err = user.GetAttribute("xyz") 320 assert.Error(t, err, "Should have returned an error, attribute should have been deleted") 321 322 attr, err := user.GetAttribute("hf.IntermediateCA") 323 assert.NoError(t, err, "Failed to add attribute") 324 assert.Equal(t, "true", attr.Value, "Incorrect value for attribute 'hf.IntermediateCA") 325 326 attr, err = user.GetAttribute("hf.Registrar.Roles") 327 assert.NoError(t, err, "Failed to get attribute") 328 assert.Equal(t, "peer", attr.Value, "Incorrect value for attribute 'hf.Registrar.Roles") 329 330 // Test to make sure that any existing attributes that were not modified continue to exist in there original state 331 attr, err = user.GetAttribute("hf.Registrar.Attributes") 332 assert.NoError(t, err, "Failed to get attribute") 333 assert.Equal(t, "*", attr.Value) 334 } 335 336 func testDeleteUser(ta TestAccessor, t *testing.T) { 337 t.Log("TestDeleteUser") 338 ta.Truncate() 339 340 insert := cadbuser.Info{ 341 Name: "testId", 342 Pass: "123456", 343 Type: "client", 344 Attributes: []api.Attribute{}, 345 } 346 347 err := ta.Accessor.InsertUser(&insert) 348 if err != nil { 349 t.Errorf("Error occured during insert query of id: %s, error: %s", insert.Name, err) 350 } 351 352 _, err = ta.Accessor.DeleteUser(insert.Name) 353 if err != nil { 354 t.Errorf("Error occured during deletion of ID: %s, error: %s", insert.Name, err) 355 } 356 357 _, err = ta.Accessor.GetUser(insert.Name, nil) 358 if err == nil { 359 t.Error("Should have errored, and not returned any results") 360 } 361 } 362 363 func testUpdateUser(ta TestAccessor, t *testing.T) { 364 t.Log("TestUpdateUser") 365 ta.Truncate() 366 367 insert := cadbuser.Info{ 368 Name: "testId", 369 Pass: "123456", 370 Type: "client", 371 Attributes: []api.Attribute{}, 372 MaxEnrollments: 1, 373 } 374 375 err := ta.Accessor.InsertUser(&insert) 376 if err != nil { 377 t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err) 378 } 379 380 insert.Pass = "654321" 381 382 err = ta.Accessor.UpdateUser(nil, true) 383 if err == nil { 384 t.Error("Passing in nil should have resulted in an error") 385 } 386 387 err = ta.Accessor.UpdateUser(&insert, true) 388 if err != nil { 389 t.Errorf("Error occured during update query of ID: %s, error: %s", insert.Name, err) 390 } 391 392 user, err := ta.Accessor.GetUser(insert.Name, nil) 393 if err != nil { 394 t.Errorf("Error occured during querying of ID: %s, error: %s", insert.Name, err) 395 } 396 397 err = user.Login(insert.Pass, -1) 398 if err != nil { 399 t.Error("Failed to login in user: ", err) 400 } 401 402 } 403 404 func testInsertAndGetAffiliation(ta TestAccessor, t *testing.T) { 405 ta.Truncate() 406 407 err := ta.Accessor.InsertAffiliation("Bank1", "Banks", 0) 408 if err != nil { 409 t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank1", err) 410 } 411 412 group, err := ta.Accessor.GetAffiliation("Bank1") 413 if err != nil { 414 t.Errorf("Error occured during querying of name: %s, error: %s", "Bank1", err) 415 } 416 417 if group.GetName() != "Bank1" { 418 t.Error("Failed to query") 419 } 420 421 } 422 423 func testDeleteAffiliation(ta TestAccessor, t *testing.T) { 424 ta.Truncate() 425 426 err := ta.Accessor.InsertAffiliation("Banks.Bank2", "Banks", 0) 427 if err != nil { 428 t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank2", err) 429 } 430 431 _, err = ta.Accessor.DeleteAffiliation("Banks.Bank2", true, true, true) 432 if err != nil { 433 t.Errorf("Error occured during deletion of group: %s, error: %s", "Bank2", err) 434 } 435 436 _, err = ta.Accessor.GetAffiliation("Banks.Bank2") 437 if err == nil { 438 t.Error("Should have errored, and not returned any results") 439 } 440 } 441 442 func TestDBErrorMessages(t *testing.T) { 443 var err error 444 445 cleanTestSlateSQ(t) 446 defer cleanTestSlateSQ(t) 447 448 if _, err = os.Stat(dbPath); err != nil { 449 if os.IsNotExist(err) { 450 os.MkdirAll(dbPath, 0755) 451 } 452 } else { 453 err = os.RemoveAll(dbPath) 454 if err != nil { 455 t.Errorf("RemoveAll failed: %s", err) 456 } 457 os.MkdirAll(dbPath, 0755) 458 } 459 460 dataSource := dbPath + "/fabric-ca.db" 461 sqlitedb, err := getSqliteDb(dataSource) 462 if err != nil { 463 t.Error("Failed to open connection to DB") 464 } 465 accessor := NewDBAccessor(sqlitedb) 466 467 ta := TestAccessor{ 468 Accessor: accessor, 469 DB: sqlitedb, 470 } 471 472 expectedErr := "Failed to get %s" 473 _, err = ta.Accessor.GetAffiliation("hyperledger") 474 if assert.Error(t, err, "Should have errored, and not returned any results") { 475 assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Affiliation")) 476 } 477 478 _, err = ta.Accessor.GetUser("testuser", []string{}) 479 if assert.Error(t, err, "Should have errored, and not returned any results") { 480 assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "User")) 481 } 482 483 newCertDBAcc := NewCertDBAccessor(sqlitedb, 0) 484 _, err = newCertDBAcc.GetCertificateWithID("serial", "aki") 485 if assert.Error(t, err, "Should have errored, and not returned any results") { 486 assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Certificate")) 487 } 488 } 489 490 func getSqliteDb(datasource string) (*db.DB, error) { 491 sqliteDB := sqlite.NewDB(datasource, "", &disabled.Provider{}) 492 err := sqliteDB.Connect() 493 if err != nil { 494 return nil, err 495 } 496 testdb, err := sqliteDB.Create() 497 if err != nil { 498 return nil, err 499 } 500 return testdb, nil 501 }