github.com/simranvc/fabric-ca@v0.0.0-20191030094829-acc364294dde/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 } 242 243 func testInsertAndGetUser(ta TestAccessor, t *testing.T) { 244 t.Log("TestInsertAndGetUser") 245 ta.Truncate() 246 247 insert := cadbuser.Info{ 248 Name: "testId", 249 Pass: "123456", 250 Type: "client", 251 Attributes: []api.Attribute{ 252 api.Attribute{ 253 Name: "hf.Registrar.Roles", 254 Value: "peer,client,orderer,user", 255 }, 256 api.Attribute{ 257 Name: "hf.Revoker", 258 Value: "false", 259 }, 260 api.Attribute{ 261 Name: "hf.Registrar.Attributes", 262 Value: "*", 263 }, 264 api.Attribute{ 265 Name: "xyz", 266 Value: "xyz", 267 }, 268 }, 269 } 270 271 err := ta.Accessor.InsertUser(&insert) 272 if err != nil { 273 t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err) 274 } 275 276 user, err := ta.Accessor.GetUser(insert.Name, nil) 277 if err != nil { 278 t.Errorf("Error occured during querying of id: %s, error: %s", insert.Name, err) 279 } 280 281 if user.GetName() != insert.Name { 282 t.Error("Incorrect ID retrieved") 283 } 284 } 285 286 func testModifyAttribute(ta TestAccessor, t *testing.T) { 287 288 user, err := ta.Accessor.GetUser("testId", nil) 289 assert.NoError(t, err, "Failed to get user") 290 291 err = user.ModifyAttributes([]api.Attribute{ 292 api.Attribute{ 293 Name: "hf.Registrar.Roles", 294 Value: "peer", 295 }, 296 api.Attribute{ 297 Name: "hf.Revoker", 298 Value: "", 299 }, 300 api.Attribute{ 301 Name: "xyz", 302 Value: "", 303 }, 304 api.Attribute{ 305 Name: "hf.IntermediateCA", 306 Value: "true", 307 }, 308 }) 309 assert.NoError(t, err, "Failed to modify user's attributes") 310 311 user, err = ta.Accessor.GetUser("testId", nil) 312 assert.NoError(t, err, "Failed to get user") 313 314 _, err = user.GetAttribute("hf.Revoker") 315 assert.Error(t, err, "Should have returned an error, attribute should have been deleted") 316 317 // Removes last attribute in the slice, should have correctly removed it 318 _, err = user.GetAttribute("xyz") 319 assert.Error(t, err, "Should have returned an error, attribute should have been deleted") 320 321 attr, err := user.GetAttribute("hf.IntermediateCA") 322 assert.NoError(t, err, "Failed to add attribute") 323 assert.Equal(t, "true", attr.Value, "Incorrect value for attribute 'hf.IntermediateCA") 324 325 attr, err = user.GetAttribute("hf.Registrar.Roles") 326 assert.NoError(t, err, "Failed to get attribute") 327 assert.Equal(t, "peer", attr.Value, "Incorrect value for attribute 'hf.Registrar.Roles") 328 329 // Test to make sure that any existing attributes that were not modified continue to exist in there original state 330 attr, err = user.GetAttribute("hf.Registrar.Attributes") 331 assert.NoError(t, err, "Failed to get attribute") 332 assert.Equal(t, "*", attr.Value) 333 } 334 335 func testDeleteUser(ta TestAccessor, t *testing.T) { 336 t.Log("TestDeleteUser") 337 ta.Truncate() 338 339 insert := cadbuser.Info{ 340 Name: "testId", 341 Pass: "123456", 342 Type: "client", 343 Attributes: []api.Attribute{}, 344 } 345 346 err := ta.Accessor.InsertUser(&insert) 347 if err != nil { 348 t.Errorf("Error occured during insert query of id: %s, error: %s", insert.Name, err) 349 } 350 351 _, err = ta.Accessor.DeleteUser(insert.Name) 352 if err != nil { 353 t.Errorf("Error occured during deletion of ID: %s, error: %s", insert.Name, err) 354 } 355 356 _, err = ta.Accessor.GetUser(insert.Name, nil) 357 if err == nil { 358 t.Error("Should have errored, and not returned any results") 359 } 360 } 361 362 func testUpdateUser(ta TestAccessor, t *testing.T) { 363 t.Log("TestUpdateUser") 364 ta.Truncate() 365 366 insert := cadbuser.Info{ 367 Name: "testId", 368 Pass: "123456", 369 Type: "client", 370 Attributes: []api.Attribute{}, 371 MaxEnrollments: 1, 372 } 373 374 err := ta.Accessor.InsertUser(&insert) 375 if err != nil { 376 t.Errorf("Error occured during insert query of ID: %s, error: %s", insert.Name, err) 377 } 378 379 insert.Pass = "654321" 380 381 err = ta.Accessor.UpdateUser(nil, true) 382 if err == nil { 383 t.Error("Passing in nil should have resulted in an error") 384 } 385 386 err = ta.Accessor.UpdateUser(&insert, true) 387 if err != nil { 388 t.Errorf("Error occured during update query of ID: %s, error: %s", insert.Name, err) 389 } 390 391 user, err := ta.Accessor.GetUser(insert.Name, nil) 392 if err != nil { 393 t.Errorf("Error occured during querying of ID: %s, error: %s", insert.Name, err) 394 } 395 396 err = user.Login(insert.Pass, -1) 397 if err != nil { 398 t.Error("Failed to login in user: ", err) 399 } 400 401 } 402 403 func testInsertAndGetAffiliation(ta TestAccessor, t *testing.T) { 404 ta.Truncate() 405 406 err := ta.Accessor.InsertAffiliation("Bank1", "Banks", 0) 407 if err != nil { 408 t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank1", err) 409 } 410 411 group, err := ta.Accessor.GetAffiliation("Bank1") 412 if err != nil { 413 t.Errorf("Error occured during querying of name: %s, error: %s", "Bank1", err) 414 } 415 416 if group.GetName() != "Bank1" { 417 t.Error("Failed to query") 418 } 419 420 } 421 422 func testDeleteAffiliation(ta TestAccessor, t *testing.T) { 423 ta.Truncate() 424 425 err := ta.Accessor.InsertAffiliation("Banks.Bank2", "Banks", 0) 426 if err != nil { 427 t.Errorf("Error occured during insert query of group: %s, error: %s", "Bank2", err) 428 } 429 430 _, err = ta.Accessor.DeleteAffiliation("Banks.Bank2", true, true, true) 431 if err != nil { 432 t.Errorf("Error occured during deletion of group: %s, error: %s", "Bank2", err) 433 } 434 435 _, err = ta.Accessor.GetAffiliation("Banks.Bank2") 436 if err == nil { 437 t.Error("Should have errored, and not returned any results") 438 } 439 } 440 441 func TestDBErrorMessages(t *testing.T) { 442 var err error 443 444 cleanTestSlateSQ(t) 445 defer cleanTestSlateSQ(t) 446 447 if _, err = os.Stat(dbPath); err != nil { 448 if os.IsNotExist(err) { 449 os.MkdirAll(dbPath, 0755) 450 } 451 } else { 452 err = os.RemoveAll(dbPath) 453 if err != nil { 454 t.Errorf("RemoveAll failed: %s", err) 455 } 456 os.MkdirAll(dbPath, 0755) 457 } 458 459 dataSource := dbPath + "/fabric-ca.db" 460 sqlitedb, err := getSqliteDb(dataSource) 461 if err != nil { 462 t.Error("Failed to open connection to DB") 463 } 464 accessor := NewDBAccessor(sqlitedb) 465 466 ta := TestAccessor{ 467 Accessor: accessor, 468 DB: sqlitedb, 469 } 470 471 expectedErr := "Failed to get %s" 472 _, err = ta.Accessor.GetAffiliation("hyperledger") 473 if assert.Error(t, err, "Should have errored, and not returned any results") { 474 assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Affiliation")) 475 } 476 477 _, err = ta.Accessor.GetUser("testuser", []string{}) 478 if assert.Error(t, err, "Should have errored, and not returned any results") { 479 assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "User")) 480 } 481 482 newCertDBAcc := NewCertDBAccessor(sqlitedb, 0) 483 _, err = newCertDBAcc.GetCertificateWithID("serial", "aki") 484 if assert.Error(t, err, "Should have errored, and not returned any results") { 485 assert.Contains(t, err.Error(), fmt.Sprintf(expectedErr, "Certificate")) 486 } 487 } 488 489 func getSqliteDb(datasource string) (*db.DB, error) { 490 sqliteDB := sqlite.NewDB(datasource, "", nil) 491 err := sqliteDB.Connect() 492 if err != nil { 493 return nil, err 494 } 495 testdb, err := sqliteDB.Create() 496 if err != nil { 497 return nil, err 498 } 499 return testdb, nil 500 }