148 KJ_EXPECT(foo->add(1, 2) == 3);
150 foo->addOut(3, 4,
ret);
152 foo->addInOut(3,
ret);
153 KJ_EXPECT(
ret == 10);
168 KJ_EXPECT(in.
name == out.name);
169 KJ_EXPECT(in.
set_int.size() == out.set_int.size());
170 for (
auto init{in.
set_int.begin()}, outit{out.set_int.begin()};
init != in.
set_int.end() && outit != out.set_int.end(); ++
init, ++outit) {
171 KJ_EXPECT(*
init == *outit);
175 KJ_EXPECT(out.unordered_set_int.count(elem) == 1);
177 KJ_EXPECT(in.
vector_bool.size() == out.vector_bool.size());
178 for (
size_t i = 0; i < in.
vector_bool.size(); ++i) {
179 KJ_EXPECT(in.
vector_bool[i] == out.vector_bool[i]);
184 KJ_EXPECT(
init->first == outit->first);
185 KJ_EXPECT(
init->second == outit->second);
189 KJ_EXPECT(foo->pass(in).optional_int == 3);
191 KJ_EXPECT(!foo->pass(in).optional_int);
205 int call(
int arg)
override
207 KJ_EXPECT(arg == m_expect);
210 int callExtended(
int arg)
override
212 KJ_EXPECT(arg == m_expect + 10);
218 foo->initThreadMap();
219 Callback callback(1, 2);
220 KJ_EXPECT(foo->callback(callback, 1) == 2);
221 KJ_EXPECT(foo->callbackUnique(std::make_unique<Callback>(3, 4), 3) == 4);
222 KJ_EXPECT(foo->callbackShared(std::make_shared<Callback>(5, 6), 5) == 6);
223 auto saved = std::make_shared<Callback>(7, 8);
224 KJ_EXPECT(saved.use_count() == 1);
225 foo->saveCallback(saved);
226 KJ_EXPECT(saved.use_count() == 2);
227 foo->callbackSaved(7);
228 KJ_EXPECT(foo->callbackSaved(7) == 8);
229 foo->saveCallback(
nullptr);
230 KJ_EXPECT(saved.use_count() == 1);
231 KJ_EXPECT(foo->callbackExtended(callback, 11) == 12);
236 FooCustom custom_out = foo->passCustom(custom_in);
237 KJ_EXPECT(custom_in.
v1 == custom_out.
v1);
238 KJ_EXPECT(custom_in.
v2 == custom_out.
v2);
243 KJ_EXPECT(empty_data_out.empty());
247 FooMessage message2{foo->passMessage(message1)};
248 KJ_EXPECT(message2.
message ==
"init build read call build read");
252 foo->passMutable(mut);
253 KJ_EXPECT(mut.
message ==
"init build pass call return read");
255 KJ_EXPECT(foo->passDouble(1.25) == 1.25);
257 KJ_EXPECT(foo->passFn([]{ return 10; }) == 10);
260 KJ_EXPECT(foo->passFn([foo]{
261 return foo->passFn([]{ return 1; });
264 std::vector<FooDataRef> data_in;
265 data_in.push_back(std::make_shared<FooData>(FooData{
'H',
'i'}));
266 data_in.push_back(
nullptr);
267 std::vector<FooDataRef> data_out{foo->passDataPointers(data_in)};
268 KJ_EXPECT(data_out.size() == 2);
269 KJ_REQUIRE(data_out[0] !=
nullptr);
270 KJ_EXPECT(*data_out[0] == *data_in[0]);
271 KJ_EXPECT(!data_out[1]);
454KJ_TEST(
"Make simultaneous IPC calls on single remote thread")
458 std::promise<void> signal;
460 foo->initThreadMap();
463 setup.
server->m_impl->m_fn = [&] {};
466 Thread::Client *callback_thread, *request_thread;
467 foo->m_context.loop->sync([&] {
469 callback_thread = &tc.callback_threads.at(foo->m_context.connection)->m_client;
470 request_thread = &tc.request_threads.at(foo->m_context.connection)->m_client;
474 std::atomic<int> expected = 100;
476 setup.
server->m_impl->m_int_fn = [&](
int n) {
482 auto client{foo->m_client};
483 std::atomic<size_t> running{3};
484 foo->m_context.loop->sync([&]
486 for (
size_t i = 0; i < running; i++)
488 auto request{client.callIntFnAsyncRequest()};
489 auto context{
request.initContext()};
490 context.setCallbackThread(*callback_thread);
491 context.setThread(*request_thread);
493 foo->m_context.loop->m_task_set->add(
request.send().then(
494 [&running, &tc, i](
auto&& results) {
495 assert(results.getResult() == static_cast<int32_t>(100 * (i+1)));
497 Lock lock(tc.waiter->m_mutex);
498 tc.waiter->m_cv.notify_all();
504 tc.
waiter->wait(lock, [&running] {
return running == 0; });
506 KJ_EXPECT(expected == 400);
509KJ_TEST(
"Call async IPC method dispatched to pool thread")
516 foo->initThreadMap();
517 setup.
server->m_impl->m_int_fn = [](
int n) {
return n * 2; };
520 std::atomic<size_t> running{3};
521 std::promise<void> pool_ready;
522 foo->m_context.loop->sync([&] {
523 auto pool_req = foo->m_context.connection->m_thread_map.makePoolRequest();
524 pool_req.setCount(2);
525 foo->m_context.loop->m_task_set->add(
526 pool_req.send().then([&](
auto&&) { pool_ready.set_value(); }));
528 pool_ready.get_future().get();
532 auto client{foo->m_client};
533 foo->m_context.loop->sync([&] {
534 for (
size_t i = 0; i < running; ++i) {
535 auto request{client.callIntFnAsyncRequest()};
537 request.setArg(
static_cast<int32_t
>(i + 1));
538 foo->m_context.loop->m_task_set->add(
request.send().then(
539 [&running, &tc, i](
auto&& results) {
540 assert(results.getResult() == static_cast<int32_t>((i + 1) * 2));
542 Lock lock(tc.waiter->m_mutex);
543 tc.waiter->m_cv.notify_all();
549 tc.
waiter->wait(lock, [&running] {
return running == 0; });
553KJ_TEST(
"Call async IPC method without thread or pool errors correctly")
557 setup.
server->m_impl->m_fn = [] {};
561 std::promise<void> done;
562 bool error_thrown{
false};
563 foo->m_context.loop->sync([&] {
564 auto request{foo->m_client.callFnAsyncRequest()};
566 foo->m_context.loop->m_task_set->add(
568 [&](
auto&&) { done.set_value(); },
569 [&](kj::Exception&& e) {
571 KJ_EXPECT(std::string_view{e.getDescription().cStr()}.find(
572 "no thread specified and no pool configured") != std::string_view::npos);
576 done.get_future().get();
577 KJ_EXPECT(error_thrown);
std::unique_ptr< Waiter > waiter