• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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