TEST(FutureTest, Future) { Promise<bool> promise; promise.set(true); ASSERT_TRUE(promise.future().isReady()); EXPECT_TRUE(promise.future().get()); }
TEST(AwaitTest, AwaitSingleDiscard) { Promise<int> promise; auto bar = [&]() { return promise.future(); }; auto foo = [&]() { return await(bar()) .then([](const Future<int>& f) { return f .then([](int i) { return stringify(i); }); }); }; Future<string> future = foo(); future.discard(); AWAIT_DISCARDED(future); EXPECT_TRUE(promise.future().hasDiscard()); }
void futureCanDowncastToVoid() { Promise<int> promise; Future<int> future1 = promise.future(); Future<void> future2 = promise.future(); Future<void> future3 = future1; }
// This test ensures that destroy can be called at the end of the // launch loop. The composing containerizer still calls the // underlying containerizer's destroy (because it's not sure // if the containerizer can handle the type of container being // launched). If the launch is not supported by any containerizers // both the launch and destroy futures should be false. TEST_F(ComposingContainerizerTest, DestroyAfterLaunchLoop) { vector<Containerizer*> containerizers; MockContainerizer* mockContainerizer1 = new MockContainerizer(); containerizers.push_back(mockContainerizer1); ComposingContainerizer containerizer(containerizers); ContainerID containerId; containerId.set_value("container"); TaskInfo taskInfo; ExecutorInfo executorInfo; SlaveID slaveId; std::map<std::string, std::string> environment; Promise<bool> launchPromise; EXPECT_CALL(*mockContainerizer1, launch(_, _, _, _, _, _, _, _)) .WillOnce(Return(launchPromise.future())); Future<Nothing> destroy; Promise<bool> destroyPromise; EXPECT_CALL(*mockContainerizer1, destroy(_)) .WillOnce(DoAll(FutureSatisfy(&destroy), Return(destroyPromise.future()))); Future<bool> launched = containerizer.launch( containerId, taskInfo, executorInfo, "dir", "user", slaveId, environment, false); Resources resources = Resources::parse("cpus:1;mem:256").get(); EXPECT_TRUE(launched.isPending()); Future<bool> destroyed = containerizer.destroy(containerId); // We make sure the destroy is being called on the containerizer. AWAIT_READY(destroy); launchPromise.set(false); destroyPromise.set(false); // `launch` should return false and `destroyed` should return false // because none of the containerizers support the launch. AWAIT_EXPECT_EQ(false, launched); AWAIT_EXPECT_EQ(false, destroyed); }
Future<Option<MasterInfo>> detect( const Option<MasterInfo>& previous = None()) { if (leader != previous) { return leader; } Promise<Option<MasterInfo>>* promise = new Promise<Option<MasterInfo>>(); promise->future() .onDiscard(defer(self(), &Self::discard, promise->future())); promises.insert(promise); return promise->future(); }
TEST(FutureTest, UndiscardableFuture) { Promise<int> promise; Future<int> f = undiscardable(promise.future()); f.discard(); EXPECT_TRUE(f.hasDiscard()); EXPECT_FALSE(promise.future().hasDiscard()); promise.set(42); AWAIT_ASSERT_EQ(42, f); }
Future<int> create( const string& path, const string& data, const ACL_vector& acl, int flags, string* result) { Promise<int>* promise = new Promise<int>(); Future<int> future = promise->future(); tuple<Promise<int>*, string*>* args = new tuple<Promise<int>*, string*>(promise, result); int ret = zoo_acreate( zh, path.c_str(), data.data(), data.size(), &acl, flags, stringCompletion, args); if (ret != ZOK) { delete promise; delete args; return ret; } return future; }
Future<int> set(const string& path, const string& data, int version) { Promise<int>* promise = new Promise<int>(); Future<int> future = promise->future(); tuple<Promise<int>*, Stat*>* args = new tuple<Promise<int>*, Stat*>(promise, nullptr); int ret = zoo_aset( zh, path.c_str(), data.data(), data.size(), version, statCompletion, args); if (ret != ZOK) { delete promise; delete args; return ret; } return future; }
FutureSync<void> TransportSocketCache::disconnect(MessageSocketPtr socket) { Promise<void> promiseSocketRemoved; { auto syncDisconnectInfos = _disconnectInfos.synchronize(); // TODO: Remove Promise<void>{} when get rid of VS2013. syncDisconnectInfos->push_back(DisconnectInfo{socket, Promise<void>{}}); promiseSocketRemoved = syncDisconnectInfos->back().promiseSocketRemoved; } // We wait that the socket has been disconnected _and_ the `disconnected` // signal has been received by the cache. FutureBarrier<void> barrier; barrier.addFuture(promiseSocketRemoved.future()); barrier.addFuture(socket->disconnect()); Promise<void> promise; return barrier.future().then([=](const std::vector<Future<void>>& v) mutable { const auto isInError = [](const Future<void>& f) { return f.hasError(); }; if (std::any_of(begin(v), end(v), isInError)) { promise.setError("disconnect error"); return; } promise.setValue(0); }); }
TEST(FutureTest, Chain) { Future<string> s = readyFuture() .then(lambda::bind(&second, lambda::_1)) .then(lambda::bind(&third, lambda::_1)); s.await(); ASSERT_TRUE(s.isReady()); EXPECT_EQ("true", s.get()); s = failedFuture() .then(lambda::bind(&second, lambda::_1)) .then(lambda::bind(&third, lambda::_1)); s.await(); ASSERT_TRUE(s.isFailed()); Promise<bool> promise; s = pendingFuture(promise.future()) .then(lambda::bind(&second, lambda::_1)) .then(lambda::bind(&third, lambda::_1)); ASSERT_TRUE(s.isPending()); promise.discard(); AWAIT_DISCARDED(s); }
TEST(FutureTest, CallableOnce) { Promise<Nothing> promise; promise.set(Nothing()); Future<int> future = promise.future() .then(lambda::partial( [](std::unique_ptr<int>&& o) { return *o; }, std::unique_ptr<int>(new int(42)))); ASSERT_TRUE(future.isReady()); EXPECT_EQ(42, future.get()); int n = 0; future = promise.future() .onReady(lambda::partial( [&n](std::unique_ptr<int> o) { n += *o; }, std::unique_ptr<int>(new int(1)))) .onAny(lambda::partial( [&n](std::unique_ptr<int>&& o) { n += *o; }, std::unique_ptr<int>(new int(10)))) .onFailed(lambda::partial( [&n](const std::unique_ptr<int>& o) { n += *o; }, std::unique_ptr<int>(new int(100)))) .onDiscard(lambda::partial( [&n](std::unique_ptr<int>&& o) { n += *o; }, std::unique_ptr<int>(new int(1000)))) .onDiscarded(lambda::partial( [&n](std::unique_ptr<int>&& o) { n += *o; }, std::unique_ptr<int>(new int(10000)))) .then([&n]() { return n; }); ASSERT_TRUE(future.isReady()); EXPECT_EQ(11, future.get()); }
inline Future<std::list<T> > collect( std::list<Future<T> >& futures, const Option<Timeout>& timeout) { Promise<std::list<T> >* promise = new Promise<std::list<T> >(); Future<std::list<T> > future = promise->future(); spawn(new internal::CollectProcess<T>(futures, timeout, promise), true); return future; }
// This test checks if destroy is called while container is being // launched, the composing containerizer still calls the underlying // containerizer's destroy and skip calling the rest of the // containerizers. TEST_F(ComposingContainerizerTest, DestroyWhileLaunching) { vector<Containerizer*> containerizers; MockContainerizer* mockContainerizer = new MockContainerizer(); MockContainerizer* mockContainerizer2 = new MockContainerizer(); containerizers.push_back(mockContainerizer); containerizers.push_back(mockContainerizer2); ComposingContainerizer containerizer(containerizers); ContainerID containerId; containerId.set_value("container"); TaskInfo taskInfo; ExecutorInfo executorInfo; SlaveID slaveId; std::map<std::string, std::string> environment; Promise<bool> launchPromise; EXPECT_CALL(*mockContainerizer, launch(_, _, _, _, _, _, _, _)) .WillOnce(Return(launchPromise.future())); Future<Nothing> destroy; EXPECT_CALL(*mockContainerizer, destroy(_)) .WillOnce(FutureSatisfy(&destroy)); Future<bool> launch = containerizer.launch( containerId, taskInfo, executorInfo, "dir", "user", slaveId, environment, false); Resources resources = Resources::parse("cpus:1;mem:256").get(); EXPECT_TRUE(launch.isPending()); containerizer.destroy(containerId); EXPECT_CALL(*mockContainerizer2, launch(_, _, _, _, _, _, _, _)) .Times(0); // We make sure the destroy is being called on the first containerizer. // The second containerizer shouldn't be called as well since the // container is already destroyed. AWAIT_READY(destroy); launchPromise.set(false); AWAIT_FAILED(launch); }
TEST(Process, then) { Promise<int*> promise; int i = 42; promise.set(&i); Future<std::string> future = promise.future() .then(std::tr1::bind(&itoa1, std::tr1::placeholders::_1)); ASSERT_TRUE(future.isReady()); EXPECT_EQ("42", future.get()); future = promise.future() .then(std::tr1::bind(&itoa2, std::tr1::placeholders::_1)); ASSERT_TRUE(future.isReady()); EXPECT_EQ("42", future.get()); }
TEST(FutureTest, Then) { Promise<int*> promise; int i = 42; promise.set(&i); Future<string> future = promise.future() .then(lambda::bind(&itoa1, lambda::_1)); ASSERT_TRUE(future.isReady()); EXPECT_EQ("42", future.get()); future = promise.future() .then(lambda::bind(&itoa2, lambda::_1)); ASSERT_TRUE(future.isReady()); EXPECT_EQ("42", future.get()); }
TEST(FutureTest, UndiscardableLambda) { Promise<int> promise; Future<int> f = Future<int>(2) .then(undiscardable([&](int multiplier) { return promise.future() .then([=](int i) { return i * multiplier; }); })); f.discard(); EXPECT_TRUE(f.hasDiscard()); EXPECT_FALSE(promise.future().hasDiscard()); promise.set(42); AWAIT_ASSERT_EQ(84, f); }
TEST(LoopTest, DiscardIterate) { Promise<int> promise; promise.future().onDiscard([&]() { promise.discard(); }); Future<Nothing> future = loop( [&]() { return promise.future(); }, [&](int i) -> ControlFlow<Nothing> { return Break(); }); EXPECT_TRUE(future.isPending()); future.discard(); AWAIT_DISCARDED(future); EXPECT_TRUE(promise.future().hasDiscard()); }
Future<Option<int64_t> > GroupProcess::session() { if (error.isSome()) { Promise<Option<int64_t> > promise; promise.fail(error.get()); return promise.future(); } else if (state != CONNECTED) { return None(); } return Option<int64_t>::some(zk->getSessionId()); }
Future<Nothing> acquire() { if (!promises.empty()) { // Need to wait for others to get permits first. Promise<Nothing>* promise = new Promise<Nothing>(); promises.push_back(promise); return promise->future() .onDiscard(defer(self(), &Self::discard, promise->future())); } if (timeout.remaining() > Seconds(0)) { // Need to wait a bit longer, but first one in the queue. Promise<Nothing>* promise = new Promise<Nothing>(); promises.push_back(promise); delay(timeout.remaining(), self(), &Self::_acquire); return promise->future() .onDiscard(defer(self(), &Self::discard, promise->future())); } // No need to wait! timeout = Seconds(1) / permitsPerSecond; return Nothing(); }
Future<Option<Group::Membership> > LeaderDetectorProcess::detect( const Option<Group::Membership>& previous) { // Return immediately if the incumbent leader is different from the // expected. if (leader != previous) { return leader; } // Otherwise wait for the next election result. Promise<Option<Group::Membership> >* promise = new Promise<Option<Group::Membership> >(); promises.insert(promise); return promise->future(); }
TEST(FutureTest, RecoverFailed) { Promise<int> promise; Future<string> future = promise.future() .then([]() -> string { return "hello"; }) .recover([](const Future<string>&) -> string { return "world"; }); promise.fail("Failure"); AWAIT_EQ("world", future); }
// This test ensures that a framework that is removed while // authorization for registration is in progress is properly handled. TEST_F(MasterAuthorizationTest, FrameworkRemovedBeforeRegistration) { MockAuthorizer authorizer; Try<PID<Master> > master = StartMaster(&authorizer); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); // Return a pending future from authorizer. Future<Nothing> future; Promise<bool> promise; EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::ReceiveOffers&>())) .WillOnce(DoAll(FutureSatisfy(&future), Return(promise.future()))); driver.start(); // Wait until authorization is in progress. AWAIT_READY(future); // Stop the framework. // At this point the framework is disconnected but the master does // not take any action because the framework is not in its map yet. driver.stop(); driver.join(); // Settle the clock here to ensure master handles the framework // 'exited' event. Clock::pause(); Clock::settle(); Clock::resume(); Future<Nothing> frameworkRemoved = FUTURE_DISPATCH(_, &AllocatorProcess::frameworkRemoved); // Now complete authorization. promise.set(true); // When the master tries to link to a non-existent framework PID // it should realize the framework is gone and remove it. AWAIT_READY(frameworkRemoved); Shutdown(); }
Future<int> remove(const string& path, int version) { Promise<int>* promise = new Promise<int>(); Future<int> future = promise->future(); tuple<Promise<int>*>* args = new tuple<Promise<int>*>(promise); int ret = zoo_adelete(zh, path.c_str(), version, voidCompletion, args); if (ret != ZOK) { delete promise; delete args; return ret; } return future; }
Future<int> get(const string& path, bool watch, string* result, Stat* stat) { Promise<int>* promise = new Promise<int>(); Future<int> future = promise->future(); tuple<Promise<int>*, string*, Stat*>* args = new tuple<Promise<int>*, string*, Stat*>(promise, result, stat); int ret = zoo_aget(zh, path.c_str(), watch, dataCompletion, args); if (ret != ZOK) { delete promise; delete args; return ret; } return future; }
Future<int> authenticate(const string& scheme, const string& credentials) { Promise<int>* promise = new Promise<int>(); Future<int> future = promise->future(); tuple<Promise<int>*>* args = new tuple<Promise<int>*>(promise); int ret = zoo_add_auth(zh, scheme.c_str(), credentials.data(), credentials.size(), voidCompletion, args); if (ret != ZOK) { delete promise; delete args; return ret; } return future; }
Future<Option<Group::Membership> > LeaderDetectorProcess::detect( const Option<Group::Membership> &previous) { // Return immediately if the detector is no longer operational due // to the non-retryable error. if (error.isSome()) { return Failure(error.get().message); } // Return immediately if the incumbent leader is different from the // expected. if (leader != previous) { return leader; } // Otherwise wait for the next election result. Promise < Option<Group::Membership> > *promise = new Promise <Option<Group::Membership>>(); promises.insert(promise); return promise->future(); }
Future<int> getChildren(const string& path, bool watch, vector<string>* results) { Promise<int>* promise = new Promise<int>(); Future<int> future = promise->future(); tuple<Promise<int>*, vector<string>*>* args = new tuple<Promise<int>*, vector<string>*>(promise, results); int ret = zoo_aget_children(zh, path.c_str(), watch, stringsCompletion, args); if (ret != ZOK) { delete promise; delete args; return ret; } return future; }
TEST(FutureTest, FromTryFuture) { Try<Future<int>> t = 1; Future<int> future = t; ASSERT_TRUE(future.isReady()); EXPECT_EQ(1, future.get()); Promise<int> p; t = p.future(); future = t; ASSERT_TRUE(future.isPending()); p.set(1); ASSERT_TRUE(future.isReady()); EXPECT_EQ(1, future.get()); t = Error("error"); future = t; ASSERT_TRUE(future.isFailed()); EXPECT_EQ(t.error(), future.failure()); }
// Checks that completing a promise will keep the 'after' callback // from executing. TEST(FutureTest, After2) { Clock::pause(); std::atomic_bool executed(false); Promise<Nothing> promise; Future<Nothing> future = promise.future() .after(Hours(42), lambda::bind(&after, &executed, lambda::_1)); EXPECT_TRUE(future.isPending()); // Only advanced halfway, future should remain pending. Clock::advance(Hours(21)); EXPECT_TRUE(future.isPending()); // Even doing a discard on the future should keep it pending. future.discard(); EXPECT_TRUE(future.isPending()); // Now set the promise, the 'after' timer should be cancelled and // the pending future should be completed. promise.set(Nothing()); AWAIT_READY(future); // Advancing time the rest of the way should not cause the 'after' // callback to execute. Clock::advance(Hours(21)); EXPECT_FALSE(executed.load()); Clock::resume(); }
// This test ensures that destroy can be called while in the // launch loop. The composing containerizer still calls the // underlying containerizer's destroy (because it's not sure // if the containerizer can handle the type of container being // launched). If the launch is not supported by the 1st containerizer, // the composing containerizer should stop the launch loop and // set the value of destroy future to true. TEST_F(ComposingContainerizerTest, DestroyDuringUnsupportedLaunchLoop) { vector<Containerizer*> containerizers; MockContainerizer* mockContainerizer1 = new MockContainerizer(); MockContainerizer* mockContainerizer2 = new MockContainerizer(); containerizers.push_back(mockContainerizer1); containerizers.push_back(mockContainerizer2); ComposingContainerizer containerizer(containerizers); ContainerID containerId; containerId.set_value("container"); TaskInfo taskInfo; ExecutorInfo executorInfo; SlaveID slaveId; std::map<std::string, std::string> environment; Promise<bool> launchPromise; EXPECT_CALL(*mockContainerizer1, launch(_, _, _, _, _, _, _, _)) .WillOnce(Return(launchPromise.future())); Future<Nothing> destroy; Promise<bool> destroyPromise; EXPECT_CALL(*mockContainerizer1, destroy(_)) .WillOnce(DoAll(FutureSatisfy(&destroy), Return(destroyPromise.future()))); Future<bool> launched = containerizer.launch( containerId, taskInfo, executorInfo, "dir", "user", slaveId, environment, false); Resources resources = Resources::parse("cpus:1;mem:256").get(); EXPECT_TRUE(launched.isPending()); Future<bool> destroyed = containerizer.destroy(containerId); EXPECT_CALL(*mockContainerizer2, launch(_, _, _, _, _, _, _, _)) .Times(0); // We make sure the destroy is being called on the first containerizer. // The second containerizer shouldn't be called as well since the // container is already destroyed. AWAIT_READY(destroy); launchPromise.set(false); destroyPromise.set(false); // `launched` should be a failure and `destroyed` should be true // because the launch was stopped from being tried on the 2nd // containerizer because of the destroy. AWAIT_FAILED(launched); AWAIT_EXPECT_EQ(true, destroyed); }