1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "module_gdx_unittest.h"
18
19 #include <base/callback.h>
20 #include <base/functional/bind.h>
21 #include <base/location.h>
22 #include <base/threading/platform_thread.h>
23 #include <sys/syscall.h>
24
25 #include <chrono>
26 #include <future>
27 #include <string>
28
29 #include "common/bind.h"
30 #include "common/contextual_callback.h"
31 #include "gtest/gtest.h"
32 #include "module.h"
33 #include "os/handler.h"
34
35 using namespace bluetooth;
36
37 namespace {
38 constexpr int sync_timeout_in_ms = 3000;
39
40 std::promise<pid_t> gdx_external_function_promise;
41 std::promise<pid_t> private_impl_promise;
42 std::promise<pid_t> protected_method_promise;
43
44 } // namespace
45
46 // Global function with C linkage
external_function_gdx(int,double,char)47 void external_function_gdx(int /* a */, double /* b */, char /* c */) {
48 gdx_external_function_promise.set_value(base::PlatformThread::CurrentId());
49 }
50
51 // Module private implementation that is inaccessible externally
52 struct TestGdxModule::PrivateImpl : public ModuleMainloop, public ModuleJniloop {
53 const int kMaxTestGdxModuleRecurseDepth = 10;
54
privateCallableMethodTestGdxModule::PrivateImpl55 void privateCallableMethod(int /* a */, double /* b */, char /* c */) {
56 private_impl_promise.set_value(base::PlatformThread::CurrentId());
57 }
58
repostMethodTestTestGdxModule::PrivateImpl59 void repostMethodTest(int /* a */, double /* b */, char /* c */) {
60 private_impl_promise.set_value(base::PlatformThread::CurrentId());
61 }
62
privateCallableRepostOnMainMethodTestGdxModule::PrivateImpl63 void privateCallableRepostOnMainMethod(
64 std::shared_ptr<TestGdxModule::PrivateImpl> ptr, int a, double b, char c) {
65 PostMethodOnMain(ptr, &PrivateImpl::repostMethodTest, a, b, c);
66 }
67
privateCallableRepostOnJniMethodTestGdxModule::PrivateImpl68 void privateCallableRepostOnJniMethod(
69 std::shared_ptr<TestGdxModule::PrivateImpl> ptr, int a, double b, char c) {
70 PostMethodOnJni(ptr, &PrivateImpl::repostMethodTest, a, b, c);
71 }
72
privateCallableRecursiveOnMainMethodTestGdxModule::PrivateImpl73 void privateCallableRecursiveOnMainMethod(
74 std::shared_ptr<TestGdxModule::PrivateImpl> ptr, int depth, double b, char c) {
75 if (depth > kMaxTestGdxModuleRecurseDepth) {
76 private_impl_promise.set_value(base::PlatformThread::CurrentId());
77 return;
78 }
79 PostMethodOnMain(ptr, &PrivateImpl::privateCallableRecursiveOnMainMethod, ptr, depth + 1, b, c);
80 }
81
privateCallableRecursiveOnJniMethodTestGdxModule::PrivateImpl82 void privateCallableRecursiveOnJniMethod(
83 std::shared_ptr<TestGdxModule::PrivateImpl> ptr, int depth, double b, char c) {
84 if (depth > kMaxTestGdxModuleRecurseDepth) {
85 private_impl_promise.set_value(base::PlatformThread::CurrentId());
86 return;
87 }
88 PostMethodOnJni(ptr, &PrivateImpl::privateCallableRecursiveOnJniMethod, ptr, depth + 1, b, c);
89 }
90 };
91
92 // Protected module method executed on handler
call_on_handler_protected_method(int loop_tid,int a,int b,int c)93 void TestGdxModule::call_on_handler_protected_method(int loop_tid, int a, int b, int c) {
94 protected_method_promise = std::promise<pid_t>();
95 auto future = protected_method_promise.get_future();
96 CallOn(this, &TestGdxModule::protected_method, a, b, c);
97 ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
98 ASSERT_EQ(future.get(), loop_tid);
99 }
100
101 // Global external function executed on main loop
call_on_main_external_function(int loop_tid,int a,double b,char c)102 void TestGdxModule::call_on_main_external_function(int loop_tid, int a, double b, char c) {
103 gdx_external_function_promise = std::promise<pid_t>();
104 auto future = gdx_external_function_promise.get_future();
105 PostFunctionOnMain(&external_function_gdx, a, b, c);
106 ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
107 ASSERT_EQ(future.get(), loop_tid);
108 }
109
110 // Private implementation method executed on main loop
call_on_main(int loop_tid,int a,int b,int c)111 void TestGdxModule::call_on_main(int loop_tid, int a, int b, int c) {
112 private_impl_promise = std::promise<pid_t>();
113 auto future = private_impl_promise.get_future();
114 PostMethodOnMain(pimpl_, &TestGdxModule::PrivateImpl::privateCallableMethod, a, b, c);
115 ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
116 ASSERT_EQ(future.get(), loop_tid);
117 }
118
119 // Private implementation method executed on main loop and reposted
call_on_main_repost(int loop_tid,int a,int b,int c)120 void TestGdxModule::call_on_main_repost(int loop_tid, int a, int b, int c) {
121 private_impl_promise = std::promise<pid_t>();
122 auto future = private_impl_promise.get_future();
123 PostMethodOnMain(
124 pimpl_, &TestGdxModule::PrivateImpl::privateCallableRepostOnMainMethod, pimpl_, a, b, c);
125 ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
126 ASSERT_EQ(future.get(), loop_tid);
127 }
128
129 // Private implementation method executed on main loop recursively
call_on_main_recurse(int loop_tid,int depth,int b,int c)130 void TestGdxModule::call_on_main_recurse(int loop_tid, int depth, int b, int c) {
131 private_impl_promise = std::promise<pid_t>();
132 auto future = private_impl_promise.get_future();
133 PostMethodOnMain(
134 pimpl_,
135 &TestGdxModule::PrivateImpl::privateCallableRecursiveOnMainMethod,
136 pimpl_,
137 depth,
138 b,
139 c);
140 ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
141 ASSERT_EQ(future.get(), loop_tid);
142 }
143
144 // Global external function executed on main loop
call_on_jni_external_function(int loop_tid,int a,double b,char c)145 void TestGdxModule::call_on_jni_external_function(int loop_tid, int a, double b, char c) {
146 gdx_external_function_promise = std::promise<pid_t>();
147 auto future = gdx_external_function_promise.get_future();
148 PostFunctionOnJni(&external_function_gdx, a, b, c);
149 ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
150 ASSERT_EQ(future.get(), loop_tid);
151 }
152
153 // Private implementation method executed on main loop
call_on_jni(int loop_tid,int a,int b,int c)154 void TestGdxModule::call_on_jni(int loop_tid, int a, int b, int c) {
155 private_impl_promise = std::promise<pid_t>();
156 auto future = private_impl_promise.get_future();
157 PostMethodOnJni(pimpl_, &TestGdxModule::PrivateImpl::privateCallableMethod, a, b, c);
158 ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
159 ASSERT_EQ(future.get(), loop_tid);
160 }
161
162 // Private implementation method executed on main loop and reposted
call_on_jni_repost(int loop_tid,int a,int b,int c)163 void TestGdxModule::call_on_jni_repost(int loop_tid, int a, int b, int c) {
164 private_impl_promise = std::promise<pid_t>();
165 auto future = private_impl_promise.get_future();
166 PostMethodOnJni(
167 pimpl_, &TestGdxModule::PrivateImpl::privateCallableRepostOnJniMethod, pimpl_, a, b, c);
168 ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
169 ASSERT_EQ(future.get(), loop_tid);
170 }
171
172 // Private implementation method executed on main loop recursively
call_on_jni_recurse(int loop_tid,int depth,int b,int c)173 void TestGdxModule::call_on_jni_recurse(int loop_tid, int depth, int b, int c) {
174 private_impl_promise = std::promise<pid_t>();
175 auto future = private_impl_promise.get_future();
176 PostMethodOnJni(
177 pimpl_,
178 &TestGdxModule::PrivateImpl::privateCallableRecursiveOnJniMethod,
179 pimpl_,
180 depth,
181 b,
182 c);
183 ASSERT_EQ(future.wait_for(std::chrono::seconds(3)), std::future_status::ready);
184 ASSERT_EQ(future.get(), loop_tid);
185 }
protected_method(int,int,int)186 void TestGdxModule::protected_method(int /* a */, int /* b */, int /* c */) {
187 protected_method_promise.set_value(base::PlatformThread::CurrentId());
188 }
189
IsStarted() const190 bool TestGdxModule::IsStarted() const {
191 return pimpl_ != nullptr;
192 }
193
Start()194 void TestGdxModule::Start() {
195 ASSERT_FALSE(IsStarted());
196 pimpl_ = std::make_shared<TestGdxModule::PrivateImpl>();
197 }
198
Stop()199 void TestGdxModule::Stop() {
200 ASSERT_TRUE(IsStarted());
201 pimpl_.reset();
202 }
203
ToString() const204 std::string TestGdxModule::ToString() const {
205 return "TestGdxModule";
206 }
207
208 const bluetooth::ModuleFactory TestGdxModule::Factory =
__anon96f0f1170202() 209 bluetooth::ModuleFactory([]() { return new TestGdxModule(); });
210
set_callback(common::ContextualCallback<void (std::string)> callback)211 void TestGdxModule::set_callback(common::ContextualCallback<void(std::string)> callback) {
212 call_many_ = callback;
213 }
214
set_once_callback(common::ContextualOnceCallback<void (std::string)> callback)215 void TestGdxModule::set_once_callback(common::ContextualOnceCallback<void(std::string)> callback) {
216 call_once_ = std::move(callback);
217 }
218
call_callback_on_handler(std::string message)219 void TestGdxModule::call_callback_on_handler(std::string message) {
220 GetHandler()->Post(common::BindOnce(
221 [](common::ContextualCallback<void(std::string)> callback, std::string message) {
222 callback(message);
223 },
224 call_many_,
225 message));
226 }
227
call_once_callback_on_handler(std::string message)228 void TestGdxModule::call_once_callback_on_handler(std::string message) {
229 GetHandler()->Post(common::BindOnce(
230 [](common::ContextualOnceCallback<void(std::string)> callback, std::string message) {
231 callback(message);
232 },
233 std::move(call_once_),
234 message));
235 }
236
call_callback_on_main(std::string message)237 void TestGdxModule::call_callback_on_main(std::string message) {
238 post_on_bt_main([message, this]() { call_many_(message); });
239 }
240
call_once_callback_on_main(std::string message)241 void TestGdxModule::call_once_callback_on_main(std::string message) {
242 post_on_bt_main([message, this]() { call_once_(message); });
243 }
244
call_callback_on_jni(std::string message)245 void TestGdxModule::call_callback_on_jni(std::string message) {
246 post_on_bt_jni([message, this]() { call_many_(message); });
247 }
248
call_once_callback_on_jni(std::string message)249 void TestGdxModule::call_once_callback_on_jni(std::string message) {
250 post_on_bt_jni([message, this]() { call_once_(message); });
251 }
252
253 //
254 // Module GDx Testing Below
255 //
256 class ModuleGdxTest : public ::testing::Test {
257 protected:
SetUp()258 void SetUp() override {
259 test_framework_tid_ = base::PlatformThread::CurrentId();
260 module_ = new TestGdxModule();
261 main_thread_start_up();
262 mainloop_tid_ = get_mainloop_tid();
263 jni_thread_startup();
264 jniloop_tid_ = get_jniloop_tid();
265 }
266
TearDown()267 void TearDown() override {
268 sync_main_handler();
269 main_thread_shut_down();
270 jni_thread_shutdown();
271 delete module_;
272 }
273
sync_main_handler()274 void sync_main_handler() {
275 std::promise promise = std::promise<void>();
276 std::future future = promise.get_future();
277 post_on_bt_main([&promise]() { promise.set_value(); });
278 future.wait_for(std::chrono::milliseconds(sync_timeout_in_ms));
279 };
280
sync_jni_handler()281 void sync_jni_handler() {
282 std::promise promise = std::promise<void>();
283 std::future future = promise.get_future();
284 post_on_bt_jni([&promise]() { promise.set_value(); });
285 future.wait_for(std::chrono::milliseconds(sync_timeout_in_ms));
286 };
287
get_mainloop_tid()288 static pid_t get_mainloop_tid() {
289 std::promise<pid_t> pid_promise = std::promise<pid_t>();
290 auto future = pid_promise.get_future();
291 post_on_bt_main([&pid_promise]() { pid_promise.set_value(base::PlatformThread::CurrentId()); });
292 return future.get();
293 }
294
get_jniloop_tid()295 static pid_t get_jniloop_tid() {
296 std::promise<pid_t> pid_promise = std::promise<pid_t>();
297 auto future = pid_promise.get_future();
298 post_on_bt_jni([&pid_promise]() { pid_promise.set_value(base::PlatformThread::CurrentId()); });
299 return future.get();
300 }
301
302 pid_t test_framework_tid_{-1};
303 pid_t mainloop_tid_{-1};
304 pid_t jniloop_tid_{-1};
305 TestModuleRegistry module_registry_;
306 TestGdxModule* module_;
307 };
308
309 class ModuleGdxWithStackTest : public ModuleGdxTest {
310 protected:
SetUp()311 void SetUp() override {
312 ModuleGdxTest::SetUp();
313 module_registry_.InjectTestModule(&TestGdxModule::Factory, module_ /* pass ownership */);
314 module_ = nullptr; // ownership is passed
315 handler_tid_ = get_handler_tid(module_registry_.GetTestModuleHandler(&TestGdxModule::Factory));
316 }
317
get_handler_tid(os::Handler * handler)318 static pid_t get_handler_tid(os::Handler* handler) {
319 std::promise<pid_t> handler_tid_promise = std::promise<pid_t>();
320 std::future<pid_t> future = handler_tid_promise.get_future();
321 handler->Post(common::BindOnce(
322 [](std::promise<pid_t> promise) { promise.set_value(base::PlatformThread::CurrentId()); },
323 std::move(handler_tid_promise)));
324 return future.get();
325 }
326
TearDown()327 void TearDown() override {
328 module_registry_.StopAll();
329 ModuleGdxTest::TearDown();
330 }
331
Mod()332 TestGdxModule* Mod() {
333 return module_registry_.GetModuleUnderTest<TestGdxModule>();
334 }
335
336 pid_t handler_tid_{-1};
337 };
338
TEST_F(ModuleGdxTest,nop)339 TEST_F(ModuleGdxTest, nop) {}
340
TEST_F(ModuleGdxTest,lifecycle)341 TEST_F(ModuleGdxTest, lifecycle) {
342 ::bluetooth::os::Thread* thread =
343 new bluetooth::os::Thread("Name", bluetooth::os::Thread::Priority::REAL_TIME);
344 ASSERT_FALSE(module_registry_.IsStarted<TestGdxModule>());
345 module_registry_.Start<TestGdxModule>(thread);
346 ASSERT_TRUE(module_registry_.IsStarted<TestGdxModule>());
347 module_registry_.StopAll();
348 ASSERT_FALSE(module_registry_.IsStarted<TestGdxModule>());
349 delete thread;
350 }
351
352 // internal handler
TEST_F(ModuleGdxWithStackTest,call_on_handler_protected_method)353 TEST_F(ModuleGdxWithStackTest, call_on_handler_protected_method) {
354 Mod()->call_on_handler_protected_method(handler_tid_, 1, 2, 3);
355 }
356
TEST_F(ModuleGdxWithStackTest,test_call_on_main)357 TEST_F(ModuleGdxWithStackTest, test_call_on_main) {
358 Mod()->call_on_main(mainloop_tid_, 1, 2, 3);
359 }
360
TEST_F(ModuleGdxWithStackTest,test_call_gdx_external_function_on_main)361 TEST_F(ModuleGdxWithStackTest, test_call_gdx_external_function_on_main) {
362 Mod()->call_on_main_external_function(mainloop_tid_, 1, 2.3, 'c');
363 }
364
TEST_F(ModuleGdxWithStackTest,test_call_on_main_repost)365 TEST_F(ModuleGdxWithStackTest, test_call_on_main_repost) {
366 Mod()->call_on_main_repost(mainloop_tid_, 1, 2, 3);
367 }
368
TEST_F(ModuleGdxWithStackTest,test_call_on_main_recurse)369 TEST_F(ModuleGdxWithStackTest, test_call_on_main_recurse) {
370 Mod()->call_on_main_recurse(mainloop_tid_, 1, 2, 3);
371 }
372
TEST_F(ModuleGdxWithStackTest,test_call_on_jni)373 TEST_F(ModuleGdxWithStackTest, test_call_on_jni) {
374 Mod()->call_on_jni(jniloop_tid_, 1, 2, 3);
375 }
376
TEST_F(ModuleGdxWithStackTest,test_call_gdx_external_function_on_jni)377 TEST_F(ModuleGdxWithStackTest, test_call_gdx_external_function_on_jni) {
378 Mod()->call_on_jni_external_function(jniloop_tid_, 1, 2.3, 'c');
379 }
380
TEST_F(ModuleGdxWithStackTest,test_call_on_jni_repost)381 TEST_F(ModuleGdxWithStackTest, test_call_on_jni_repost) {
382 Mod()->call_on_jni_repost(jniloop_tid_, 1, 2, 3);
383 }
384
TEST_F(ModuleGdxWithStackTest,test_call_on_jni_recurse)385 TEST_F(ModuleGdxWithStackTest, test_call_on_jni_recurse) {
386 Mod()->call_on_jni_recurse(jniloop_tid_, 1, 2, 3);
387 }
388
389 class ModuleGdxWithInstrumentedCallback : public ModuleGdxWithStackTest {
390 protected:
SetUp()391 void SetUp() override {
392 ModuleGdxWithStackTest::SetUp();
393 }
394
TearDown()395 void TearDown() override {
396 ModuleGdxWithStackTest::TearDown();
397 }
398
399 // A helper class to promise/future for synchronization
400 class Promises {
401 public:
402 std::promise<std::string> result;
403 std::future<std::string> result_future = result.get_future();
404 std::promise<void> blocking;
405 std::future<void> blocking_future = blocking.get_future();
406 std::promise<void> unblock;
407 std::future<void> unblock_future = unblock.get_future();
408 };
409
410 class InstrumentedCallback {
411 public:
412 Promises promises;
413 common::ContextualCallback<void(std::string)> callback;
414 };
415
416 class InstrumentedOnceCallback {
417 public:
418 Promises promises;
419 common::ContextualOnceCallback<void(std::string)> callback;
420 };
421
GetNewCallbackOnMain()422 std::unique_ptr<InstrumentedCallback> GetNewCallbackOnMain() {
423 auto to_return = std::make_unique<InstrumentedCallback>();
424 to_return->callback = get_main()->Bind(
425 [](std::promise<std::string>* promise_ptr,
426 std::promise<void>* blocking,
427 std::future<void>* unblock,
428 std::string result) {
429 // Tell the test that this callback is running (and blocking)
430 blocking->set_value();
431 // Block until the test is ready to continue
432 ASSERT_EQ(std::future_status::ready, unblock->wait_for(std::chrono::seconds(1)));
433 // Send the result back to the test
434 promise_ptr->set_value(result);
435 log::info("set_value {}", result);
436 },
437 &to_return->promises.result,
438 &to_return->promises.blocking,
439 &to_return->promises.unblock_future);
440
441 return to_return;
442 }
443
GetNewOnceCallbackOnMain()444 std::unique_ptr<InstrumentedOnceCallback> GetNewOnceCallbackOnMain() {
445 auto to_return = std::make_unique<InstrumentedOnceCallback>();
446 to_return->callback = get_main()->BindOnce(
447 [](std::promise<std::string>* promise_ptr,
448 std::promise<void>* blocking,
449 std::future<void>* unblock,
450 std::string result) {
451 blocking->set_value();
452 ASSERT_EQ(std::future_status::ready, unblock->wait_for(std::chrono::seconds(1)));
453 promise_ptr->set_value(result);
454 log::info("set_value {}", result);
455 },
456 &to_return->promises.result,
457 &to_return->promises.blocking,
458 &to_return->promises.unblock_future);
459
460 return to_return;
461 }
462 };
463
TEST_F(ModuleGdxWithInstrumentedCallback,test_call_callback_on_handler)464 TEST_F(ModuleGdxWithInstrumentedCallback, test_call_callback_on_handler) {
465 auto instrumented = GetNewCallbackOnMain();
466 Mod()->set_callback(instrumented->callback);
467
468 // Enqueue the callback and wait for it to block on main thread
469 std::string result = "This was called on the handler";
470 Mod()->call_callback_on_handler(result);
471 ASSERT_EQ(
472 std::future_status::ready,
473 instrumented->promises.blocking_future.wait_for(std::chrono::seconds(1)));
474 log::info("Waiting");
475
476 // Enqueue something else on the main thread and verify that it hasn't run
477 static auto second_task_promise = std::promise<void>();
478 auto final_future = second_task_promise.get_future();
479 do_in_main_thread(
480 FROM_HERE,
481 common::BindOnce(
482 [](std::promise<void> promise) {
483 promise.set_value();
484 log::info("Finally");
485 },
486 std::move(second_task_promise)));
487 ASSERT_EQ(std::future_status::timeout, final_future.wait_for(std::chrono::milliseconds(1)));
488
489 // Let the callback start
490 instrumented->promises.unblock.set_value();
491 ASSERT_EQ(
492 std::future_status::ready,
493 instrumented->promises.result_future.wait_for(std::chrono::seconds(1)));
494 ASSERT_EQ(result, instrumented->promises.result_future.get());
495
496 // Let the second task finish
497 ASSERT_EQ(std::future_status::ready, final_future.wait_for(std::chrono::seconds(1)));
498 }
499
TEST_F(ModuleGdxWithInstrumentedCallback,test_call_once_callback_on_handler)500 TEST_F(ModuleGdxWithInstrumentedCallback, test_call_once_callback_on_handler) {
501 auto instrumented = GetNewOnceCallbackOnMain();
502 Mod()->set_once_callback(std::move(instrumented->callback));
503
504 // Enqueue the callback and wait for it to block on main thread
505 std::string result = "This was called on the handler";
506 Mod()->call_once_callback_on_handler(result);
507 ASSERT_EQ(
508 std::future_status::ready,
509 instrumented->promises.blocking_future.wait_for(std::chrono::seconds(1)));
510 log::info("Waiting");
511
512 // Enqueue something else on the main thread and verify that it hasn't run
513 static auto second_task_promise = std::promise<void>();
514 auto final_future = second_task_promise.get_future();
515 do_in_main_thread(
516 FROM_HERE,
517 common::BindOnce(
518 [](std::promise<void> promise) {
519 promise.set_value();
520 log::info("Finally");
521 },
522 std::move(second_task_promise)));
523 ASSERT_EQ(std::future_status::timeout, final_future.wait_for(std::chrono::milliseconds(1)));
524
525 // Let the callback start
526 instrumented->promises.unblock.set_value();
527 ASSERT_EQ(
528 std::future_status::ready,
529 instrumented->promises.result_future.wait_for(std::chrono::seconds(1)));
530 ASSERT_EQ(result, instrumented->promises.result_future.get());
531
532 // Let the second task finish
533 ASSERT_EQ(std::future_status::ready, final_future.wait_for(std::chrono::seconds(1)));
534 }
535
TEST_F(ModuleGdxWithInstrumentedCallback,test_call_callback_on_main)536 TEST_F(ModuleGdxWithInstrumentedCallback, test_call_callback_on_main) {
537 auto instrumented = GetNewCallbackOnMain();
538 Mod()->set_callback(instrumented->callback);
539
540 // Enqueue the callback and wait for it to block on main thread
541 std::string result = "This was called on the main";
542 Mod()->call_callback_on_main(result);
543 ASSERT_EQ(
544 std::future_status::ready,
545 instrumented->promises.blocking_future.wait_for(std::chrono::seconds(1)));
546 log::info("Waiting");
547
548 // Enqueue something else on the main thread and verify that it hasn't run
549 static auto second_task_promise = std::promise<void>();
550 auto final_future = second_task_promise.get_future();
551 do_in_main_thread(
552 FROM_HERE,
553 common::BindOnce(
554 [](std::promise<void> promise) {
555 promise.set_value();
556 log::info("Finally");
557 },
558 std::move(second_task_promise)));
559 ASSERT_EQ(std::future_status::timeout, final_future.wait_for(std::chrono::milliseconds(1)));
560
561 // Let the callback start
562 instrumented->promises.unblock.set_value();
563 ASSERT_EQ(
564 std::future_status::ready,
565 instrumented->promises.result_future.wait_for(std::chrono::seconds(1)));
566 ASSERT_EQ(result, instrumented->promises.result_future.get());
567
568 // Let the second task finish
569 ASSERT_EQ(std::future_status::ready, final_future.wait_for(std::chrono::seconds(1)));
570 }
571
TEST_F(ModuleGdxWithInstrumentedCallback,test_call_once_callback_on_main)572 TEST_F(ModuleGdxWithInstrumentedCallback, test_call_once_callback_on_main) {
573 auto instrumented = GetNewOnceCallbackOnMain();
574 Mod()->set_once_callback(std::move(instrumented->callback));
575
576 // Enqueue the callback and wait for it to block on main thread
577 std::string result = "This was called on the main";
578 Mod()->call_once_callback_on_main(result);
579 ASSERT_EQ(
580 std::future_status::ready,
581 instrumented->promises.blocking_future.wait_for(std::chrono::seconds(1)));
582 log::info("Waiting");
583
584 // Enqueue something else on the main thread and verify that it hasn't run
585 static auto second_task_promise = std::promise<void>();
586 auto final_future = second_task_promise.get_future();
587 do_in_main_thread(
588 FROM_HERE,
589 common::BindOnce(
590 [](std::promise<void> promise) {
591 promise.set_value();
592 log::info("Finally");
593 },
594 std::move(second_task_promise)));
595 ASSERT_EQ(std::future_status::timeout, final_future.wait_for(std::chrono::milliseconds(1)));
596
597 // Let the callback start
598 instrumented->promises.unblock.set_value();
599 ASSERT_EQ(
600 std::future_status::ready,
601 instrumented->promises.result_future.wait_for(std::chrono::seconds(1)));
602 ASSERT_EQ(result, instrumented->promises.result_future.get());
603
604 // Let the second task finish
605 ASSERT_EQ(std::future_status::ready, final_future.wait_for(std::chrono::seconds(1)));
606 }
607
TEST_F(ModuleGdxWithInstrumentedCallback,test_call_callback_on_jni)608 TEST_F(ModuleGdxWithInstrumentedCallback, test_call_callback_on_jni) {
609 auto instrumented = GetNewCallbackOnMain();
610 Mod()->set_callback(instrumented->callback);
611
612 // Enqueue the callback and wait for it to block on main thread
613 std::string result = "This was called on the jni";
614 Mod()->call_callback_on_jni(result);
615 ASSERT_EQ(
616 std::future_status::ready,
617 instrumented->promises.blocking_future.wait_for(std::chrono::seconds(1)));
618 log::info("Waiting");
619
620 // Enqueue something else on the main thread and verify that it hasn't run
621 static auto second_task_promise = std::promise<void>();
622 auto final_future = second_task_promise.get_future();
623 do_in_main_thread(
624 FROM_HERE,
625 common::BindOnce(
626 [](std::promise<void> promise) {
627 promise.set_value();
628 log::info("Finally");
629 },
630 std::move(second_task_promise)));
631 ASSERT_EQ(std::future_status::timeout, final_future.wait_for(std::chrono::milliseconds(1)));
632
633 // Let the callback start
634 instrumented->promises.unblock.set_value();
635 ASSERT_EQ(
636 std::future_status::ready,
637 instrumented->promises.result_future.wait_for(std::chrono::seconds(1)));
638 ASSERT_EQ(result, instrumented->promises.result_future.get());
639
640 // Let the second task finish
641 ASSERT_EQ(std::future_status::ready, final_future.wait_for(std::chrono::seconds(1)));
642 }
643
TEST_F(ModuleGdxWithInstrumentedCallback,test_call_once_callback_on_jni)644 TEST_F(ModuleGdxWithInstrumentedCallback, test_call_once_callback_on_jni) {
645 auto instrumented = GetNewOnceCallbackOnMain();
646 Mod()->set_once_callback(std::move(instrumented->callback));
647
648 // Enqueue the callback and wait for it to block on main thread
649 std::string result = "This was called on the jni";
650 Mod()->call_once_callback_on_jni(result);
651 ASSERT_EQ(
652 std::future_status::ready,
653 instrumented->promises.blocking_future.wait_for(std::chrono::seconds(1)));
654 log::info("Waiting");
655
656 // Enqueue something else on the main thread and verify that it hasn't run
657 static auto second_task_promise = std::promise<void>();
658 auto final_future = second_task_promise.get_future();
659 do_in_main_thread(
660 FROM_HERE,
661 common::BindOnce(
662 [](std::promise<void> promise) {
663 promise.set_value();
664 log::info("Finally");
665 },
666 std::move(second_task_promise)));
667 ASSERT_EQ(std::future_status::timeout, final_future.wait_for(std::chrono::milliseconds(1)));
668
669 // Let the callback start
670 instrumented->promises.unblock.set_value();
671 ASSERT_EQ(
672 std::future_status::ready,
673 instrumented->promises.result_future.wait_for(std::chrono::seconds(1)));
674 ASSERT_EQ(result, instrumented->promises.result_future.get());
675
676 // Let the second task finish
677 ASSERT_EQ(std::future_status::ready, final_future.wait_for(std::chrono::seconds(1)));
678 }
679