#include #include #include #include #include #include using namespace mbgl; using namespace std::chrono_literals; TEST(Actor, Construction) { // Construction is currently synchronous. It may become asynchronous in the future. struct Test { Test(ActorRef, bool& constructed) { constructed = true; }; }; ThreadPool pool { 1 }; bool constructed = false; Actor test(pool, std::ref(constructed)); EXPECT_TRUE(constructed); } TEST(Actor, DestructionClosesMailbox) { // Destruction blocks until the actor is not receiving. struct Test { std::promise promise; std::future future; std::atomic waited; Test(ActorRef, std::promise promise_, std::future future_) : promise(std::move(promise_)), future(std::move(future_)), waited(false) { } ~Test() { EXPECT_TRUE(waited.load()); } void wait() { promise.set_value(); future.wait(); std::this_thread::sleep_for(1ms); waited = true; } }; ThreadPool pool { 1 }; std::promise enteredPromise; std::future enteredFuture = enteredPromise.get_future(); std::promise exitingPromise; std::future exitingFuture = exitingPromise.get_future(); Actor test(pool, std::move(enteredPromise), std::move(exitingFuture)); test.invoke(&Test::wait); enteredFuture.wait(); exitingPromise.set_value(); } TEST(Actor, OrderedMailbox) { // Messages are processed in order. struct Test { int last = 0; std::promise promise; Test(ActorRef, std::promise promise_) : promise(std::move(promise_)) { } void receive(int i) { EXPECT_EQ(i, last + 1); last = i; } void end() { promise.set_value(); } }; ThreadPool pool { 1 }; std::promise endedPromise; std::future endedFuture = endedPromise.get_future(); Actor test(pool, std::move(endedPromise)); for (auto i = 1; i <= 10; ++i) { test.invoke(&Test::receive, i); } test.invoke(&Test::end); endedFuture.wait(); } TEST(Actor, NonConcurrentMailbox) { // An individual actor is never itself concurrent. struct Test { int last = 0; std::promise promise; Test(ActorRef, std::promise promise_) : promise(std::move(promise_)) { } void receive(int i) { EXPECT_EQ(i, last + 1); last = i; std::this_thread::sleep_for(1ms); } void end() { promise.set_value(); } }; ThreadPool pool { 10 }; std::promise endedPromise; std::future endedFuture = endedPromise.get_future(); Actor test(pool, std::move(endedPromise)); for (auto i = 1; i <= 10; ++i) { test.invoke(&Test::receive, i); } test.invoke(&Test::end); endedFuture.wait(); }