github.com/mmatczuk/gohan@v0.0.0-20170206152520-30e45d9bdb69/extension/otto/gohan_db_test.go (about) 1 // Copyright (C) 2015 NTT Innovation Institute, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 12 // implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 16 package otto_test 17 18 import ( 19 "errors" 20 "time" 21 22 "github.com/cloudwan/gohan/db/pagination" 23 "github.com/cloudwan/gohan/db/transaction" 24 "github.com/cloudwan/gohan/extension" 25 "github.com/cloudwan/gohan/extension/otto" 26 "github.com/cloudwan/gohan/schema" 27 "github.com/cloudwan/gohan/server/middleware" 28 29 "github.com/cloudwan/gohan/db" 30 db_mocks "github.com/cloudwan/gohan/db/mocks" 31 "github.com/cloudwan/gohan/db/transaction/mocks" 32 "github.com/golang/mock/gomock" 33 . "github.com/onsi/ginkgo" 34 . "github.com/onsi/gomega" 35 ) 36 37 func newEnvironmentWithExtension(extension *schema.Extension, db db.DB) (env extension.Environment) { 38 timelimit := time.Duration(1) * time.Second 39 extensions := []*schema.Extension{extension} 40 env = otto.NewEnvironment("db_test", 41 db, &middleware.FakeIdentity{}, timelimit, testSync) 42 Expect(env.LoadExtensionsForPath(extensions, "test_path")).To(Succeed()) 43 return 44 } 45 46 var _ = Describe("GohanDb", func() { 47 var ( 48 manager *schema.Manager 49 s *schema.Schema 50 ok bool 51 fakeResources []map[string]interface{} 52 err error 53 r0, r1 *schema.Resource 54 mockCtrl *gomock.Controller 55 ) 56 57 var () 58 59 BeforeEach(func() { 60 manager = schema.GetManager() 61 s, ok = manager.Schema("test") 62 Expect(ok).To(BeTrue()) 63 mockCtrl = gomock.NewController(GinkgoT()) 64 65 fakeResources = []map[string]interface{}{ 66 map[string]interface{}{"tenant_id": "t0", "test_string": "str0", "test_bool": false}, 67 map[string]interface{}{"tenant_id": "t1", "test_string": "str1", "test_bool": true}, 68 } 69 70 r0, err = schema.NewResource(s, fakeResources[0]) 71 Expect(err).ToNot(HaveOccurred()) 72 r1, err = schema.NewResource(s, fakeResources[1]) 73 Expect(err).ToNot(HaveOccurred()) 74 75 }) 76 77 AfterEach(func() { 78 mockCtrl.Finish() 79 }) 80 81 Describe("gohan_db_transaction", func() { 82 Context("When no argument is given", func() { 83 It("doesn't run SetIsolationLevel method", func() { 84 ext, err := schema.NewExtension(map[string]interface{}{ 85 "id": "test_extension", 86 "code": ` 87 gohan_register_handler("test_event", function(context){ 88 var tx = gohan_db_transaction(); 89 tx.Commit(); 90 tx.Close(); 91 });`, 92 "path": ".*", 93 }) 94 Expect(err).ToNot(HaveOccurred()) 95 var fakeTx = new(mocks.Transaction) 96 fakeTx.On("Commit").Return(nil) 97 fakeTx.On("Close").Return(nil) 98 mockDB := db_mocks.NewMockDB(mockCtrl) 99 mockDB.EXPECT().Begin().Return(fakeTx, nil) 100 env := newEnvironmentWithExtension(ext, mockDB) 101 102 context := map[string]interface{}{} 103 104 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 105 fakeTx.AssertExpectations(GinkgoT()) 106 }) 107 }) 108 109 Context("When proper isolation level argument is given", func() { 110 It("runs SetIsolationLevel method", func() { 111 ext, err := schema.NewExtension(map[string]interface{}{ 112 "id": "test_extension", 113 "code": ` 114 gohan_register_handler("test_event", function(context){ 115 var tx = gohan_db_transaction("Serializable"); 116 tx.Commit(); 117 tx.Close(); 118 });`, 119 "path": ".*", 120 }) 121 Expect(err).ToNot(HaveOccurred()) 122 var fakeTx = new(mocks.Transaction) 123 fakeTx.On("SetIsolationLevel", transaction.Serializable).Return(nil) 124 fakeTx.On("Commit").Return(nil) 125 fakeTx.On("Close").Return(nil) 126 mockDB := db_mocks.NewMockDB(mockCtrl) 127 mockDB.EXPECT().Begin().Return(fakeTx, nil) 128 env := newEnvironmentWithExtension(ext, mockDB) 129 130 context := map[string]interface{}{} 131 132 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 133 fakeTx.AssertExpectations(GinkgoT()) 134 }) 135 }) 136 137 }) 138 139 Describe("gohan_db_list", func() { 140 Context("When valid minimum parameters are given", func() { 141 It("returns the list ordered by id", func() { 142 extension, err := schema.NewExtension(map[string]interface{}{ 143 "id": "test_extension", 144 "code": ` 145 gohan_register_handler("test_event", function(context){ 146 var tx = context.transaction; 147 context.resp = gohan_db_list( 148 tx, 149 "test", 150 {"tenant_id": "tenant0"} 151 ); 152 });`, 153 "path": ".*", 154 }) 155 Expect(err).ToNot(HaveOccurred()) 156 env := newEnvironmentWithExtension(extension, testDB) 157 158 var pagenator *pagination.Paginator 159 var fakeTx = new(mocks.Transaction) 160 fakeTx.On( 161 "List", s, transaction.Filter{"tenant_id": "tenant0"}, pagenator, 162 ).Return( 163 []*schema.Resource{r0, r1}, 164 uint64(2), 165 nil, 166 ) 167 168 context := map[string]interface{}{ 169 "transaction": fakeTx, 170 } 171 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 172 173 Expect(context["resp"]).To( 174 Equal( 175 fakeResources, 176 ), 177 ) 178 }) 179 }) 180 181 Context("When boolean parameter is given", func() { 182 It("returns the list test_bool is true", func() { 183 extension, err := schema.NewExtension(map[string]interface{}{ 184 "id": "test_extension", 185 "code": ` 186 gohan_register_handler("test_event", function(context){ 187 var tx = context.transaction; 188 context.resp = gohan_db_list( 189 tx, 190 "test", 191 {"test_bool": true} 192 ); 193 });`, 194 "path": ".*", 195 }) 196 Expect(err).ToNot(HaveOccurred()) 197 env := newEnvironmentWithExtension(extension, testDB) 198 199 var pagenator *pagination.Paginator 200 var fakeTx = new(mocks.Transaction) 201 fakeTx.On( 202 "List", s, transaction.Filter{"test_bool": true}, pagenator, 203 ).Return( 204 []*schema.Resource{r1}, 205 uint64(1), 206 nil, 207 ) 208 209 context := map[string]interface{}{ 210 "transaction": fakeTx, 211 } 212 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 213 214 Expect(context["resp"]).To( 215 Equal( 216 []map[string]interface{}{ 217 map[string]interface{}{"tenant_id": "t1", "test_string": "str1", "test_bool": true}, 218 }, 219 ), 220 ) 221 }) 222 }) 223 224 Context("When 4 parameters are given", func() { 225 It("returns the list ordered by given clumn", func() { 226 extension, err := schema.NewExtension(map[string]interface{}{ 227 "id": "test_extension", 228 "code": ` 229 gohan_register_handler("test_event", function(context){ 230 var tx = context.transaction; 231 context.resp = gohan_db_list( 232 tx, 233 "test", 234 {"tenant_id": "tenant0"}, 235 "test_string" 236 ); 237 });`, 238 "path": ".*", 239 }) 240 Expect(err).ToNot(HaveOccurred()) 241 env := newEnvironmentWithExtension(extension, testDB) 242 243 pagenator := &pagination.Paginator{ 244 Key: "test_string", 245 Order: pagination.ASC, 246 } 247 var fakeTx = new(mocks.Transaction) 248 fakeTx.On( 249 "List", s, transaction.Filter{"tenant_id": "tenant0"}, pagenator, 250 ).Return( 251 []*schema.Resource{r0, r1}, 252 uint64(2), 253 nil, 254 ) 255 256 context := map[string]interface{}{ 257 "transaction": fakeTx, 258 } 259 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 260 261 Expect(context["resp"]).To( 262 Equal( 263 fakeResources, 264 ), 265 ) 266 }) 267 }) 268 269 Context("When 5 parameters are given", func() { 270 It("returns the list ordered by given clumn and limited", func() { 271 extension, err := schema.NewExtension(map[string]interface{}{ 272 "id": "test_extension", 273 "code": ` 274 gohan_register_handler("test_event", function(context){ 275 var tx = context.transaction; 276 context.resp = gohan_db_list( 277 tx, 278 "test", 279 {"tenant_id": "tenant0"}, 280 "test_string", 281 100 282 ); 283 });`, 284 "path": ".*", 285 }) 286 Expect(err).ToNot(HaveOccurred()) 287 env := newEnvironmentWithExtension(extension, testDB) 288 289 pagenator := &pagination.Paginator{ 290 Key: "test_string", 291 Order: pagination.ASC, 292 Limit: 100, 293 } 294 var fakeTx = new(mocks.Transaction) 295 fakeTx.On( 296 "List", s, transaction.Filter{"tenant_id": "tenant0"}, pagenator, 297 ).Return( 298 []*schema.Resource{r0, r1}, 299 uint64(2), 300 nil, 301 ) 302 303 context := map[string]interface{}{ 304 "transaction": fakeTx, 305 } 306 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 307 308 Expect(context["resp"]).To( 309 Equal( 310 fakeResources, 311 ), 312 ) 313 }) 314 }) 315 316 Context("When 6 parameters are given", func() { 317 It("returns the list ordered by given clumn and limited with offset", func() { 318 extension, err := schema.NewExtension(map[string]interface{}{ 319 "id": "test_extension", 320 "code": ` 321 gohan_register_handler("test_event", function(context){ 322 var tx = context.transaction; 323 context.resp = gohan_db_list( 324 tx, 325 "test", 326 {"tenant_id": "tenant0"}, 327 "test_string", 328 100, 329 10 330 ); 331 });`, 332 "path": ".*", 333 }) 334 Expect(err).ToNot(HaveOccurred()) 335 env := newEnvironmentWithExtension(extension, testDB) 336 337 pagenator := &pagination.Paginator{ 338 Key: "test_string", 339 Order: pagination.ASC, 340 Limit: 100, 341 Offset: 10, 342 } 343 var fakeTx = new(mocks.Transaction) 344 fakeTx.On( 345 "List", s, transaction.Filter{"tenant_id": "tenant0"}, pagenator, 346 ).Return( 347 []*schema.Resource{r0, r1}, 348 uint64(2), 349 nil, 350 ) 351 352 context := map[string]interface{}{ 353 "transaction": fakeTx, 354 } 355 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 356 357 Expect(context["resp"]).To( 358 Equal( 359 fakeResources, 360 ), 361 ) 362 }) 363 }) 364 365 }) 366 367 Describe("gohan_db_state_fetch", func() { 368 Context("When valid parameters are given", func() { 369 It("returns a resource state object", func() { 370 extension, err := schema.NewExtension(map[string]interface{}{ 371 "id": "test_extension", 372 "code": ` 373 gohan_register_handler("test_event", function(context){ 374 var tx = context.transaction; 375 context.resp = gohan_db_state_fetch( 376 tx, 377 "test", 378 "resource_id", 379 "tenant0" 380 ); 381 });`, 382 "path": ".*", 383 }) 384 Expect(err).ToNot(HaveOccurred()) 385 env := newEnvironmentWithExtension(extension, testDB) 386 387 var fakeTx = new(mocks.Transaction) 388 fakeTx.On( 389 "StateFetch", s, 390 transaction.Filter{"id": "resource_id", "tenant_id": "tenant0"}, 391 ).Return( 392 transaction.ResourceState{ 393 ConfigVersion: 30, 394 StateVersion: 29, 395 Error: "e", 396 State: "s", 397 Monitoring: "m", 398 }, 399 nil, 400 ) 401 402 context := map[string]interface{}{ 403 "transaction": fakeTx, 404 } 405 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 406 407 Expect(context["resp"]).To( 408 Equal( 409 map[string]interface{}{ 410 "config_version": int64(30), 411 "state_version": int64(29), 412 "error": "e", 413 "state": "s", 414 "monitoring": "m", 415 }, 416 ), 417 ) 418 }) 419 }) 420 }) 421 422 Describe("gohan_db_sql_make_columns", func() { 423 Context("when a valid schema ID is given", func() { 424 It("returns column names in Gohan DB compatible format", func() { 425 extension, err := schema.NewExtension(map[string]interface{}{ 426 "id": "test_extension", 427 "code": ` 428 gohan_register_handler("test_event", function(context){ 429 context.resp = gohan_db_sql_make_columns("test"); 430 });`, 431 "path": ".*", 432 }) 433 Expect(err).ToNot(HaveOccurred()) 434 env := newEnvironmentWithExtension(extension, testDB) 435 436 context := map[string]interface{}{} 437 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 438 Expect(context["resp"]).To(ContainElement("tests.`id` as `tests__id`")) 439 Expect(context["resp"]).To(ContainElement("tests.`tenant_id` as `tests__tenant_id`")) 440 Expect(context["resp"]).To(ContainElement("tests.`test_string` as `tests__test_string`")) 441 }) 442 }) 443 444 Context("when an invalid schema ID is given", func() { 445 It("returns an error", func() { 446 extension, err := schema.NewExtension(map[string]interface{}{ 447 "id": "test_extension", 448 "code": ` 449 gohan_register_handler("test_event", function(context){ 450 context.resp = gohan_db_sql_make_columns("NOT EXIST"); 451 });`, 452 "path": ".*", 453 }) 454 Expect(err).ToNot(HaveOccurred()) 455 env := newEnvironmentWithExtension(extension, testDB) 456 457 context := map[string]interface{}{} 458 err = env.HandleEvent("test_event", context) 459 Expect(err).NotTo(BeNil()) 460 Expect(err.Error()).To(MatchRegexp("test_event: Error: Unknown schema 'NOT EXIST'")) 461 }) 462 }) 463 464 }) 465 466 Describe("gohan_db_query", func() { 467 Context("when valid parameters are given", func() { 468 It("returns resources in db", func() { 469 extension, err := schema.NewExtension(map[string]interface{}{ 470 "id": "test_extension", 471 "code": ` 472 gohan_register_handler("test_event", function(context){ 473 var tx = context.transaction; 474 context.resp = gohan_db_query( 475 tx, 476 "test", 477 "SELECT DUMMY", 478 ["tenant0", "obj1"] 479 ); 480 });`, 481 "path": ".*", 482 }) 483 Expect(err).ToNot(HaveOccurred()) 484 env := newEnvironmentWithExtension(extension, testDB) 485 486 var fakeTx = new(mocks.Transaction) 487 fakeTx.On( 488 "Query", s, "SELECT DUMMY", []interface{}{"tenant0", "obj1"}, 489 ).Return( 490 []*schema.Resource{r0, r1}, nil, 491 ) 492 493 context := map[string]interface{}{ 494 "transaction": fakeTx, 495 } 496 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 497 Expect(context["resp"]).To(Equal(fakeResources)) 498 }) 499 }) 500 501 Context("When an invalid transaction is provided", func() { 502 It("fails and return an error", func() { 503 extension, err := schema.NewExtension(map[string]interface{}{ 504 "id": "test_extension", 505 "code": ` 506 gohan_register_handler("test_event", function(context){ 507 var tx = context.transaction; 508 context.resp = gohan_db_query( 509 tx, 510 "test", 511 "SELECT DUMMY", 512 ["tenant0", "obj1"] 513 ); 514 });`, 515 "path": ".*", 516 }) 517 Expect(err).ToNot(HaveOccurred()) 518 env := newEnvironmentWithExtension(extension, testDB) 519 520 context := map[string]interface{}{ 521 "transaction": "not_a_transaction", 522 } 523 524 err = env.HandleEvent("test_event", context) 525 Expect(err).NotTo(BeNil()) 526 Expect(err.Error()).To(MatchRegexp("test_event: Error: Argument 'not_a_transaction' should be of type 'Transaction'")) 527 }) 528 }) 529 530 Context("When an invalid schema ID is provided", func() { 531 It("fails and return an error", func() { 532 extension, err := schema.NewExtension(map[string]interface{}{ 533 "id": "test_extension", 534 "code": ` 535 gohan_register_handler("test_event", function(context){ 536 var tx = context.transaction; 537 context.resp = gohan_db_query( 538 tx, 539 "INVALID_SCHEMA_ID", 540 "SELECT DUMMY", 541 ["tenant0", "obj1"] 542 ); 543 });`, 544 "path": ".*", 545 }) 546 Expect(err).ToNot(HaveOccurred()) 547 env := newEnvironmentWithExtension(extension, testDB) 548 549 context := map[string]interface{}{ 550 "transaction": new(mocks.Transaction), 551 } 552 err = env.HandleEvent("test_event", context) 553 Expect(err).NotTo(BeNil()) 554 Expect(err.Error()).To(MatchRegexp("test_event: Error: Unknown schema 'INVALID_SCHEMA_ID'")) 555 }) 556 }) 557 558 Context("When an invalid array is provided to arguments", func() { 559 It("fails and return an error", func() { 560 extension, err := schema.NewExtension(map[string]interface{}{ 561 "id": "test_extension", 562 "code": ` 563 gohan_register_handler("test_event", function(context){ 564 var tx = context.transaction; 565 context.resp = gohan_db_query( 566 tx, 567 "test", 568 "SELECT DUMMY", 569 "THIS IS NOT AN ARRAY" 570 ); 571 });`, 572 "path": ".*", 573 }) 574 Expect(err).ToNot(HaveOccurred()) 575 env := newEnvironmentWithExtension(extension, testDB) 576 577 context := map[string]interface{}{ 578 "transaction": new(mocks.Transaction), 579 } 580 err = env.HandleEvent("test_event", context) 581 Expect(err).NotTo(BeNil()) 582 Expect(err.Error()).To(MatchRegexp("test_event: Error: Argument 'THIS IS NOT AN ARRAY' should be of type 'array'")) 583 }) 584 }) 585 586 Context("When an error occurred while processing the query", func() { 587 It("fails and return an error", func() { 588 extension, err := schema.NewExtension(map[string]interface{}{ 589 "id": "test_extension", 590 "code": ` 591 gohan_register_handler("test_event", function(context){ 592 var tx = context.transaction; 593 context.resp = gohan_db_query( 594 tx, 595 "test", 596 "SELECT DUMMY", 597 [] 598 ); 599 });`, 600 "path": ".*", 601 }) 602 Expect(err).ToNot(HaveOccurred()) 603 env := newEnvironmentWithExtension(extension, testDB) 604 605 var fakeTx = new(mocks.Transaction) 606 fakeTx.On( 607 "Query", s, "SELECT DUMMY", []interface{}{}, 608 ).Return( 609 nil, errors.New("SOMETHING HAPPENED"), 610 ) 611 612 context := map[string]interface{}{ 613 "transaction": fakeTx, 614 } 615 err = env.HandleEvent("test_event", context) 616 Expect(err).NotTo(BeNil()) 617 Expect(err.Error()).To(MatchRegexp("test_event: Error: Error during gohan_db_query: SOMETHING HAPPEN")) 618 }) 619 }) 620 621 }) 622 })