github.com/jbking/gohan@v0.0.0-20151217002006-b41ccf1c2a96/extension/otto/otto_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 "fmt" 20 "regexp" 21 "time" 22 23 ottopkg "github.com/dop251/otto" 24 . "github.com/onsi/ginkgo" 25 . "github.com/onsi/gomega" 26 "github.com/onsi/gomega/ghttp" 27 28 "github.com/cloudwan/gohan/db/transaction" 29 "github.com/cloudwan/gohan/extension" 30 "github.com/cloudwan/gohan/extension/otto" 31 "github.com/cloudwan/gohan/schema" 32 "github.com/cloudwan/gohan/server/middleware" 33 "github.com/cloudwan/gohan/server/resources" 34 "github.com/cloudwan/gohan/util" 35 ) 36 37 var _ = Describe("Otto extension manager", func() { 38 var ( 39 manager *schema.Manager 40 environmentManager *extension.Manager 41 ) 42 43 BeforeEach(func() { 44 manager = schema.GetManager() 45 environmentManager = extension.GetManager() 46 }) 47 48 AfterEach(func() { 49 tx, err := testDB.Begin() 50 Expect(err).ToNot(HaveOccurred(), "Failed to create transaction.") 51 defer tx.Close() 52 for _, schema := range schema.GetManager().Schemas() { 53 if whitelist[schema.ID] { 54 continue 55 } 56 err = clearTable(tx, schema) 57 Expect(err).ToNot(HaveOccurred(), "Failed to clear table.") 58 } 59 err = tx.Commit() 60 Expect(err).ToNot(HaveOccurred(), "Failed to commite transaction.") 61 62 extension.ClearManager() 63 }) 64 65 Describe("Loading an extension", func() { 66 Context("When extension is not a valid JavaScript", func() { 67 It("returns a meaningful compilation error", func() { 68 goodExtension, err := schema.NewExtension(map[string]interface{}{ 69 "id": "good_extension", 70 "code": `gohan_register_handler("test_event", function(context) {});`, 71 "path": ".*", 72 }) 73 Expect(err).ToNot(HaveOccurred()) 74 goodExtension.URL = "good_extension.js" 75 76 badExtension, err := schema.NewExtension(map[string]interface{}{ 77 "id": "bad_extension", 78 "code": `gohan_register_handler("test_event", function(context {});`, 79 "path": ".*", 80 }) 81 Expect(err).ToNot(HaveOccurred()) 82 badExtension.URL = "bad_extension.js" 83 84 extensions := []*schema.Extension{goodExtension, badExtension} 85 env := otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 86 err = env.LoadExtensionsForPath(extensions, "test_path") 87 Expect(err).To(HaveOccurred(), "Expected compilation errors.") 88 89 pattern := regexp.MustCompile(`^(?P<file>[^:]+).*Line\s(?P<line>\d+).*`) 90 match := pattern.FindStringSubmatch(err.Error()) 91 Expect(len(match)).To(Equal(3)) 92 93 groups := make(map[string]string) 94 for i, name := range pattern.SubexpNames() { 95 groups[name] = match[i] 96 } 97 98 Expect(groups).To(HaveKeyWithValue("file", "bad_extension.js")) 99 Expect(groups).To(HaveKeyWithValue("line", "1")) 100 }) 101 }) 102 103 Context("When extension URL uses file:// protocol", func() { 104 It("should read the file and run the extension", func() { 105 extension, err := schema.NewExtension(map[string]interface{}{ 106 "id": "test_extension", 107 "url": "file://../tests/sample_extension.js", 108 "path": ".*", 109 }) 110 Expect(err).ToNot(HaveOccurred()) 111 112 extensions := []*schema.Extension{extension} 113 env := otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 114 Expect(env.LoadExtensionsForPath(extensions, "test_path")).To(Succeed()) 115 116 context := map[string]interface{}{ 117 "id": "test", 118 } 119 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 120 Expect(context["resp"]).ToNot(BeNil()) 121 }) 122 }) 123 124 Context("When extension URL uses http:// protocol", func() { 125 It("should download and run the extension", func() { 126 server := ghttp.NewServer() 127 code := ` 128 gohan_register_handler("test_event", function(context){ 129 context.resp = "Hello"; 130 }); 131 ` 132 server.AppendHandlers(ghttp.CombineHandlers( 133 ghttp.VerifyRequest("GET", "/extension.js"), 134 ghttp.RespondWith(200, code), 135 )) 136 137 extension, err := schema.NewExtension(map[string]interface{}{ 138 "id": "test_extension", 139 "url": server.URL() + "/extension.js", 140 "path": ".*", 141 }) 142 Expect(err).ToNot(HaveOccurred()) 143 extensions := []*schema.Extension{extension} 144 env := otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 145 Expect(env.LoadExtensionsForPath(extensions, "test_path")).To(Succeed()) 146 147 context := map[string]interface{}{ 148 "id": "test", 149 } 150 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 151 Expect(context["resp"]).ToNot(BeNil()) 152 server.Close() 153 }) 154 }) 155 }) 156 157 Describe("Running an extension", func() { 158 Context("When a runtime error occurs", func() { 159 It("should return a meaningful error", func() { 160 goodExtension, err := schema.NewExtension(map[string]interface{}{ 161 "id": "good_extension", 162 "code": `gohan_register_handler("test_event", function(context) {});`, 163 "path": ".*", 164 }) 165 Expect(err).ToNot(HaveOccurred()) 166 goodExtension.URL = "good_extension.js" 167 168 badExtension, err := schema.NewExtension(map[string]interface{}{ 169 "id": "bad_extension", 170 "code": `gohan_register_handler("test_event", function foo(context) { 171 var a = 5; 172 console.log(b); 173 });`, 174 "path": ".*", 175 }) 176 Expect(err).ToNot(HaveOccurred()) 177 badExtension.URL = "bad_extension.js" 178 179 extensions := []*schema.Extension{goodExtension, badExtension} 180 env := otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 181 err = env.LoadExtensionsForPath(extensions, "test_path") 182 183 context := map[string]interface{}{ 184 "id": "test", 185 } 186 err = env.HandleEvent("test_event", context) 187 Expect(err).To(HaveOccurred()) 188 189 Expect(regexp.MatchString(`ReferenceError:\s'b'`, err.Error())).To(BeTrue()) 190 191 pattern := regexp.MustCompile(`at\s(?P<function>\w+)\s\((?P<file>.*?):(?P<line>\d+).*?\)`) 192 match := pattern.FindStringSubmatch(err.Error()) 193 Expect(len(match)).To(Equal(4)) 194 //FIXME(timorl): because of a throw bug in otto we cannot expect more meaningful errors 195 }) 196 }) 197 198 Context("When a nil value is passed", func() { 199 It("should be represented as null in the virtual machine", func() { 200 goodExtension, err := schema.NewExtension(map[string]interface{}{ 201 "id": "good_extension", 202 "code": `gohan_register_handler("test_event", function(context) { 203 if (context.nulo === null) { 204 context.respondo = "verdo" 205 } else { 206 context.respondo = "ne verdo" 207 } 208 });`, 209 "path": ".*", 210 }) 211 Expect(err).ToNot(HaveOccurred()) 212 goodExtension.URL = "good_extension.js" 213 214 extensions := []*schema.Extension{goodExtension} 215 env := otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 216 err = env.LoadExtensionsForPath(extensions, "test_path") 217 218 context := map[string]interface{}{ 219 "id": "test", 220 "nulo": nil, 221 } 222 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 223 Expect(context).To(HaveKeyWithValue("respondo", "verdo")) 224 }) 225 }) 226 }) 227 228 Describe("Using gohan_http builtin", func() { 229 Context("When the destination is reachable", func() { 230 It("Should return the contents", func() { 231 server := ghttp.NewServer() 232 server.AppendHandlers(ghttp.CombineHandlers( 233 ghttp.VerifyRequest("GET", "/contents"), 234 ghttp.RespondWith(200, "HELLO"), 235 )) 236 237 extension, err := schema.NewExtension(map[string]interface{}{ 238 "id": "test_extension", 239 "code": ` 240 gohan_register_handler("test_event", function(context){ 241 context.resp = gohan_http('GET', '` + server.URL() + `/contents', {}, {}); 242 });`, 243 "path": ".*", 244 }) 245 Expect(err).ToNot(HaveOccurred()) 246 extensions := []*schema.Extension{extension} 247 env := otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 248 Expect(env.LoadExtensionsForPath(extensions, "test_path")).To(Succeed()) 249 250 context := map[string]interface{}{ 251 "id": "test", 252 } 253 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 254 Expect(context).To(HaveKeyWithValue("resp", HaveKeyWithValue("status_code", "200"))) 255 Expect(context).To(HaveKeyWithValue("resp", HaveKeyWithValue("body", "HELLO"))) 256 server.Close() 257 }) 258 }) 259 260 Context("When the destination is not reachable", func() { 261 It("Should return the error", func() { 262 extension, err := schema.NewExtension(map[string]interface{}{ 263 "id": "test_extension", 264 "code": ` 265 gohan_register_handler("test_event", function(context){ 266 context.resp = gohan_http('GET', 'http://localhost:38000/contents', {}, {}); 267 });`, 268 "path": ".*", 269 }) 270 Expect(err).ToNot(HaveOccurred()) 271 extensions := []*schema.Extension{extension} 272 env := otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 273 Expect(env.LoadExtensionsForPath(extensions, "test_path")).To(Succeed()) 274 275 context := map[string]interface{}{ 276 "id": "test", 277 } 278 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 279 Expect(context).To(HaveKeyWithValue("resp", HaveKeyWithValue("status", "err"))) 280 Expect(context).To(HaveKeyWithValue("resp", HaveKey("error"))) 281 }) 282 }) 283 }) 284 285 Describe("Using gohan database manipulation builtins", func() { 286 var ( 287 adminAuth schema.Authorization 288 memberAuth schema.Authorization 289 auth schema.Authorization 290 context middleware.Context 291 schemaID string 292 path string 293 action string 294 currentSchema *schema.Schema 295 extensions []*schema.Extension 296 env extension.Environment 297 events map[string]string 298 299 network1 map[string]interface{} 300 network2 map[string]interface{} 301 subnet1 map[string]interface{} 302 ) 303 304 BeforeEach(func() { 305 adminAuth = schema.NewAuthorization(adminTenantID, "admin", adminTokenID, []string{"admin"}, nil) 306 memberAuth = schema.NewAuthorization(memberTenantID, "member", memberTokenID, []string{"_member_"}, nil) 307 auth = adminAuth 308 309 context = middleware.Context{} 310 311 events = map[string]string{} 312 313 network1 = map[string]interface{}{ 314 "id": "test1", 315 "name": "Rohan", 316 "description": "The proud horsemasters", 317 "tenant_id": adminTenantID, 318 "providor_networks": map[string]interface{}{}, 319 "route_targets": []interface{}{}, 320 "shared": false, 321 } 322 network2 = map[string]interface{}{ 323 "id": "test2", 324 "name": "Gondor", 325 "description": "Once glorious empire", 326 "tenant_id": adminTenantID, 327 "providor_networks": map[string]interface{}{}, 328 "route_targets": []interface{}{}, 329 "shared": false, 330 } 331 subnet1 = map[string]interface{}{ 332 "id": "test3", 333 "name": "Minas Tirith", 334 "tenant_id": adminTenantID, 335 "cidr": "10.10.0.0/16", 336 } 337 }) 338 339 JustBeforeEach(func() { 340 var ok bool 341 currentSchema, ok = manager.Schema(schemaID) 342 Expect(ok).To(BeTrue()) 343 344 path = currentSchema.GetPluralURL() 345 346 policy, role := manager.PolicyValidate(action, path, auth) 347 Expect(policy).NotTo(BeNil()) 348 context["policy"] = policy 349 context["role"] = role 350 context["tenant_id"] = auth.TenantID() 351 context["tenant_name"] = auth.TenantName() 352 context["auth_token"] = auth.AuthToken() 353 context["catalog"] = auth.Catalog() 354 context["auth"] = auth 355 context["identity_service"] = &middleware.FakeIdentity{} 356 357 env = otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 358 environmentManager.RegisterEnvironment(schemaID, env) 359 extensions = []*schema.Extension{} 360 for event, javascript := range events { 361 extension, err := schema.NewExtension(map[string]interface{}{ 362 "id": event + "_extension", 363 "code": `gohan_register_handler("` + event + `", function(context) {` + javascript + `});`, 364 "path": path, 365 }) 366 Expect(err).ToNot(HaveOccurred()) 367 extensions = append(extensions, extension) 368 } 369 Expect(env.LoadExtensionsForPath(extensions, path)).To(Succeed()) 370 }) 371 372 AfterEach(func() { 373 tx, err := testDB.Begin() 374 Expect(err).ToNot(HaveOccurred(), "Failed to create transaction.") 375 environmentManager.UnRegisterEnvironment(schemaID) 376 defer tx.Close() 377 for _, schema := range schema.GetManager().Schemas() { 378 if whitelist[schema.ID] { 379 continue 380 } 381 err = clearTable(tx, schema) 382 Expect(err).ToNot(HaveOccurred(), "Failed to clear table.") 383 } 384 err = tx.Commit() 385 Expect(err).ToNot(HaveOccurred(), "Failed to commite transaction.") 386 }) 387 388 Describe("Using gohan_db_* builtins", func() { 389 BeforeEach(func() { 390 schemaID = "network" 391 action = "read" 392 }) 393 394 Context("When given a transaction", func() { 395 It("Correctly handles CRUD operations", func() { 396 tx, err := testDB.Begin() 397 defer tx.Commit() 398 399 extension, err := schema.NewExtension(map[string]interface{}{ 400 "id": "test_extension", 401 "code": ` 402 gohan_register_handler("test_event", function(context){ 403 gohan_db_create(context.transaction, 404 'network', { 405 'id':'test1', 406 'name': 'name', 407 'description': 'description', 408 'providor_networks': {}, 409 'route_targets': [], 410 'shared': false, 411 'tenant_id': 'admin'}); 412 context.network = gohan_db_fetch(context.transaction, 'network', 'test1', 'admin'); 413 gohan_db_update(context.transaction, 414 'network', {'id':'test1', 'name': 'name_updated', 'tenant_id': 'admin'}); 415 context.networks = gohan_db_list(context.transaction, 'network', {}); 416 gohan_db_delete(context.transaction, 'network', 'test1'); 417 context.networks2 = gohan_db_list(context.transaction, 'network', {}); 418 });`, 419 "path": ".*", 420 }) 421 Expect(err).ToNot(HaveOccurred()) 422 extensions := []*schema.Extension{extension} 423 env := otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 424 env.LoadExtensionsForPath(extensions, "test_path") 425 426 context := map[string]interface{}{ 427 "id": "test", 428 "transaction": tx, 429 } 430 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 431 Expect(context["network"]).ToNot(BeNil()) 432 Expect(context["networks"]).ToNot(BeNil()) 433 }) 434 }) 435 436 Context("When given no transaction", func() { 437 It("Correctly handles CRUD operations", func() { 438 tx, err := testDB.Begin() 439 defer tx.Commit() 440 441 extension, err := schema.NewExtension(map[string]interface{}{ 442 "id": "test_extension", 443 "code": ` 444 gohan_register_handler("test_event", function(context){ 445 gohan_db_create(context.transaction, 446 'network', { 447 'id':'test1', 448 'name': 'name', 449 'description': 'description', 450 'providor_networks': {}, 451 'route_targets': [], 452 'shared': false, 453 'tenant_id': 'admin'}); 454 context.network = gohan_db_fetch(context.transaction, 'network', 'test1', 'admin'); 455 gohan_db_update(context.transaction, 456 'network', {'id':'test1', 'name': 'name_updated', 'tenant_id': 'admin'}); 457 context.networks = gohan_db_list(context.transaction, 'network', {}); 458 gohan_db_delete(context.transaction, 'network', 'test1'); 459 context.networks2 = gohan_db_list(context.transaction, 'network', {}); 460 });`, 461 "path": ".*", 462 }) 463 Expect(err).ToNot(HaveOccurred()) 464 extensions := []*schema.Extension{extension} 465 env := otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 466 env.LoadExtensionsForPath(extensions, "test_path") 467 468 context := map[string]interface{}{ 469 "id": "test", 470 "transaction": nil, 471 } 472 Expect(env.HandleEvent("test_event", context)).To(Succeed()) 473 Expect(context["network"]).ToNot(BeNil()) 474 Expect(context["networks"]).ToNot(BeNil()) 475 }) 476 }) 477 }) 478 479 Describe("Using chaining builtins", func() { 480 BeforeEach(func() { 481 schemaID = "network" 482 }) 483 484 Describe("Using gohan_model_list", func() { 485 var ( 486 tx transaction.Transaction 487 ) 488 489 BeforeEach(func() { 490 resource, err := manager.LoadResource(schemaID, network1) 491 Expect(err).NotTo(HaveOccurred()) 492 tx, err = testDB.Begin() 493 Expect(err).NotTo(HaveOccurred()) 494 defer tx.Close() 495 Expect(tx.Create(resource)).To(Succeed()) 496 Expect(tx.Commit()).To(Succeed()) 497 498 action = "read" 499 }) 500 501 Describe("When invoked correctly", func() { 502 Context("With transaction", func() { 503 BeforeEach(func() { 504 events["test"] = ` 505 context.networks = gohan_model_list(context, 'network', {});` 506 }) 507 508 It("Correctly lists elements", func() { 509 tx, err := testDB.Begin() 510 Expect(err).NotTo(HaveOccurred()) 511 defer tx.Close() 512 context["transaction"] = tx 513 514 Expect(env.HandleEvent("test", context)).To(Succeed()) 515 Expect(tx.Commit()).To(Succeed()) 516 Expect(context).To(HaveKeyWithValue("networks", ConsistOf(util.MatchAsJSON(network1)))) 517 }) 518 }) 519 520 Context("With a string filter", func() { 521 BeforeEach(func() { 522 events["test"] = ` 523 console.log(context) 524 context.networks = gohan_model_list(context, 'network', {'id': 'test1'});` 525 }) 526 527 It("Correctly lists elements", func() { 528 tx, err := testDB.Begin() 529 Expect(err).NotTo(HaveOccurred()) 530 defer tx.Close() 531 context["transaction"] = tx 532 Expect(env.HandleEvent("test", context)).To(Succeed()) 533 Expect(context).To(HaveKeyWithValue("networks", ConsistOf(util.MatchAsJSON(network1)))) 534 }) 535 }) 536 537 Context("With an array filter", func() { 538 BeforeEach(func() { 539 events["test"] = ` 540 context.networks = gohan_model_list(context, 'network', {'id': ['test1']});` 541 }) 542 543 It("Correctly lists elements", func() { 544 tx, err := testDB.Begin() 545 Expect(err).NotTo(HaveOccurred()) 546 defer tx.Close() 547 context["transaction"] = tx 548 Expect(env.HandleEvent("test", context)).To(Succeed()) 549 Expect(context).To(HaveKeyWithValue("networks", ConsistOf(util.MatchAsJSON(network1)))) 550 }) 551 }) 552 553 Context("With chained exception", func() { 554 BeforeEach(func() { 555 events["test"] = ` 556 context.networks = gohan_model_list(context, 'network', {});` 557 events["post_list_in_transaction"] = ` 558 throw new CustomException("Labori inteligente estas pli bona ol laboregi", 390);` 559 }) 560 561 It("Returns the proper error", func() { 562 tx, err := testDB.Begin() 563 Expect(err).NotTo(HaveOccurred()) 564 defer tx.Close() 565 context["transaction"] = tx 566 Expect(env.HandleEvent("test", context)).To(Succeed()) 567 Expect(context["exception"]).To(HaveKeyWithValue("message", ContainSubstring("Labori inteligente"))) 568 Expect(context["exception_message"]).To(ContainSubstring("Labori inteligente")) 569 }) 570 }) 571 572 Context("With internal resource manipulation error", func() { 573 BeforeEach(func() { 574 events["test"] = ` 575 context.networks = gohan_model_list(context, 'network', {});` 576 events["post_list_in_transaction"] = ` 577 delete context.response;` 578 }) 579 580 It("Returns the proper error", func() { 581 tx, err := testDB.Begin() 582 Expect(err).NotTo(HaveOccurred()) 583 defer tx.Close() 584 context["transaction"] = tx 585 err = env.HandleEvent("test", context) 586 Expect(err).To(MatchError(ContainSubstring("No response"))) 587 }) 588 }) 589 }) 590 591 Describe("When invoked incorrectly", func() { 592 Context("With wrong number of arguments", func() { 593 BeforeEach(func() { 594 events["test"] = ` 595 context.networks = gohan_model_list();` 596 }) 597 598 It("Returns the proper error", func() { 599 err := env.HandleEvent("test", context) 600 Expect(err).To(MatchError(ContainSubstring("arguments"))) 601 }) 602 }) 603 604 Context("With wrong schema ID", func() { 605 BeforeEach(func() { 606 events["test"] = ` 607 context.networks = gohan_model_list(context, 'netwerk', {});` 608 }) 609 610 It("Returns the proper error", func() { 611 err := env.HandleEvent("test", context) 612 Expect(err).To(MatchError(ContainSubstring("Unknown schema"))) 613 }) 614 }) 615 616 Context("With wrong filter", func() { 617 BeforeEach(func() { 618 events["test"] = ` 619 context.networks = gohan_model_list(context, 'network', {'id': context.policy});` 620 }) 621 622 It("Returns the proper error", func() { 623 err := env.HandleEvent("test", context) 624 Expect(err).To(MatchError(ContainSubstring("not a string"))) 625 }) 626 }) 627 628 Context("With wrong filter but array", func() { 629 BeforeEach(func() { 630 events["test"] = ` 631 context.networks = gohan_model_list(context, 'network', {'id': [context.policy]});` 632 }) 633 634 It("Returns the proper error", func() { 635 err := env.HandleEvent("test", context) 636 Expect(err).To(MatchError(ContainSubstring("not a string"))) 637 }) 638 }) 639 }) 640 }) 641 642 Describe("Using gohan_model_fetch", func() { 643 var ( 644 tx transaction.Transaction 645 ) 646 647 BeforeEach(func() { 648 resource, err := manager.LoadResource(schemaID, network1) 649 Expect(err).NotTo(HaveOccurred()) 650 tx, err = testDB.Begin() 651 Expect(err).NotTo(HaveOccurred()) 652 defer tx.Close() 653 Expect(tx.Create(resource)).To(Succeed()) 654 Expect(tx.Commit()).To(Succeed()) 655 656 action = "read" 657 }) 658 659 Describe("When invoked correctly", func() { 660 Context("With transaction", func() { 661 BeforeEach(func() { 662 events["test"] = ` 663 context.network = gohan_model_fetch(context, 'network', 'test1', null); 664 ` 665 }) 666 667 It("Correctly fetches the element", func() { 668 tx, err := testDB.Begin() 669 Expect(err).NotTo(HaveOccurred()) 670 defer tx.Close() 671 context["transaction"] = tx 672 673 Expect(env.HandleEvent("test", context)).To(Succeed()) 674 Expect(tx.Commit()).To(Succeed()) 675 By(fmt.Sprintf("%v", context)) 676 resultRaw, ok := context["network"] 677 Expect(ok).To(BeTrue()) 678 _, ok = resultRaw.(map[string]interface{}) 679 Expect(ok).To(BeTrue()) 680 }) 681 }) 682 683 Context("Asking for a nonexistent resource", func() { 684 BeforeEach(func() { 685 events["test"] = ` 686 context.network = gohan_model_fetch(context, 'network', 'neEstas', null);` 687 }) 688 689 It("Returns the not found error", func() { 690 tx, err := testDB.Begin() 691 Expect(err).NotTo(HaveOccurred()) 692 defer tx.Close() 693 context["transaction"] = tx 694 Expect(env.HandleEvent("test", context)).To(Succeed()) 695 Expect(context["exception"]).To(HaveKeyWithValue("problem", int(resources.NotFound))) 696 Expect(context["exception_message"]).To(ContainSubstring("ResourceException")) 697 }) 698 }) 699 700 Context("With chained exception", func() { 701 BeforeEach(func() { 702 events["test"] = ` 703 context.network = gohan_model_fetch(context, 'network', 'test1', null);` 704 events["post_show_in_transaction"] = ` 705 throw new CustomException("Labori inteligente estas pli bona ol laboregi", 390);` 706 }) 707 708 It("Returns the proper error", func() { 709 tx, err := testDB.Begin() 710 Expect(err).NotTo(HaveOccurred()) 711 defer tx.Close() 712 context["transaction"] = tx 713 Expect(env.HandleEvent("test", context)).To(Succeed()) 714 Expect(context["exception"]).To(HaveKeyWithValue("message", ContainSubstring("Labori inteligente"))) 715 Expect(context["exception_message"]).To(ContainSubstring("Labori inteligente")) 716 }) 717 }) 718 719 Context("With internal resource manipulation error", func() { 720 BeforeEach(func() { 721 events["test"] = ` 722 context.network = gohan_model_fetch(context, 'network', 'test1', null);` 723 events["post_show_in_transaction"] = ` 724 delete context.response;` 725 }) 726 727 It("Returns the proper error", func() { 728 tx, err := testDB.Begin() 729 Expect(err).NotTo(HaveOccurred()) 730 defer tx.Close() 731 context["transaction"] = tx 732 err = env.HandleEvent("test", context) 733 Expect(err).To(MatchError(ContainSubstring("No response"))) 734 }) 735 }) 736 }) 737 738 Describe("When invoked incorrectly", func() { 739 Context("With wrong number of arguments", func() { 740 BeforeEach(func() { 741 events["test"] = ` 742 context.network = gohan_model_fetch();` 743 }) 744 745 It("Returns the proper error", func() { 746 err := env.HandleEvent("test", context) 747 Expect(err).To(MatchError(ContainSubstring("arguments"))) 748 }) 749 }) 750 751 Context("With wrong schema ID", func() { 752 BeforeEach(func() { 753 events["test"] = ` 754 context.network = gohan_model_fetch(context, 'netwerk', 'test1', null);` 755 }) 756 757 It("Returns the proper error", func() { 758 err := env.HandleEvent("test", context) 759 Expect(err).To(MatchError(ContainSubstring("Unknown schema"))) 760 }) 761 }) 762 763 }) 764 }) 765 766 Describe("Using gohan_model_create", func() { 767 var ( 768 tx transaction.Transaction 769 ) 770 771 BeforeEach(func() { 772 resource, err := manager.LoadResource(schemaID, network1) 773 Expect(err).NotTo(HaveOccurred()) 774 tx, err = testDB.Begin() 775 Expect(err).NotTo(HaveOccurred()) 776 defer tx.Close() 777 Expect(tx.Create(resource)).To(Succeed()) 778 Expect(tx.Commit()).To(Succeed()) 779 780 action = "create" 781 }) 782 783 Describe("When invoked correctly", func() { 784 Context("With transaction", func() { 785 BeforeEach(func() { 786 script := ` 787 context.network = gohan_model_create(context, 'network', {'%v': '%v', '%v': '%v', '%v': '%v', '%v': '%v', 'route_targets': [], 'providor_networks': {}, 'shared': false});` 788 events["test"] = fmt.Sprintf(script, "id", network2["id"], "name", network2["name"], "description", network2["description"], "tenant_id", network2["tenant_id"]) 789 }) 790 791 It("Correctly creates the element", func() { 792 tx, err := testDB.Begin() 793 Expect(err).NotTo(HaveOccurred()) 794 defer tx.Close() 795 context["transaction"] = tx 796 Expect(env.HandleEvent("test", context)).To(Succeed()) 797 Expect(tx.Commit()).To(Succeed()) 798 for key, value := range network2 { 799 Expect(context).To(HaveKeyWithValue("network", HaveKeyWithValue(key, value))) 800 } 801 }) 802 }) 803 804 Context("With chained exception", func() { 805 BeforeEach(func() { 806 script := ` 807 context.network = gohan_model_create(context, 'network', {'%v': '%v', '%v': '%v', '%v': '%v', '%v': '%v', 'route_targets': [], 'providor_networks': {}, 'shared': false});` 808 events["test"] = fmt.Sprintf(script, "id", network2["id"], "name", network2["name"], "description", network2["description"], "tenant_id", network2["tenant_id"]) 809 events["post_create_in_transaction"] = ` 810 throw new CustomException("Labori inteligente estas pli bona ol laboregi", 390);` 811 }) 812 813 It("Returns the proper error", func() { 814 tx, err := testDB.Begin() 815 Expect(err).NotTo(HaveOccurred()) 816 defer tx.Close() 817 context["transaction"] = tx 818 Expect(env.HandleEvent("test", context)).To(Succeed()) 819 Expect(context["exception"]).To(HaveKeyWithValue("message", ContainSubstring("Labori inteligente"))) 820 Expect(context["exception_message"]).To(ContainSubstring("Labori inteligente")) 821 }) 822 }) 823 824 Context("With internal resource manipulation error", func() { 825 BeforeEach(func() { 826 script := ` 827 context.network = gohan_model_create(context, 'network', {'%v': '%v', '%v': '%v', '%v': '%v', '%v': '%v', 'route_targets': [], 'providor_networks': {}, 'shared': false});` 828 events["test"] = fmt.Sprintf(script, "id", network2["id"], "name", network2["name"], "description", network2["description"], "tenant_id", network2["tenant_id"]) 829 events["post_create_in_transaction"] = ` 830 delete context.response;` 831 }) 832 833 It("Returns the proper error", func() { 834 tx, err := testDB.Begin() 835 Expect(err).NotTo(HaveOccurred()) 836 defer tx.Close() 837 context["transaction"] = tx 838 err = env.HandleEvent("test", context) 839 Expect(err).To(MatchError(ContainSubstring("No response"))) 840 }) 841 }) 842 }) 843 844 Describe("When invoked incorrectly", func() { 845 Context("With wrong number of arguments", func() { 846 BeforeEach(func() { 847 events["test"] = ` 848 context.network = gohan_model_create();` 849 }) 850 851 It("Returns the proper error", func() { 852 err := env.HandleEvent("test", context) 853 Expect(err).To(MatchError(ContainSubstring("arguments"))) 854 }) 855 }) 856 857 Context("With wrong schema ID", func() { 858 BeforeEach(func() { 859 script := ` 860 context.network = gohan_model_create(context, 'netwerk', {'%v': '%v', '%v': '%v', '%v': '%v', '%v': '%v'});` 861 events["test"] = fmt.Sprintf(script, "id", network2["id"], "name", network2["name"], "description", network2["description"], "tenant_id", network2["tenant_id"]) 862 }) 863 864 It("Returns the proper error", func() { 865 err := env.HandleEvent("test", context) 866 Expect(err).To(MatchError(ContainSubstring("Unknown schema"))) 867 }) 868 }) 869 870 Context("With wrong resource to create", func() { 871 BeforeEach(func() { 872 events["test"] = ` 873 context.network = gohan_model_create(context, 'network', 'Ne estas reto');` 874 }) 875 876 It("Returns the proper error", func() { 877 err := env.HandleEvent("test", context) 878 Expect(err).To(MatchError(ContainSubstring("Not a dictionary"))) 879 }) 880 }) 881 }) 882 }) 883 884 Describe("Using gohan_model_update", func() { 885 var ( 886 tx transaction.Transaction 887 ) 888 889 BeforeEach(func() { 890 resource, err := manager.LoadResource(schemaID, network1) 891 Expect(err).NotTo(HaveOccurred()) 892 tx, err = testDB.Begin() 893 Expect(err).NotTo(HaveOccurred()) 894 defer tx.Close() 895 Expect(tx.Create(resource)).To(Succeed()) 896 Expect(tx.Commit()).To(Succeed()) 897 898 action = "update" 899 }) 900 901 Describe("When invoked correctly", func() { 902 Context("With transaction", func() { 903 BeforeEach(func() { 904 script := ` 905 context.network = gohan_model_update(context, 'network', 'test1', {'%v': '%v'}, null);` 906 events["test"] = fmt.Sprintf(script, "name", network2["name"]) 907 }) 908 909 It("Correctly updates the element", func() { 910 tx, err := testDB.Begin() 911 Expect(err).NotTo(HaveOccurred()) 912 defer tx.Close() 913 context["transaction"] = tx 914 915 Expect(env.HandleEvent("test", context)).To(Succeed()) 916 Expect(tx.Commit()).To(Succeed()) 917 Expect(context).To(HaveKeyWithValue("network", HaveKeyWithValue("name", network2["name"]))) 918 }) 919 }) 920 921 Context("With chained exception", func() { 922 BeforeEach(func() { 923 script := ` 924 context.network = gohan_model_update(context, 'network', 'test1', {'%v': '%v'}, null);` 925 events["test"] = fmt.Sprintf(script, "name", network2["name"]) 926 events["post_update_in_transaction"] = ` 927 throw new CustomException("Labori inteligente estas pli bona ol laboregi", 390);` 928 }) 929 930 It("Returns the proper error", func() { 931 tx, err := testDB.Begin() 932 Expect(err).NotTo(HaveOccurred()) 933 defer tx.Close() 934 context["transaction"] = tx 935 936 Expect(env.HandleEvent("test", context)).To(Succeed()) 937 Expect(context["exception"]).To(HaveKeyWithValue("message", ContainSubstring("Labori inteligente"))) 938 Expect(context["exception_message"]).To(ContainSubstring("Labori inteligente")) 939 }) 940 }) 941 942 Context("With internal resource manipulation error", func() { 943 BeforeEach(func() { 944 script := ` 945 context.network = gohan_model_update(context, 'network', 'test1', {'%v': '%v'}, null);` 946 events["test"] = fmt.Sprintf(script, "name", network2["name"]) 947 events["post_update_in_transaction"] = ` 948 delete context.response;` 949 }) 950 951 It("Returns the proper error", func() { 952 tx, err := testDB.Begin() 953 Expect(err).NotTo(HaveOccurred()) 954 defer tx.Close() 955 context["transaction"] = tx 956 957 err = env.HandleEvent("test", context) 958 Expect(err).To(MatchError(ContainSubstring("No response"))) 959 }) 960 }) 961 }) 962 963 Describe("When invoked incorrectly", func() { 964 Context("With wrong number of arguments", func() { 965 BeforeEach(func() { 966 events["test"] = ` 967 context.network = gohan_model_update();` 968 }) 969 970 It("Returns the proper error", func() { 971 err := env.HandleEvent("test", context) 972 Expect(err).To(MatchError(ContainSubstring("arguments"))) 973 }) 974 }) 975 976 Context("With wrong schema ID", func() { 977 BeforeEach(func() { 978 script := ` 979 context.network = gohan_model_update(context, 'netwerk', 'test1', {'%v': '%v'}, null);` 980 events["test"] = fmt.Sprintf(script, "name", network2["name"]) 981 }) 982 983 It("Returns the proper error", func() { 984 err := env.HandleEvent("test", context) 985 Expect(err).To(MatchError(ContainSubstring("Unknown schema"))) 986 }) 987 }) 988 989 Context("With wrong update data map", func() { 990 BeforeEach(func() { 991 events["test"] = ` 992 context.network = gohan_model_update(context, 'network', 'test1', 'Ne estas reto', null);` 993 }) 994 995 It("Returns the proper error", func() { 996 tx, err := testDB.Begin() 997 Expect(err).NotTo(HaveOccurred()) 998 defer tx.Close() 999 context["transaction"] = tx 1000 1001 err = env.HandleEvent("test", context) 1002 Expect(err).To(MatchError(ContainSubstring("Not a dictionary"))) 1003 }) 1004 }) 1005 }) 1006 }) 1007 1008 Describe("Using gohan_model_delete", func() { 1009 var ( 1010 tx transaction.Transaction 1011 ) 1012 1013 BeforeEach(func() { 1014 resource, err := manager.LoadResource(schemaID, network1) 1015 Expect(err).NotTo(HaveOccurred()) 1016 tx, err = testDB.Begin() 1017 Expect(err).NotTo(HaveOccurred()) 1018 defer tx.Close() 1019 Expect(tx.Create(resource)).To(Succeed()) 1020 Expect(tx.Commit()).To(Succeed()) 1021 1022 action = "delete" 1023 }) 1024 1025 Describe("When invoked correctly", func() { 1026 Context("With transaction", func() { 1027 BeforeEach(func() { 1028 events["test"] = ` 1029 context.network = gohan_model_delete(context, 'network', 'test1');` 1030 }) 1031 1032 It("Correctly deletes the element", func() { 1033 tx, err := testDB.Begin() 1034 Expect(err).NotTo(HaveOccurred()) 1035 defer tx.Close() 1036 context["transaction"] = tx 1037 1038 Expect(env.HandleEvent("test", context)).To(Succeed()) 1039 Expect(tx.Commit()).To(Succeed()) 1040 }) 1041 }) 1042 1043 Context("With chained exception", func() { 1044 BeforeEach(func() { 1045 events["test"] = ` 1046 context.network = gohan_model_delete(context, 'network', 'test1');` 1047 events["post_delete_in_transaction"] = ` 1048 throw new CustomException("Labori inteligente estas pli bona ol laboregi", 390);` 1049 }) 1050 1051 It("Returns the proper error", func() { 1052 tx, err := testDB.Begin() 1053 Expect(err).NotTo(HaveOccurred()) 1054 defer tx.Close() 1055 context["transaction"] = tx 1056 1057 Expect(env.HandleEvent("test", context)).To(Succeed()) 1058 Expect(context["exception"]).To(HaveKeyWithValue("message", ContainSubstring("Labori inteligente"))) 1059 Expect(context["exception_message"]).To(ContainSubstring("Labori inteligente")) 1060 }) 1061 }) 1062 }) 1063 1064 Describe("When invoked incorrectly", func() { 1065 Context("With wrong number of arguments", func() { 1066 BeforeEach(func() { 1067 events["test"] = ` 1068 context.network = gohan_model_delete();` 1069 }) 1070 1071 It("Returns the proper error", func() { 1072 err := env.HandleEvent("test", context) 1073 Expect(err).To(MatchError(ContainSubstring("arguments"))) 1074 }) 1075 }) 1076 1077 Context("With wrong schema ID", func() { 1078 BeforeEach(func() { 1079 events["test"] = ` 1080 context.network = gohan_model_delete(context, 'netwerk', 'test1');` 1081 }) 1082 1083 It("Returns the proper error", func() { 1084 err := env.HandleEvent("test", context) 1085 Expect(err).To(MatchError(ContainSubstring("Unknown schema"))) 1086 }) 1087 }) 1088 }) 1089 }) 1090 1091 Describe("Actually chaining them", func() { 1092 var ( 1093 tx transaction.Transaction 1094 createNetworkContext middleware.Context 1095 createSubnetContext middleware.Context 1096 readSubnetContext middleware.Context 1097 subnetEnv extension.Environment 1098 subnetEvents map[string]string 1099 ) 1100 1101 BeforeEach(func() { 1102 1103 resource, err := manager.LoadResource(schemaID, network1) 1104 Expect(err).NotTo(HaveOccurred()) 1105 tx, err = testDB.Begin() 1106 Expect(err).NotTo(HaveOccurred()) 1107 defer tx.Close() 1108 Expect(tx.Create(resource)).To(Succeed()) 1109 Expect(tx.Commit()).To(Succeed()) 1110 1111 action = "read" 1112 1113 createNetworkContext = middleware.Context{} 1114 createSubnetContext = middleware.Context{} 1115 readSubnetContext = middleware.Context{} 1116 subnetEvents = map[string]string{} 1117 }) 1118 1119 JustBeforeEach(func() { 1120 curAction := "create" 1121 curSchemaID := "subnet" 1122 curSchema, ok := manager.Schema(curSchemaID) 1123 Expect(ok).To(BeTrue()) 1124 1125 curPath := curSchema.GetPluralURL() 1126 1127 curPolicy, curRole := manager.PolicyValidate(curAction, curPath, auth) 1128 Expect(curPolicy).NotTo(BeNil()) 1129 createSubnetContext["policy"] = curPolicy 1130 createSubnetContext["role"] = curRole 1131 createSubnetContext["tenant_id"] = auth.TenantID() 1132 createSubnetContext["tenant_name"] = auth.TenantName() 1133 createSubnetContext["auth_token"] = auth.AuthToken() 1134 createSubnetContext["catalog"] = auth.Catalog() 1135 createSubnetContext["auth"] = auth 1136 createSubnetContext["identity_service"] = &middleware.FakeIdentity{} 1137 1138 curAction = "create" 1139 curPolicy, curRole = manager.PolicyValidate(curAction, curPath, auth) 1140 Expect(curPolicy).NotTo(BeNil()) 1141 readSubnetContext["policy"] = curPolicy 1142 readSubnetContext["role"] = curRole 1143 readSubnetContext["tenant_id"] = auth.TenantID() 1144 readSubnetContext["tenant_name"] = auth.TenantName() 1145 readSubnetContext["auth_token"] = auth.AuthToken() 1146 readSubnetContext["catalog"] = auth.Catalog() 1147 readSubnetContext["auth"] = auth 1148 readSubnetContext["identity_service"] = &middleware.FakeIdentity{} 1149 1150 subnetEnv = otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 1151 environmentManager.RegisterEnvironment(curSchemaID, subnetEnv) 1152 curExtensions := []*schema.Extension{} 1153 for event, javascript := range subnetEvents { 1154 extension, err := schema.NewExtension(map[string]interface{}{ 1155 "id": event + "_extension", 1156 "code": `gohan_register_handler("` + event + `", function(context) {` + javascript + `});`, 1157 "path": curPath, 1158 }) 1159 Expect(err).ToNot(HaveOccurred()) 1160 curExtensions = append(curExtensions, extension) 1161 } 1162 Expect(subnetEnv.LoadExtensionsForPath(curExtensions, curPath)).To(Succeed()) 1163 1164 curAction = "create" 1165 curSchemaID = "network" 1166 curSchema, ok = manager.Schema(curSchemaID) 1167 Expect(ok).To(BeTrue()) 1168 1169 curPath = curSchema.GetPluralURL() 1170 1171 curPolicy, curRole = manager.PolicyValidate(curAction, curPath, auth) 1172 Expect(curPolicy).NotTo(BeNil()) 1173 createNetworkContext["policy"] = curPolicy 1174 createNetworkContext["role"] = curRole 1175 createNetworkContext["tenant_id"] = auth.TenantID() 1176 createNetworkContext["tenant_name"] = auth.TenantName() 1177 createNetworkContext["auth_token"] = auth.AuthToken() 1178 createNetworkContext["catalog"] = auth.Catalog() 1179 createNetworkContext["auth"] = auth 1180 createNetworkContext["identity_service"] = &middleware.FakeIdentity{} 1181 }) 1182 1183 Describe("When being chained", func() { 1184 Context("Without exceptions", func() { 1185 BeforeEach(func() { 1186 script := ` 1187 context.network = gohan_model_create(context, 1188 'network', {'%v': '%v', '%v': '%v', '%v': '%v', '%v': '%v', 1189 'route_targets': [], 'providor_networks': {}, 'shared': false});` 1190 events["test"] = fmt.Sprintf(script, "id", 1191 network2["id"], "name", network2["name"], 1192 "description", network2["description"], "tenant_id", network2["tenant_id"]) 1193 script = ` 1194 console.log("model create"); 1195 gohan_model_create( 1196 { 1197 transaction: context.transaction, 1198 policy: context.policy, 1199 }, 1200 'subnet', 1201 {'%v': '%v', '%v': '%v', '%v': '%v', '%v': '%v', 1202 'network_id': context.response.network.id, 'description': "test"});` 1203 events["post_create_in_transaction"] = fmt.Sprintf(script, "id", subnet1["id"], "name", subnet1["name"], "tenant_id", subnet1["tenant_id"], "cidr", subnet1["cidr"]) 1204 subnetEvents["test_subnet"] = ` 1205 context.subnet = gohan_model_fetch(context, 'subnet', 'test3', null); 1206 ` 1207 }) 1208 1209 It("Correctly handles chaining", func() { 1210 tx, err := testDB.Begin() 1211 Expect(err).NotTo(HaveOccurred()) 1212 createNetworkContext["transaction"] = tx 1213 By("Creating the network") 1214 Expect(env.HandleEvent("test", createNetworkContext)).To(Succeed()) 1215 tx.Commit() 1216 tx.Close() 1217 By("network created") 1218 for key, value := range network2 { 1219 Expect(createNetworkContext).To(HaveKeyWithValue("network", HaveKeyWithValue(key, value))) 1220 } 1221 1222 tx, err = testDB.Begin() 1223 Expect(err).NotTo(HaveOccurred()) 1224 readSubnetContext["transaction"] = tx 1225 1226 By("Also creating a default subnet for it") 1227 Expect(subnetEnv.HandleEvent("test_subnet", readSubnetContext)).To(Succeed()) 1228 tx.Close() 1229 for key, value := range subnet1 { 1230 Expect(readSubnetContext).To(HaveKey("subnet")) 1231 Expect(readSubnetContext).To(HaveKeyWithValue("subnet", HaveKeyWithValue(key, value))) 1232 } 1233 Expect(readSubnetContext).To(HaveKeyWithValue("subnet", HaveKey("description"))) 1234 }) 1235 }) 1236 1237 Context("With an exception", func() { 1238 BeforeEach(func() { 1239 script := ` 1240 context.network = gohan_model_create(context, 'network', {'%v': '%v', '%v': '%v', '%v': '%v', 'route_targets': [], 'providor_networks': {}, 'shared': false, 'description': ""});` 1241 1242 events["test"] = fmt.Sprintf(script, "id", network2["id"], "name", network2["name"], "tenant_id", network2["tenant_id"]) 1243 script = ` 1244 gohan_model_create(context, 1245 'subnet', {'%v': '%v', '%v': '%v', '%v': '%v', '%v': '%v', 'network_id': context.response.id});` 1246 events["post_create_in_transaction"] = fmt.Sprintf(script, "id", subnet1["id"], "name", subnet1["name"], "tenant_id", subnet1["tenant_id"], "cidr", subnet1["cidr"]) 1247 subnetEvents["pre_create_in_transaction"] = ` 1248 throw new CustomException("Minas Tirith has fallen!", 390);` 1249 }) 1250 1251 It("Returns the proper error", func() { 1252 tx, err := testDB.Begin() 1253 Expect(err).NotTo(HaveOccurred()) 1254 defer tx.Close() 1255 createNetworkContext["transaction"] = tx 1256 1257 Expect(env.HandleEvent("test", createNetworkContext)).To(Succeed()) 1258 Expect(createNetworkContext["exception"]).To(HaveKeyWithValue("message", ContainSubstring("Minas Tirith has fallen!"))) 1259 Expect(createNetworkContext["exception_message"]).To(ContainSubstring("Minas Tirith has fallen!")) 1260 }) 1261 }) 1262 }) 1263 }) 1264 }) 1265 }) 1266 var _ = Describe("Concurrency race", func() { 1267 var ( 1268 env *otto.Environment 1269 ) 1270 channel := make(chan string) 1271 Context("Given environment", func() { 1272 BeforeEach(func() { 1273 env = otto.NewEnvironment(testDB, &middleware.FakeIdentity{}) 1274 env.SetUp() 1275 vm := env.VM 1276 builtins := map[string]interface{}{ 1277 "test_consume": func(call ottopkg.FunctionCall) ottopkg.Value { 1278 result := <-channel 1279 ottoResult, _ := vm.ToValue(result) 1280 return ottoResult 1281 }, 1282 "test_produce": func(call ottopkg.FunctionCall) ottopkg.Value { 1283 ottoProduct := otto.ConvertOttoToGo(call.Argument(0)) 1284 product := otto.ConvertOttoToGo(ottoProduct).(string) 1285 channel <- product 1286 return ottopkg.NullValue() 1287 }, 1288 } 1289 for name, object := range builtins { 1290 vm.Set(name, object) 1291 } 1292 1293 Expect(env.Load("<race_test>", ` 1294 var produce = function() { 1295 for (var i = 0; i < 10; i++) { 1296 console.log("producing:", i); 1297 test_produce(i.toString()); 1298 } 1299 }; 1300 1301 var consume = function() { 1302 for (var i = 0; i < 10; i++) { 1303 var result = test_consume(); 1304 console.log("consumed:", result); 1305 } 1306 }`)).To(BeNil()) 1307 environmentManager.RegisterEnvironment("test_race", env) 1308 }) 1309 1310 It("Should work", func() { 1311 var consumerError = make(chan error) 1312 var producerError = make(chan error) 1313 1314 go func() { 1315 testEnv, _ := environmentManager.GetEnvironment("test_race") 1316 ottoEnv := testEnv.(*otto.Environment) 1317 _, err := ottoEnv.VM.Call("consume", nil) 1318 consumerError <- err 1319 }() 1320 1321 go func() { 1322 testEnv, _ := environmentManager.GetEnvironment("test_race") 1323 ottoEnv := testEnv.(*otto.Environment) 1324 _, err := ottoEnv.VM.Call("produce", nil) 1325 producerError <- err 1326 }() 1327 1328 select { 1329 case err := <-consumerError: 1330 Expect(err).To(BeNil()) 1331 case <-time.After(1 * time.Second): 1332 Fail("Timeout when waiting for consumer") 1333 } 1334 select { 1335 case err := <-producerError: 1336 Expect(err).To(BeNil()) 1337 case <-time.After(1 * time.Second): 1338 Fail("Timeout when waiting for producer") 1339 } 1340 }) 1341 }) 1342 }) 1343 })