capability-test.c++ (43281B)
1 // Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors 2 // Licensed under the MIT License: 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 #include "schema.capnp.h" 23 24 #ifdef CAPNP_CAPABILITY_H_INCLUDED 25 #error "schema.capnp should not depend on capability.h, because it contains no interfaces." 26 #endif 27 28 #include <capnp/test.capnp.h> 29 30 #ifndef CAPNP_CAPABILITY_H_INCLUDED 31 #error "test.capnp did not include capability.h." 32 #endif 33 34 #include "capability.h" 35 #include "test-util.h" 36 #include <kj/debug.h> 37 #include <kj/compat/gtest.h> 38 39 namespace capnp { 40 namespace _ { 41 namespace { 42 43 TEST(Capability, Basic) { 44 kj::EventLoop loop; 45 kj::WaitScope waitScope(loop); 46 47 int callCount = 0; 48 test::TestInterface::Client client(kj::heap<TestInterfaceImpl>(callCount)); 49 50 auto request1 = client.fooRequest(); 51 request1.setI(123); 52 request1.setJ(true); 53 auto promise1 = request1.send(); 54 55 auto request2 = client.bazRequest(); 56 initTestMessage(request2.initS()); 57 auto promise2 = request2.send(); 58 59 bool barFailed = false; 60 auto request3 = client.barRequest(); 61 auto promise3 = request3.send().then( 62 [](Response<test::TestInterface::BarResults>&& response) { 63 ADD_FAILURE() << "Expected bar() call to fail."; 64 }, [&](kj::Exception&& e) { 65 EXPECT_EQ(kj::Exception::Type::UNIMPLEMENTED, e.getType()); 66 barFailed = true; 67 }); 68 69 EXPECT_EQ(0, callCount); 70 71 auto response1 = promise1.wait(waitScope); 72 73 EXPECT_EQ("foo", response1.getX()); 74 75 auto response2 = promise2.wait(waitScope); 76 77 promise3.wait(waitScope); 78 79 EXPECT_EQ(2, callCount); 80 EXPECT_TRUE(barFailed); 81 } 82 83 TEST(Capability, CapabilityList) { 84 kj::EventLoop loop; 85 kj::WaitScope waitScope(loop); 86 87 MallocMessageBuilder builder; 88 auto root = builder.initRoot<test::TestListOfAny>(); 89 auto initCapList = root.initCapList(2); 90 91 int callCount0 = 0; 92 int callCount1 = 0; 93 initCapList.set(0, kj::heap<TestInterfaceImpl>(callCount0)); 94 initCapList.set(1, kj::heap<TestInterfaceImpl>(callCount1)); 95 96 auto capList = root.getCapList(); 97 auto cap0 = capList[0].castAs<test::TestInterface>(); 98 auto cap1 = capList[1].castAs<test::TestInterface>(); 99 100 EXPECT_EQ(2u, root.getCapList().size()); 101 102 auto request0 = cap0.fooRequest(); 103 request0.setI(123); 104 request0.setJ(true); 105 EXPECT_EQ("foo", request0.send().wait(waitScope).getX()); 106 107 auto request1 = cap1.fooRequest(); 108 request1.setI(123); 109 request1.setJ(true); 110 EXPECT_EQ("foo", request1.send().wait(waitScope).getX()); 111 112 EXPECT_EQ(1, callCount0); 113 EXPECT_EQ(1, callCount1); 114 } 115 116 TEST(Capability, Inheritance) { 117 kj::EventLoop loop; 118 kj::WaitScope waitScope(loop); 119 120 int callCount = 0; 121 test::TestExtends::Client client1(kj::heap<TestExtendsImpl>(callCount)); 122 test::TestInterface::Client client2 = client1; 123 auto client = client2.castAs<test::TestExtends>(); 124 125 auto request1 = client.fooRequest(); 126 request1.setI(321); 127 auto promise1 = request1.send(); 128 129 auto request2 = client.graultRequest(); 130 auto promise2 = request2.send(); 131 132 EXPECT_EQ(0, callCount); 133 134 auto response2 = promise2.wait(waitScope); 135 136 checkTestMessage(response2); 137 138 auto response1 = promise1.wait(waitScope); 139 140 EXPECT_EQ("bar", response1.getX()); 141 142 EXPECT_EQ(2, callCount); 143 } 144 145 TEST(Capability, Pipelining) { 146 kj::EventLoop loop; 147 kj::WaitScope waitScope(loop); 148 149 int callCount = 0; 150 int chainedCallCount = 0; 151 test::TestPipeline::Client client(kj::heap<TestPipelineImpl>(callCount)); 152 153 auto request = client.getCapRequest(); 154 request.setN(234); 155 request.setInCap(test::TestInterface::Client(kj::heap<TestInterfaceImpl>(chainedCallCount))); 156 157 auto promise = request.send(); 158 159 auto pipelineRequest = promise.getOutBox().getCap().fooRequest(); 160 pipelineRequest.setI(321); 161 auto pipelinePromise = pipelineRequest.send(); 162 163 auto pipelineRequest2 = promise.getOutBox().getCap().castAs<test::TestExtends>().graultRequest(); 164 auto pipelinePromise2 = pipelineRequest2.send(); 165 166 promise = nullptr; // Just to be annoying, drop the original promise. 167 168 EXPECT_EQ(0, callCount); 169 EXPECT_EQ(0, chainedCallCount); 170 171 auto response = pipelinePromise.wait(waitScope); 172 EXPECT_EQ("bar", response.getX()); 173 174 auto response2 = pipelinePromise2.wait(waitScope); 175 checkTestMessage(response2); 176 177 EXPECT_EQ(3, callCount); 178 EXPECT_EQ(1, chainedCallCount); 179 } 180 181 KJ_TEST("use pipeline after dropping response") { 182 kj::EventLoop loop; 183 kj::WaitScope waitScope(loop); 184 185 int callCount = 0; 186 int chainedCallCount = 0; 187 test::TestPipeline::Client client(kj::heap<TestPipelineImpl>(callCount)); 188 189 auto request = client.getCapRequest(); 190 request.setN(234); 191 request.setInCap(test::TestInterface::Client(kj::heap<TestInterfaceImpl>(chainedCallCount))); 192 193 auto promise = request.send(); 194 test::TestPipeline::GetCapResults::Pipeline pipeline = kj::mv(promise); 195 196 { 197 auto response = promise.wait(waitScope); 198 KJ_EXPECT(response.getS() == "bar"); 199 } 200 201 auto pipelineRequest = pipeline.getOutBox().getCap().fooRequest(); 202 pipelineRequest.setI(321); 203 auto pipelinePromise = pipelineRequest.send(); 204 205 auto pipelineRequest2 = pipeline.getOutBox().getCap().castAs<test::TestExtends>().graultRequest(); 206 auto pipelinePromise2 = pipelineRequest2.send(); 207 208 auto response = pipelinePromise.wait(waitScope); 209 EXPECT_EQ("bar", response.getX()); 210 211 auto response2 = pipelinePromise2.wait(waitScope); 212 checkTestMessage(response2); 213 214 EXPECT_EQ(3, callCount); 215 EXPECT_EQ(1, chainedCallCount); 216 } 217 218 KJ_TEST("context.setPipeline") { 219 kj::EventLoop loop; 220 kj::WaitScope waitScope(loop); 221 222 int callCount = 0; 223 test::TestPipeline::Client client(kj::heap<TestPipelineImpl>(callCount)); 224 225 auto promise = client.getCapPipelineOnlyRequest().send(); 226 227 auto pipelineRequest = promise.getOutBox().getCap().fooRequest(); 228 pipelineRequest.setI(321); 229 auto pipelinePromise = pipelineRequest.send(); 230 231 auto pipelineRequest2 = promise.getOutBox().getCap().castAs<test::TestExtends>().graultRequest(); 232 auto pipelinePromise2 = pipelineRequest2.send(); 233 234 EXPECT_EQ(0, callCount); 235 236 auto response = pipelinePromise.wait(waitScope); 237 EXPECT_EQ("bar", response.getX()); 238 239 auto response2 = pipelinePromise2.wait(waitScope); 240 checkTestMessage(response2); 241 242 EXPECT_EQ(3, callCount); 243 244 // The original promise never completed. 245 KJ_EXPECT(!promise.poll(waitScope)); 246 } 247 248 TEST(Capability, TailCall) { 249 kj::EventLoop loop; 250 kj::WaitScope waitScope(loop); 251 252 int calleeCallCount = 0; 253 int callerCallCount = 0; 254 255 test::TestTailCallee::Client callee(kj::heap<TestTailCalleeImpl>(calleeCallCount)); 256 test::TestTailCaller::Client caller(kj::heap<TestTailCallerImpl>(callerCallCount)); 257 258 auto request = caller.fooRequest(); 259 request.setI(456); 260 request.setCallee(callee); 261 262 auto promise = request.send(); 263 264 auto dependentCall0 = promise.getC().getCallSequenceRequest().send(); 265 266 auto response = promise.wait(waitScope); 267 EXPECT_EQ(456, response.getI()); 268 EXPECT_EQ(456, response.getI()); 269 270 auto dependentCall1 = promise.getC().getCallSequenceRequest().send(); 271 272 auto dependentCall2 = response.getC().getCallSequenceRequest().send(); 273 274 EXPECT_EQ(0, dependentCall0.wait(waitScope).getN()); 275 EXPECT_EQ(1, dependentCall1.wait(waitScope).getN()); 276 EXPECT_EQ(2, dependentCall2.wait(waitScope).getN()); 277 278 EXPECT_EQ(1, calleeCallCount); 279 EXPECT_EQ(1, callerCallCount); 280 } 281 282 TEST(Capability, AsyncCancelation) { 283 // Tests allowCancellation(). 284 285 kj::EventLoop loop; 286 kj::WaitScope waitScope(loop); 287 288 auto paf = kj::newPromiseAndFulfiller<void>(); 289 bool destroyed = false; 290 auto destructionPromise = paf.promise.then([&]() { destroyed = true; }).eagerlyEvaluate(nullptr); 291 292 int callCount = 0; 293 int handleCount = 0; 294 295 test::TestMoreStuff::Client client(kj::heap<TestMoreStuffImpl>(callCount, handleCount)); 296 297 kj::Promise<void> promise = nullptr; 298 299 bool returned = false; 300 { 301 auto request = client.expectCancelRequest(); 302 request.setCap(test::TestInterface::Client(kj::heap<TestCapDestructor>(kj::mv(paf.fulfiller)))); 303 promise = request.send().then( 304 [&](Response<test::TestMoreStuff::ExpectCancelResults>&& response) { 305 returned = true; 306 }).eagerlyEvaluate(nullptr); 307 } 308 kj::evalLater([]() {}).wait(waitScope); 309 kj::evalLater([]() {}).wait(waitScope); 310 311 // We can detect that the method was canceled because it will drop the cap. 312 EXPECT_FALSE(destroyed); 313 EXPECT_FALSE(returned); 314 315 promise = nullptr; // request cancellation 316 destructionPromise.wait(waitScope); 317 318 EXPECT_TRUE(destroyed); 319 EXPECT_FALSE(returned); 320 } 321 322 // ======================================================================================= 323 324 TEST(Capability, DynamicClient) { 325 kj::EventLoop loop; 326 kj::WaitScope waitScope(loop); 327 328 int callCount = 0; 329 DynamicCapability::Client client = 330 test::TestInterface::Client(kj::heap<TestInterfaceImpl>(callCount)); 331 332 auto request1 = client.newRequest("foo"); 333 request1.set("i", 123); 334 request1.set("j", true); 335 auto promise1 = request1.send(); 336 337 auto request2 = client.newRequest("baz"); 338 initDynamicTestMessage(request2.init("s").as<DynamicStruct>()); 339 auto promise2 = request2.send(); 340 341 bool barFailed = false; 342 auto request3 = client.newRequest("bar"); 343 auto promise3 = request3.send().then( 344 [](Response<DynamicStruct>&& response) { 345 ADD_FAILURE() << "Expected bar() call to fail."; 346 }, [&](kj::Exception&& e) { 347 EXPECT_EQ(kj::Exception::Type::UNIMPLEMENTED, e.getType()); 348 barFailed = true; 349 }); 350 351 EXPECT_EQ(0, callCount); 352 353 auto response1 = promise1.wait(waitScope); 354 355 EXPECT_EQ("foo", response1.get("x").as<Text>()); 356 357 auto response2 = promise2.wait(waitScope); 358 359 promise3.wait(waitScope); 360 361 EXPECT_EQ(2, callCount); 362 EXPECT_TRUE(barFailed); 363 } 364 365 TEST(Capability, DynamicClientInheritance) { 366 kj::EventLoop loop; 367 kj::WaitScope waitScope(loop); 368 369 int callCount = 0; 370 371 DynamicCapability::Client client1 = 372 test::TestExtends::Client(kj::heap<TestExtendsImpl>(callCount)); 373 EXPECT_EQ(Schema::from<test::TestExtends>(), client1.getSchema()); 374 EXPECT_NE(Schema::from<test::TestInterface>(), client1.getSchema()); 375 376 DynamicCapability::Client client2 = client1.upcast(Schema::from<test::TestInterface>()); 377 EXPECT_EQ(Schema::from<test::TestInterface>(), client2.getSchema()); 378 379 EXPECT_ANY_THROW(client2.upcast(Schema::from<test::TestExtends>())); 380 auto client = client2.castAs<DynamicCapability>(Schema::from<test::TestExtends>()); 381 382 auto request1 = client.newRequest("foo"); 383 request1.set("i", 321); 384 auto promise1 = request1.send(); 385 386 auto request2 = client.newRequest("grault"); 387 auto promise2 = request2.send(); 388 389 EXPECT_EQ(0, callCount); 390 391 auto response2 = promise2.wait(waitScope); 392 393 checkDynamicTestMessage(response2.as<DynamicStruct>()); 394 395 auto response1 = promise1.wait(waitScope); 396 397 EXPECT_EQ("bar", response1.get("x").as<Text>()); 398 399 EXPECT_EQ(2, callCount); 400 } 401 402 TEST(Capability, DynamicClientPipelining) { 403 kj::EventLoop loop; 404 kj::WaitScope waitScope(loop); 405 406 int callCount = 0; 407 int chainedCallCount = 0; 408 DynamicCapability::Client client = 409 test::TestPipeline::Client(kj::heap<TestPipelineImpl>(callCount)); 410 411 auto request = client.newRequest("getCap"); 412 request.set("n", 234); 413 request.set("inCap", test::TestInterface::Client(kj::heap<TestInterfaceImpl>(chainedCallCount))); 414 415 auto promise = request.send(); 416 417 auto outCap = promise.get("outBox").releaseAs<DynamicStruct>() 418 .get("cap").releaseAs<DynamicCapability>(); 419 auto pipelineRequest = outCap.newRequest("foo"); 420 pipelineRequest.set("i", 321); 421 auto pipelinePromise = pipelineRequest.send(); 422 423 auto pipelineRequest2 = outCap.castAs<test::TestExtends>().graultRequest(); 424 auto pipelinePromise2 = pipelineRequest2.send(); 425 426 promise = nullptr; // Just to be annoying, drop the original promise. 427 428 EXPECT_EQ(0, callCount); 429 EXPECT_EQ(0, chainedCallCount); 430 431 auto response = pipelinePromise.wait(waitScope); 432 EXPECT_EQ("bar", response.get("x").as<Text>()); 433 434 auto response2 = pipelinePromise2.wait(waitScope); 435 checkTestMessage(response2); 436 437 EXPECT_EQ(3, callCount); 438 EXPECT_EQ(1, chainedCallCount); 439 } 440 441 TEST(Capability, DynamicClientPipelineAnyCap) { 442 kj::EventLoop loop; 443 kj::WaitScope waitScope(loop); 444 445 int callCount = 0; 446 int chainedCallCount = 0; 447 DynamicCapability::Client client = 448 test::TestPipeline::Client(kj::heap<TestPipelineImpl>(callCount)); 449 450 auto request = client.newRequest("getAnyCap"); 451 request.set("n", 234); 452 request.set("inCap", test::TestInterface::Client(kj::heap<TestInterfaceImpl>(chainedCallCount))); 453 454 auto promise = request.send(); 455 456 auto outAnyCap = promise.get("outBox").releaseAs<DynamicStruct>() 457 .get("cap").releaseAs<DynamicCapability>(); 458 459 EXPECT_EQ(Schema::from<Capability>(), outAnyCap.getSchema()); 460 auto outCap = outAnyCap.castAs<DynamicCapability>(Schema::from<test::TestInterface>()); 461 462 auto pipelineRequest = outCap.newRequest("foo"); 463 pipelineRequest.set("i", 321); 464 auto pipelinePromise = pipelineRequest.send(); 465 466 auto pipelineRequest2 = outCap.castAs<test::TestExtends>().graultRequest(); 467 auto pipelinePromise2 = pipelineRequest2.send(); 468 469 promise = nullptr; // Just to be annoying, drop the original promise. 470 471 EXPECT_EQ(0, callCount); 472 EXPECT_EQ(0, chainedCallCount); 473 474 auto response = pipelinePromise.wait(waitScope); 475 EXPECT_EQ("bar", response.get("x").as<Text>()); 476 477 auto response2 = pipelinePromise2.wait(waitScope); 478 checkTestMessage(response2); 479 480 EXPECT_EQ(3, callCount); 481 EXPECT_EQ(1, chainedCallCount); 482 } 483 484 // ======================================================================================= 485 486 class TestInterfaceDynamicImpl final: public DynamicCapability::Server { 487 public: 488 TestInterfaceDynamicImpl(int& callCount) 489 : DynamicCapability::Server(Schema::from<test::TestInterface>()), 490 callCount(callCount) {} 491 492 int& callCount; 493 494 kj::Promise<void> call(InterfaceSchema::Method method, 495 CallContext<DynamicStruct, DynamicStruct> context) { 496 auto methodName = method.getProto().getName(); 497 if (methodName == "foo") { 498 ++callCount; 499 auto params = context.getParams(); 500 EXPECT_EQ(123, params.get("i").as<int>()); 501 EXPECT_TRUE(params.get("j").as<bool>()); 502 context.getResults().set("x", "foo"); 503 return kj::READY_NOW; 504 } else if (methodName == "baz") { 505 ++callCount; 506 auto params = context.getParams(); 507 checkDynamicTestMessage(params.get("s").as<DynamicStruct>()); 508 context.releaseParams(); 509 EXPECT_ANY_THROW(context.getParams()); 510 return kj::READY_NOW; 511 } else { 512 KJ_UNIMPLEMENTED("Method not implemented", methodName) { break; } 513 return kj::READY_NOW; 514 } 515 } 516 }; 517 518 TEST(Capability, DynamicServer) { 519 kj::EventLoop loop; 520 kj::WaitScope waitScope(loop); 521 522 int callCount = 0; 523 test::TestInterface::Client client = 524 DynamicCapability::Client(kj::heap<TestInterfaceDynamicImpl>(callCount)) 525 .castAs<test::TestInterface>(); 526 527 auto request1 = client.fooRequest(); 528 request1.setI(123); 529 request1.setJ(true); 530 auto promise1 = request1.send(); 531 532 auto request2 = client.bazRequest(); 533 initTestMessage(request2.initS()); 534 auto promise2 = request2.send(); 535 536 bool barFailed = false; 537 auto request3 = client.barRequest(); 538 auto promise3 = request3.send().then( 539 [](Response<test::TestInterface::BarResults>&& response) { 540 ADD_FAILURE() << "Expected bar() call to fail."; 541 }, [&](kj::Exception&& e) { 542 EXPECT_EQ(kj::Exception::Type::UNIMPLEMENTED, e.getType()); 543 barFailed = true; 544 }); 545 546 EXPECT_EQ(0, callCount); 547 548 auto response1 = promise1.wait(waitScope); 549 550 EXPECT_EQ("foo", response1.getX()); 551 552 auto response2 = promise2.wait(waitScope); 553 554 promise3.wait(waitScope); 555 556 EXPECT_EQ(2, callCount); 557 EXPECT_TRUE(barFailed); 558 } 559 560 class TestExtendsDynamicImpl final: public DynamicCapability::Server { 561 public: 562 TestExtendsDynamicImpl(int& callCount) 563 : DynamicCapability::Server(Schema::from<test::TestExtends>()), 564 callCount(callCount) {} 565 566 int& callCount; 567 568 kj::Promise<void> call(InterfaceSchema::Method method, 569 CallContext<DynamicStruct, DynamicStruct> context) { 570 auto methodName = method.getProto().getName(); 571 if (methodName == "foo") { 572 ++callCount; 573 auto params = context.getParams(); 574 EXPECT_EQ(321, params.get("i").as<int>()); 575 EXPECT_FALSE(params.get("j").as<bool>()); 576 context.getResults().set("x", "bar"); 577 return kj::READY_NOW; 578 } else if (methodName == "grault") { 579 ++callCount; 580 context.releaseParams(); 581 initDynamicTestMessage(context.getResults()); 582 return kj::READY_NOW; 583 } else { 584 KJ_FAIL_ASSERT("Method not implemented", methodName); 585 } 586 } 587 }; 588 589 TEST(Capability, DynamicServerInheritance) { 590 kj::EventLoop loop; 591 kj::WaitScope waitScope(loop); 592 593 int callCount = 0; 594 test::TestExtends::Client client1 = 595 DynamicCapability::Client(kj::heap<TestExtendsDynamicImpl>(callCount)) 596 .castAs<test::TestExtends>(); 597 test::TestInterface::Client client2 = client1; 598 auto client = client2.castAs<test::TestExtends>(); 599 600 auto request1 = client.fooRequest(); 601 request1.setI(321); 602 auto promise1 = request1.send(); 603 604 auto request2 = client.graultRequest(); 605 auto promise2 = request2.send(); 606 607 EXPECT_EQ(0, callCount); 608 609 auto response2 = promise2.wait(waitScope); 610 611 checkTestMessage(response2); 612 613 auto response1 = promise1.wait(waitScope); 614 615 EXPECT_EQ("bar", response1.getX()); 616 617 EXPECT_EQ(2, callCount); 618 } 619 620 class TestPipelineDynamicImpl final: public DynamicCapability::Server { 621 public: 622 TestPipelineDynamicImpl(int& callCount) 623 : DynamicCapability::Server(Schema::from<test::TestPipeline>()), 624 callCount(callCount) {} 625 626 int& callCount; 627 628 kj::Promise<void> call(InterfaceSchema::Method method, 629 CallContext<DynamicStruct, DynamicStruct> context) { 630 auto methodName = method.getProto().getName(); 631 if (methodName == "getCap") { 632 ++callCount; 633 634 auto params = context.getParams(); 635 EXPECT_EQ(234, params.get("n").as<uint32_t>()); 636 637 auto cap = params.get("inCap").as<DynamicCapability>(); 638 context.releaseParams(); 639 640 auto request = cap.newRequest("foo"); 641 request.set("i", 123); 642 request.set("j", true); 643 644 return request.send().then( 645 [this,KJ_CPCAP(context)](capnp::Response<DynamicStruct>&& response) mutable { 646 EXPECT_EQ("foo", response.get("x").as<Text>()); 647 648 auto result = context.getResults(); 649 result.set("s", "bar"); 650 651 auto box = result.init("outBox").as<DynamicStruct>(); 652 653 // Too lazy to write a whole separate test for each of these cases... so just make 654 // sure they both compile here, and only actually test the latter. 655 box.set("cap", kj::heap<TestExtendsDynamicImpl>(callCount)); 656 #if __GNUG__ && !__clang__ && __GNUG__ == 4 && __GNUC_MINOR__ == 9 657 // The last line in this block tickles a bug in Debian G++ 4.9.2 that is not present 658 // in 4.8.x nor in 4.9.4: 659 // https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=781060 660 // 661 // Unfortunately 4.9.2 is present on many Debian Jessie systems.. 662 // 663 // For the moment, we can get away with skipping the last line as the previous line 664 // will set things up in a way that allows the test to complete successfully. 665 return; 666 #endif 667 box.set("cap", kj::heap<TestExtendsImpl>(callCount)); 668 }); 669 } else { 670 KJ_FAIL_ASSERT("Method not implemented", methodName); 671 } 672 } 673 }; 674 675 TEST(Capability, DynamicServerPipelining) { 676 kj::EventLoop loop; 677 kj::WaitScope waitScope(loop); 678 679 int callCount = 0; 680 int chainedCallCount = 0; 681 test::TestPipeline::Client client = 682 DynamicCapability::Client(kj::heap<TestPipelineDynamicImpl>(callCount)) 683 .castAs<test::TestPipeline>(); 684 685 auto request = client.getCapRequest(); 686 request.setN(234); 687 request.setInCap(test::TestInterface::Client(kj::heap<TestInterfaceImpl>(chainedCallCount))); 688 689 auto promise = request.send(); 690 691 auto pipelineRequest = promise.getOutBox().getCap().fooRequest(); 692 pipelineRequest.setI(321); 693 auto pipelinePromise = pipelineRequest.send(); 694 695 auto pipelineRequest2 = promise.getOutBox().getCap().castAs<test::TestExtends>().graultRequest(); 696 auto pipelinePromise2 = pipelineRequest2.send(); 697 698 promise = nullptr; // Just to be annoying, drop the original promise. 699 700 EXPECT_EQ(0, callCount); 701 EXPECT_EQ(0, chainedCallCount); 702 703 auto response = pipelinePromise.wait(waitScope); 704 EXPECT_EQ("bar", response.getX()); 705 706 auto response2 = pipelinePromise2.wait(waitScope); 707 checkTestMessage(response2); 708 709 EXPECT_EQ(3, callCount); 710 EXPECT_EQ(1, chainedCallCount); 711 } 712 713 class TestTailCallerDynamicImpl final: public DynamicCapability::Server { 714 public: 715 TestTailCallerDynamicImpl(int& callCount) 716 : DynamicCapability::Server(Schema::from<test::TestTailCaller>()), 717 callCount(callCount) {} 718 719 int& callCount; 720 721 kj::Promise<void> call(InterfaceSchema::Method method, 722 CallContext<DynamicStruct, DynamicStruct> context) { 723 auto methodName = method.getProto().getName(); 724 if (methodName == "foo") { 725 ++callCount; 726 727 auto params = context.getParams(); 728 auto tailRequest = params.get("callee").as<DynamicCapability>().newRequest("foo"); 729 tailRequest.set("i", params.get("i")); 730 tailRequest.set("t", "from TestTailCaller"); 731 return context.tailCall(kj::mv(tailRequest)); 732 } else { 733 KJ_FAIL_ASSERT("Method not implemented", methodName); 734 } 735 } 736 }; 737 738 TEST(Capability, DynamicServerTailCall) { 739 kj::EventLoop loop; 740 kj::WaitScope waitScope(loop); 741 742 int calleeCallCount = 0; 743 int callerCallCount = 0; 744 745 test::TestTailCallee::Client callee(kj::heap<TestTailCalleeImpl>(calleeCallCount)); 746 test::TestTailCaller::Client caller = 747 DynamicCapability::Client(kj::heap<TestTailCallerDynamicImpl>(callerCallCount)) 748 .castAs<test::TestTailCaller>(); 749 750 auto request = caller.fooRequest(); 751 request.setI(456); 752 request.setCallee(callee); 753 754 auto promise = request.send(); 755 756 auto dependentCall0 = promise.getC().getCallSequenceRequest().send(); 757 758 auto response = promise.wait(waitScope); 759 EXPECT_EQ(456, response.getI()); 760 EXPECT_EQ(456, response.getI()); 761 762 auto dependentCall1 = promise.getC().getCallSequenceRequest().send(); 763 764 auto dependentCall2 = response.getC().getCallSequenceRequest().send(); 765 766 EXPECT_EQ(0, dependentCall0.wait(waitScope).getN()); 767 EXPECT_EQ(1, dependentCall1.wait(waitScope).getN()); 768 EXPECT_EQ(2, dependentCall2.wait(waitScope).getN()); 769 770 EXPECT_EQ(1, calleeCallCount); 771 EXPECT_EQ(1, callerCallCount); 772 } 773 774 // ======================================================================================= 775 776 void verifyClient(test::TestInterface::Client client, const int& callCount, 777 kj::WaitScope& waitScope) { 778 int origCount = callCount; 779 auto request = client.fooRequest(); 780 request.setI(123); 781 request.setJ(true); 782 auto response = request.send().wait(waitScope); 783 EXPECT_EQ("foo", response.getX()); 784 EXPECT_EQ(origCount + 1, callCount); 785 } 786 787 void verifyClient(DynamicCapability::Client client, const int& callCount, 788 kj::WaitScope& waitScope) { 789 int origCount = callCount; 790 auto request = client.newRequest("foo"); 791 request.set("i", 123); 792 request.set("j", true); 793 auto response = request.send().wait(waitScope); 794 EXPECT_EQ("foo", response.get("x").as<Text>()); 795 EXPECT_EQ(origCount + 1, callCount); 796 } 797 798 TEST(Capability, AnyPointersAndOrphans) { 799 kj::EventLoop loop; 800 kj::WaitScope waitScope(loop); 801 802 int callCount1 = 0; 803 int callCount2 = 0; 804 805 // We use a TestPipeline instance here merely as a way to conveniently obtain an imbued message 806 // instance. 807 test::TestPipeline::Client baseClient(nullptr); 808 test::TestInterface::Client client1(kj::heap<TestInterfaceImpl>(callCount1)); 809 test::TestInterface::Client client2(kj::heap<TestInterfaceImpl>(callCount2)); 810 811 auto request = baseClient.testPointersRequest(); 812 request.setCap(client1); 813 814 EXPECT_TRUE(request.hasCap()); 815 816 Orphan<test::TestInterface> orphan = request.disownCap(); 817 EXPECT_FALSE(orphan == nullptr); 818 819 EXPECT_FALSE(request.hasCap()); 820 821 verifyClient(orphan.get(), callCount1, waitScope); 822 verifyClient(orphan.getReader(), callCount1, waitScope); 823 824 request.getObj().adopt(kj::mv(orphan)); 825 EXPECT_TRUE(orphan == nullptr); 826 827 verifyClient(request.getObj().getAs<test::TestInterface>(), callCount1, waitScope); 828 verifyClient(request.asReader().getObj().getAs<test::TestInterface>(), callCount1, waitScope); 829 verifyClient(request.getObj().getAs<DynamicCapability>( 830 Schema::from<test::TestInterface>()), callCount1, waitScope); 831 verifyClient(request.asReader().getObj().getAs<DynamicCapability>( 832 Schema::from<test::TestInterface>()), callCount1, waitScope); 833 834 request.getObj().clear(); 835 EXPECT_FALSE(request.hasObj()); 836 837 request.getObj().setAs<test::TestInterface>(client2); 838 verifyClient(request.getObj().getAs<test::TestInterface>(), callCount2, waitScope); 839 840 Orphan<DynamicCapability> dynamicOrphan = request.getObj().disownAs<DynamicCapability>( 841 Schema::from<test::TestInterface>()); 842 verifyClient(dynamicOrphan.get(), callCount2, waitScope); 843 verifyClient(dynamicOrphan.getReader(), callCount2, waitScope); 844 845 Orphan<DynamicValue> dynamicValueOrphan = kj::mv(dynamicOrphan); 846 verifyClient(dynamicValueOrphan.get().as<DynamicCapability>(), callCount2, waitScope); 847 848 orphan = dynamicValueOrphan.releaseAs<test::TestInterface>(); 849 EXPECT_FALSE(orphan == nullptr); 850 verifyClient(orphan.get(), callCount2, waitScope); 851 852 request.adoptCap(kj::mv(orphan)); 853 EXPECT_TRUE(orphan == nullptr); 854 855 verifyClient(request.getCap(), callCount2, waitScope); 856 857 Orphan<DynamicCapability> dynamicOrphan2 = request.disownCap(); 858 verifyClient(dynamicOrphan2.get(), callCount2, waitScope); 859 verifyClient(dynamicOrphan2.getReader(), callCount2, waitScope); 860 } 861 862 TEST(Capability, Lists) { 863 kj::EventLoop loop; 864 kj::WaitScope waitScope(loop); 865 866 int callCount1 = 0; 867 int callCount2 = 0; 868 int callCount3 = 0; 869 test::TestPipeline::Client baseClient(kj::heap<TestPipelineImpl>(callCount1)); 870 test::TestInterface::Client client1(kj::heap<TestInterfaceImpl>(callCount1)); 871 test::TestInterface::Client client2(kj::heap<TestInterfaceImpl>(callCount2)); 872 test::TestInterface::Client client3(kj::heap<TestInterfaceImpl>(callCount3)); 873 874 auto request = baseClient.testPointersRequest(); 875 876 auto list = request.initList(3); 877 list.set(0, client1); 878 list.set(1, client2); 879 list.set(2, client3); 880 881 verifyClient(list[0], callCount1, waitScope); 882 verifyClient(list[1], callCount2, waitScope); 883 verifyClient(list[2], callCount3, waitScope); 884 885 auto listReader = request.asReader().getList(); 886 verifyClient(listReader[0], callCount1, waitScope); 887 verifyClient(listReader[1], callCount2, waitScope); 888 verifyClient(listReader[2], callCount3, waitScope); 889 890 auto dynamicList = toDynamic(list); 891 verifyClient(dynamicList[0].as<DynamicCapability>(), callCount1, waitScope); 892 verifyClient(dynamicList[1].as<DynamicCapability>(), callCount2, waitScope); 893 verifyClient(dynamicList[2].as<DynamicCapability>(), callCount3, waitScope); 894 895 auto dynamicListReader = toDynamic(listReader); 896 verifyClient(dynamicListReader[0].as<DynamicCapability>(), callCount1, waitScope); 897 verifyClient(dynamicListReader[1].as<DynamicCapability>(), callCount2, waitScope); 898 verifyClient(dynamicListReader[2].as<DynamicCapability>(), callCount3, waitScope); 899 } 900 901 TEST(Capability, KeywordMethods) { 902 // Verify that keywords are only munged where necessary. 903 904 kj::EventLoop loop; 905 kj::WaitScope waitScope(loop); 906 bool called = false; 907 908 class TestKeywordMethodsImpl final: public test::TestKeywordMethods::Server { 909 public: 910 TestKeywordMethodsImpl(bool& called): called(called) {} 911 912 kj::Promise<void> delete_(DeleteContext context) override { 913 called = true; 914 return kj::READY_NOW; 915 } 916 917 private: 918 bool& called; 919 }; 920 921 test::TestKeywordMethods::Client client = kj::heap<TestKeywordMethodsImpl>(called); 922 client.deleteRequest().send().wait(waitScope); 923 924 EXPECT_TRUE(called); 925 } 926 927 TEST(Capability, Generics) { 928 kj::EventLoop loop; 929 kj::WaitScope waitScope(loop); 930 931 typedef test::TestGenerics<TestAllTypes>::Interface<List<uint32_t>> Interface; 932 Interface::Client client = nullptr; 933 934 auto request = client.callRequest(); 935 request.setBaz("hello"); 936 initTestMessage(request.initInnerBound().initFoo()); 937 initTestMessage(request.initInnerUnbound().getFoo().initAs<TestAllTypes>()); 938 939 auto promise = request.send().then([](capnp::Response<Interface::CallResults>&& response) { 940 // This doesn't actually execute; we're just checking that it compiles. 941 List<uint32_t>::Reader qux = response.getQux(); 942 qux.size(); 943 checkTestMessage(response.getGen().getFoo()); 944 }, [](kj::Exception&& e) { 945 // Ignore exception (which we'll always get because we're calling a null capability). 946 }); 947 948 promise.wait(waitScope); 949 950 // Check that asGeneric<>() compiles. 951 test::TestGenerics<TestAllTypes>::Interface<>::Client castClient = client.asGeneric<>(); 952 test::TestGenerics<TestAllTypes>::Interface<TestAllTypes>::Client castClient2 = 953 client.asGeneric<TestAllTypes>(); 954 test::TestGenerics<>::Interface<List<uint32_t>>::Client castClient3 = client.asTestGenericsGeneric<>(); 955 } 956 957 TEST(Capability, Generics2) { 958 MallocMessageBuilder builder; 959 auto root = builder.getRoot<test::TestUseGenerics>(); 960 961 root.initCap().setFoo(test::TestInterface::Client(nullptr)); 962 } 963 964 TEST(Capability, ImplicitParams) { 965 kj::EventLoop loop; 966 kj::WaitScope waitScope(loop); 967 968 typedef test::TestImplicitMethodParams Interface; 969 Interface::Client client = nullptr; 970 971 capnp::Request<Interface::CallParams<Text, TestAllTypes>, 972 test::TestGenerics<Text, TestAllTypes>> request = 973 client.callRequest<Text, TestAllTypes>(); 974 request.setFoo("hello"); 975 initTestMessage(request.initBar()); 976 977 auto promise = request.send() 978 .then([](capnp::Response<test::TestGenerics<Text, TestAllTypes>>&& response) { 979 // This doesn't actually execute; we're just checking that it compiles. 980 Text::Reader text = response.getFoo(); 981 text.size(); 982 checkTestMessage(response.getRev().getFoo()); 983 }, [](kj::Exception&& e) {}); 984 985 promise.wait(waitScope); 986 } 987 988 TEST(Capability, CapabilityServerSet) { 989 kj::EventLoop loop; 990 kj::WaitScope waitScope(loop); 991 992 CapabilityServerSet<test::TestInterface> set1, set2; 993 994 int callCount = 0; 995 test::TestInterface::Client clientStandalone(kj::heap<TestInterfaceImpl>(callCount)); 996 test::TestInterface::Client clientNull = nullptr; 997 998 auto ownServer1 = kj::heap<TestInterfaceImpl>(callCount); 999 auto& server1 = *ownServer1; 1000 test::TestInterface::Client client1 = set1.add(kj::mv(ownServer1)); 1001 1002 auto ownServer2 = kj::heap<TestInterfaceImpl>(callCount); 1003 auto& server2 = *ownServer2; 1004 test::TestInterface::Client client2 = set2.add(kj::mv(ownServer2)); 1005 1006 // Getting the local server using the correct set works. 1007 EXPECT_EQ(&server1, &KJ_ASSERT_NONNULL(set1.getLocalServer(client1).wait(waitScope))); 1008 EXPECT_EQ(&server2, &KJ_ASSERT_NONNULL(set2.getLocalServer(client2).wait(waitScope))); 1009 1010 // Getting the local server using the wrong set doesn't work. 1011 EXPECT_TRUE(set1.getLocalServer(client2).wait(waitScope) == nullptr); 1012 EXPECT_TRUE(set2.getLocalServer(client1).wait(waitScope) == nullptr); 1013 EXPECT_TRUE(set1.getLocalServer(clientStandalone).wait(waitScope) == nullptr); 1014 EXPECT_TRUE(set1.getLocalServer(clientNull).wait(waitScope) == nullptr); 1015 1016 // A promise client waits to be resolved. 1017 auto paf = kj::newPromiseAndFulfiller<test::TestInterface::Client>(); 1018 test::TestInterface::Client clientPromise = kj::mv(paf.promise); 1019 1020 auto errorPaf = kj::newPromiseAndFulfiller<test::TestInterface::Client>(); 1021 test::TestInterface::Client errorPromise = kj::mv(errorPaf.promise); 1022 1023 bool resolved1 = false, resolved2 = false, resolved3 = false; 1024 auto promise1 = set1.getLocalServer(clientPromise) 1025 .then([&](kj::Maybe<test::TestInterface::Server&> server) { 1026 resolved1 = true; 1027 EXPECT_EQ(&server1, &KJ_ASSERT_NONNULL(server)); 1028 }); 1029 auto promise2 = set2.getLocalServer(clientPromise) 1030 .then([&](kj::Maybe<test::TestInterface::Server&> server) { 1031 resolved2 = true; 1032 EXPECT_TRUE(server == nullptr); 1033 }); 1034 auto promise3 = set1.getLocalServer(errorPromise) 1035 .then([&](kj::Maybe<test::TestInterface::Server&> server) { 1036 KJ_FAIL_EXPECT("getLocalServer() on error promise should have thrown"); 1037 }, [&](kj::Exception&& e) { 1038 resolved3 = true; 1039 KJ_EXPECT(e.getDescription().endsWith("foo"), e.getDescription()); 1040 }); 1041 1042 kj::evalLater([](){}).wait(waitScope); 1043 kj::evalLater([](){}).wait(waitScope); 1044 kj::evalLater([](){}).wait(waitScope); 1045 kj::evalLater([](){}).wait(waitScope); 1046 1047 EXPECT_FALSE(resolved1); 1048 EXPECT_FALSE(resolved2); 1049 EXPECT_FALSE(resolved3); 1050 1051 paf.fulfiller->fulfill(kj::cp(client1)); 1052 errorPaf.fulfiller->reject(KJ_EXCEPTION(FAILED, "foo")); 1053 1054 promise1.wait(waitScope); 1055 promise2.wait(waitScope); 1056 promise3.wait(waitScope); 1057 1058 EXPECT_TRUE(resolved1); 1059 EXPECT_TRUE(resolved2); 1060 EXPECT_TRUE(resolved3); 1061 } 1062 1063 class TestThisCap final: public test::TestInterface::Server { 1064 public: 1065 TestThisCap(int& callCount): callCount(callCount) {} 1066 ~TestThisCap() noexcept(false) { callCount = -1; } 1067 1068 test::TestInterface::Client getSelf() { 1069 return thisCap(); 1070 } 1071 1072 protected: 1073 kj::Promise<void> bar(BarContext context) { 1074 ++callCount; 1075 return kj::READY_NOW; 1076 } 1077 1078 private: 1079 int& callCount; 1080 }; 1081 1082 TEST(Capability, ThisCap) { 1083 int callCount = 0; 1084 kj::EventLoop loop; 1085 kj::WaitScope waitScope(loop); 1086 1087 auto server = kj::heap<TestThisCap>(callCount); 1088 TestThisCap* serverPtr = server; 1089 1090 test::TestInterface::Client client = kj::mv(server); 1091 client.barRequest().send().wait(waitScope); 1092 EXPECT_EQ(1, callCount); 1093 1094 test::TestInterface::Client client2 = serverPtr->getSelf(); 1095 EXPECT_EQ(1, callCount); 1096 client2.barRequest().send().wait(waitScope); 1097 EXPECT_EQ(2, callCount); 1098 1099 client = nullptr; 1100 1101 EXPECT_EQ(2, callCount); 1102 client2.barRequest().send().wait(waitScope); 1103 EXPECT_EQ(3, callCount); 1104 1105 client2 = nullptr; 1106 1107 EXPECT_EQ(-1, callCount); 1108 } 1109 1110 TEST(Capability, TransferCap) { 1111 kj::EventLoop loop; 1112 kj::WaitScope waitScope(loop); 1113 1114 MallocMessageBuilder message; 1115 auto root = message.initRoot<test::TestTransferCap>(); 1116 1117 auto orphan = message.getOrphanage().newOrphan<test::TestTransferCap::Element>(); 1118 auto e = orphan.get(); 1119 e.setText("foo"); 1120 e.setCap(KJ_EXCEPTION(FAILED, "whatever")); 1121 1122 root.initList(1).adoptWithCaveats(0, kj::mv(orphan)); 1123 1124 // This line used to throw due to capability pointers being incorrectly transferred. 1125 auto cap = root.getList()[0].getCap(); 1126 1127 cap.whenResolved().then([]() { 1128 KJ_FAIL_EXPECT("didn't throw?"); 1129 }, [](kj::Exception&&) { 1130 // success 1131 }).wait(waitScope); 1132 } 1133 1134 KJ_TEST("Promise<RemotePromise<T>> automatically reduces to RemotePromise<T>") { 1135 kj::EventLoop loop; 1136 kj::WaitScope waitScope(loop); 1137 1138 int callCount = 0; 1139 test::TestInterface::Client client(kj::heap<TestInterfaceImpl>(callCount)); 1140 1141 RemotePromise<test::TestInterface::FooResults> promise = kj::evalLater([&]() { 1142 auto request = client.fooRequest(); 1143 request.setI(123); 1144 request.setJ(true); 1145 return request.send(); 1146 }); 1147 1148 EXPECT_EQ(0, callCount); 1149 auto response = promise.wait(waitScope); 1150 EXPECT_EQ("foo", response.getX()); 1151 EXPECT_EQ(1, callCount); 1152 } 1153 1154 KJ_TEST("Promise<RemotePromise<T>> automatically reduces to RemotePromise<T> with pipelining") { 1155 kj::EventLoop loop; 1156 kj::WaitScope waitScope(loop); 1157 1158 int callCount = 0; 1159 int chainedCallCount = 0; 1160 test::TestPipeline::Client client(kj::heap<TestPipelineImpl>(callCount)); 1161 1162 auto promise = kj::evalLater([&]() { 1163 auto request = client.getCapRequest(); 1164 request.setN(234); 1165 request.setInCap(test::TestInterface::Client(kj::heap<TestInterfaceImpl>(chainedCallCount))); 1166 return request.send(); 1167 }); 1168 1169 auto pipelineRequest = promise.getOutBox().getCap().fooRequest(); 1170 pipelineRequest.setI(321); 1171 auto pipelinePromise = pipelineRequest.send(); 1172 1173 EXPECT_EQ(0, callCount); 1174 EXPECT_EQ(0, chainedCallCount); 1175 1176 auto response = pipelinePromise.wait(waitScope); 1177 EXPECT_EQ("bar", response.getX()); 1178 1179 EXPECT_EQ(2, callCount); 1180 EXPECT_EQ(1, chainedCallCount); 1181 } 1182 1183 KJ_TEST("clone() with caps") { 1184 int dummy = 0; 1185 MallocMessageBuilder builder(2048); 1186 auto root = builder.getRoot<AnyPointer>().initAs<List<test::TestInterface>>(3); 1187 root.set(0, kj::heap<TestInterfaceImpl>(dummy)); 1188 root.set(1, kj::heap<TestInterfaceImpl>(dummy)); 1189 root.set(2, kj::heap<TestInterfaceImpl>(dummy)); 1190 1191 auto copyPtr = clone(root.asReader()); 1192 auto& copy = *copyPtr; 1193 1194 KJ_ASSERT(copy.size() == 3); 1195 KJ_EXPECT(ClientHook::from(copy[0]).get() == ClientHook::from(root[0]).get()); 1196 KJ_EXPECT(ClientHook::from(copy[1]).get() == ClientHook::from(root[1]).get()); 1197 KJ_EXPECT(ClientHook::from(copy[2]).get() == ClientHook::from(root[2]).get()); 1198 1199 KJ_EXPECT(ClientHook::from(copy[0]).get() != ClientHook::from(root[1]).get()); 1200 KJ_EXPECT(ClientHook::from(copy[1]).get() != ClientHook::from(root[2]).get()); 1201 KJ_EXPECT(ClientHook::from(copy[2]).get() != ClientHook::from(root[0]).get()); 1202 } 1203 1204 KJ_TEST("Streaming calls block subsequent calls") { 1205 kj::EventLoop loop; 1206 kj::WaitScope waitScope(loop); 1207 1208 auto ownServer = kj::heap<TestStreamingImpl>(); 1209 auto& server = *ownServer; 1210 test::TestStreaming::Client cap = kj::mv(ownServer); 1211 1212 kj::Promise<void> promise1 = nullptr, promise2 = nullptr, promise3 = nullptr; 1213 1214 { 1215 auto req = cap.doStreamIRequest(); 1216 req.setI(123); 1217 promise1 = req.send(); 1218 } 1219 1220 { 1221 auto req = cap.doStreamJRequest(); 1222 req.setJ(321); 1223 promise2 = req.send(); 1224 } 1225 1226 { 1227 auto req = cap.doStreamIRequest(); 1228 req.setI(456); 1229 promise3 = req.send(); 1230 } 1231 1232 auto promise4 = cap.finishStreamRequest().send(); 1233 1234 KJ_EXPECT(server.iSum == 0); 1235 KJ_EXPECT(server.jSum == 0); 1236 1237 KJ_EXPECT(!promise1.poll(waitScope)); 1238 KJ_EXPECT(!promise2.poll(waitScope)); 1239 KJ_EXPECT(!promise3.poll(waitScope)); 1240 KJ_EXPECT(!promise4.poll(waitScope)); 1241 1242 KJ_EXPECT(server.iSum == 123); 1243 KJ_EXPECT(server.jSum == 0); 1244 1245 KJ_ASSERT_NONNULL(server.fulfiller)->fulfill(); 1246 1247 KJ_EXPECT(promise1.poll(waitScope)); 1248 KJ_EXPECT(!promise2.poll(waitScope)); 1249 KJ_EXPECT(!promise3.poll(waitScope)); 1250 KJ_EXPECT(!promise4.poll(waitScope)); 1251 1252 KJ_EXPECT(server.iSum == 123); 1253 KJ_EXPECT(server.jSum == 321); 1254 1255 KJ_ASSERT_NONNULL(server.fulfiller)->fulfill(); 1256 1257 KJ_EXPECT(promise1.poll(waitScope)); 1258 KJ_EXPECT(promise2.poll(waitScope)); 1259 KJ_EXPECT(!promise3.poll(waitScope)); 1260 KJ_EXPECT(!promise4.poll(waitScope)); 1261 1262 KJ_EXPECT(server.iSum == 579); 1263 KJ_EXPECT(server.jSum == 321); 1264 1265 KJ_ASSERT_NONNULL(server.fulfiller)->fulfill(); 1266 1267 KJ_EXPECT(promise1.poll(waitScope)); 1268 KJ_EXPECT(promise2.poll(waitScope)); 1269 KJ_EXPECT(promise3.poll(waitScope)); 1270 KJ_EXPECT(promise4.poll(waitScope)); 1271 1272 auto result = promise4.wait(waitScope); 1273 KJ_EXPECT(result.getTotalI() == 579); 1274 KJ_EXPECT(result.getTotalJ() == 321); 1275 } 1276 1277 KJ_TEST("Streaming calls can be canceled") { 1278 kj::EventLoop loop; 1279 kj::WaitScope waitScope(loop); 1280 1281 auto ownServer = kj::heap<TestStreamingImpl>(); 1282 auto& server = *ownServer; 1283 test::TestStreaming::Client cap = kj::mv(ownServer); 1284 1285 kj::Promise<void> promise1 = nullptr, promise2 = nullptr, promise3 = nullptr; 1286 1287 { 1288 auto req = cap.doStreamIRequest(); 1289 req.setI(123); 1290 promise1 = req.send(); 1291 } 1292 1293 { 1294 auto req = cap.doStreamJRequest(); 1295 req.setJ(321); 1296 promise2 = req.send(); 1297 } 1298 1299 { 1300 auto req = cap.doStreamIRequest(); 1301 req.setI(456); 1302 promise3 = req.send(); 1303 } 1304 1305 auto promise4 = cap.finishStreamRequest().send(); 1306 1307 // Cancel the streaming calls. 1308 promise1 = nullptr; 1309 promise2 = nullptr; 1310 promise3 = nullptr; 1311 1312 KJ_EXPECT(server.iSum == 0); 1313 KJ_EXPECT(server.jSum == 0); 1314 1315 KJ_EXPECT(!promise4.poll(waitScope)); 1316 1317 KJ_EXPECT(server.iSum == 123); 1318 KJ_EXPECT(server.jSum == 0); 1319 1320 KJ_ASSERT_NONNULL(server.fulfiller)->fulfill(); 1321 1322 KJ_EXPECT(!promise4.poll(waitScope)); 1323 1324 // The call to doStreamJ() opted into cancellation so the next call to doStreamI() happens 1325 // immediately. 1326 KJ_EXPECT(server.iSum == 579); 1327 KJ_EXPECT(server.jSum == 321); 1328 1329 KJ_ASSERT_NONNULL(server.fulfiller)->fulfill(); 1330 1331 KJ_EXPECT(promise4.poll(waitScope)); 1332 1333 auto result = promise4.wait(waitScope); 1334 KJ_EXPECT(result.getTotalI() == 579); 1335 KJ_EXPECT(result.getTotalJ() == 321); 1336 } 1337 1338 KJ_TEST("Streaming call throwing cascades to following calls") { 1339 kj::EventLoop loop; 1340 kj::WaitScope waitScope(loop); 1341 1342 auto ownServer = kj::heap<TestStreamingImpl>(); 1343 auto& server = *ownServer; 1344 test::TestStreaming::Client cap = kj::mv(ownServer); 1345 1346 server.jShouldThrow = true; 1347 1348 kj::Promise<void> promise1 = nullptr, promise2 = nullptr, promise3 = nullptr; 1349 1350 { 1351 auto req = cap.doStreamIRequest(); 1352 req.setI(123); 1353 promise1 = req.send(); 1354 } 1355 1356 { 1357 auto req = cap.doStreamJRequest(); 1358 req.setJ(321); 1359 promise2 = req.send(); 1360 } 1361 1362 { 1363 auto req = cap.doStreamIRequest(); 1364 req.setI(456); 1365 promise3 = req.send(); 1366 } 1367 1368 auto promise4 = cap.finishStreamRequest().send(); 1369 1370 KJ_EXPECT(server.iSum == 0); 1371 KJ_EXPECT(server.jSum == 0); 1372 1373 KJ_EXPECT(!promise1.poll(waitScope)); 1374 KJ_EXPECT(!promise2.poll(waitScope)); 1375 KJ_EXPECT(!promise3.poll(waitScope)); 1376 KJ_EXPECT(!promise4.poll(waitScope)); 1377 1378 KJ_EXPECT(server.iSum == 123); 1379 KJ_EXPECT(server.jSum == 0); 1380 1381 KJ_ASSERT_NONNULL(server.fulfiller)->fulfill(); 1382 1383 KJ_EXPECT(promise1.poll(waitScope)); 1384 KJ_EXPECT(promise2.poll(waitScope)); 1385 KJ_EXPECT(promise3.poll(waitScope)); 1386 KJ_EXPECT(promise4.poll(waitScope)); 1387 1388 KJ_EXPECT(server.iSum == 123); 1389 KJ_EXPECT(server.jSum == 321); 1390 1391 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("throw requested", promise2.wait(waitScope)); 1392 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("throw requested", promise3.wait(waitScope)); 1393 KJ_EXPECT_THROW_RECOVERABLE_MESSAGE("throw requested", promise4.ignoreResult().wait(waitScope)); 1394 } 1395 1396 } // namespace 1397 } // namespace _ 1398 } // namespace capnp