inline void set_result(Promise& p, T&& t) { p.set_result(std::forward<T>(t)); }
TEST(Wait, waitWithDuration) { { Promise<int> p; Future<int> f = p.getFuture(); f.wait(milliseconds(1)); EXPECT_FALSE(f.isReady()); p.setValue(1); EXPECT_TRUE(f.isReady()); } { Promise<int> p; Future<int> f = p.getFuture(); p.setValue(1); f.wait(milliseconds(1)); EXPECT_TRUE(f.isReady()); } { vector<Future<bool>> v_fb; v_fb.push_back(makeFuture(true)); v_fb.push_back(makeFuture(false)); auto f = collectAll(v_fb); f.wait(milliseconds(1)); EXPECT_TRUE(f.isReady()); EXPECT_EQ(2, f.value().size()); } { vector<Future<bool>> v_fb; Promise<bool> p1; Promise<bool> p2; v_fb.push_back(p1.getFuture()); v_fb.push_back(p2.getFuture()); auto f = collectAll(v_fb); f.wait(milliseconds(1)); EXPECT_FALSE(f.isReady()); p1.setValue(true); EXPECT_FALSE(f.isReady()); p2.setValue(true); EXPECT_TRUE(f.isReady()); } { auto f = makeFuture().wait(milliseconds(1)); EXPECT_TRUE(f.isReady()); } { Promise<Unit> p; auto start = std::chrono::steady_clock::now(); auto f = p.getFuture().wait(milliseconds(100)); auto elapsed = std::chrono::steady_clock::now() - start; EXPECT_GE(elapsed, milliseconds(100)); EXPECT_FALSE(f.isReady()); p.setValue(); EXPECT_TRUE(f.isReady()); } { // Try to trigger the race where the resultant Future is not yet complete // even if we didn't hit the timeout, and make sure we deal with it properly Promise<Unit> p; folly::Baton<> b; auto t = std::thread([&]{ b.post(); /* sleep override */ std::this_thread::sleep_for(milliseconds(100)); p.setValue(); }); b.wait(); auto f = p.getFuture().wait(std::chrono::seconds(3600)); EXPECT_TRUE(f.isReady()); t.join(); } }
// This test ensures that reconciliation requests for tasks that are // pending are exposed in reconciliation. TEST_F(ReconciliationTest, PendingTask) { MockAuthorizer authorizer; Try<PID<Master> > master = StartMaster(&authorizer); ASSERT_SOME(master); MockExecutor exec(DEFAULT_EXECUTOR_ID); Future<SlaveRegisteredMessage> slaveRegisteredMessage = FUTURE_PROTOBUF(SlaveRegisteredMessage(), _, _); Try<PID<Slave> > slave = StartSlave(); ASSERT_SOME(slave); // Wait for the slave to register and get the slave id. AWAIT_READY(slaveRegisteredMessage); const SlaveID slaveId = slaveRegisteredMessage.get().slave_id(); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); EXPECT_CALL(sched, registered(&driver, _, _)) .Times(1); Future<vector<Offer> > offers; EXPECT_CALL(sched, resourceOffers(&driver, _)) .WillOnce(FutureArg<1>(&offers)) .WillRepeatedly(Return()); // Ignore subsequent offers. driver.start(); AWAIT_READY(offers); EXPECT_NE(0u, offers.get().size()); // Return a pending future from authorizer. Future<Nothing> authorize; Promise<bool> promise; EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>())) .WillOnce(DoAll(FutureSatisfy(&authorize), Return(promise.future()))); TaskInfo task = createTask(offers.get()[0], "", DEFAULT_EXECUTOR_ID); vector<TaskInfo> tasks; tasks.push_back(task); driver.launchTasks(offers.get()[0].id(), tasks); // Wait until authorization is in progress. AWAIT_READY(authorize); // First send an implicit reconciliation request for this task. Future<TaskStatus> update; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&update)); vector<TaskStatus> statuses; driver.reconcileTasks(statuses); AWAIT_READY(update); EXPECT_EQ(TASK_STAGING, update.get().state()); EXPECT_TRUE(update.get().has_slave_id()); // Now send an explicit reconciliation request for this task. Future<TaskStatus> update2; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&update2)); TaskStatus status; status.mutable_task_id()->CopyFrom(task.task_id()); status.mutable_slave_id()->CopyFrom(slaveId); status.set_state(TASK_STAGING); statuses.push_back(status); driver.reconcileTasks(statuses); AWAIT_READY(update2); EXPECT_EQ(TASK_STAGING, update2.get().state()); EXPECT_TRUE(update2.get().has_slave_id()); driver.stop(); driver.join(); Shutdown(); // Must shutdown before 'containerizer' gets deallocated. }
// Runs the provided command in a subprocess. inline Try<Subprocess> subprocess(const std::string& command) { // Create pipes for stdin, stdout, stderr. // Index 0 is for reading, and index 1 is for writing. int stdinPipe[2]; int stdoutPipe[2]; int stderrPipe[2]; if (pipe(stdinPipe) == -1) { return ErrnoError("Failed to create pipe"); } else if (pipe(stdoutPipe) == -1) { os::close(stdinPipe[0]); os::close(stdinPipe[1]); return ErrnoError("Failed to create pipe"); } else if (pipe(stderrPipe) == -1) { os::close(stdinPipe[0]); os::close(stdinPipe[1]); os::close(stdoutPipe[0]); os::close(stdoutPipe[1]); return ErrnoError("Failed to create pipe"); } pid_t pid; if ((pid = fork()) == -1) { os::close(stdinPipe[0]); os::close(stdinPipe[1]); os::close(stdoutPipe[0]); os::close(stdoutPipe[1]); os::close(stderrPipe[0]); os::close(stderrPipe[1]); return ErrnoError("Failed to fork"); } Subprocess process; process.data->pid = pid; if (process.data->pid == 0) { // Child. // Close parent's end of the pipes. os::close(stdinPipe[1]); os::close(stdoutPipe[0]); os::close(stderrPipe[0]); // Make our pipes look like stdin, stderr, stdout before we exec. while (dup2(stdinPipe[0], STDIN_FILENO) == -1 && errno == EINTR); while (dup2(stdoutPipe[1], STDOUT_FILENO) == -1 && errno == EINTR); while (dup2(stderrPipe[1], STDERR_FILENO) == -1 && errno == EINTR); // Close the copies. os::close(stdinPipe[0]); os::close(stdoutPipe[1]); os::close(stderrPipe[1]); execl("/bin/sh", "sh", "-c", command.c_str(), (char *) NULL); ABORT("Failed to execl '/bin sh -c ", command.c_str(), "'\n"); } // Parent. // Close the child's end of the pipes. os::close(stdinPipe[0]); os::close(stdoutPipe[1]); os::close(stderrPipe[1]); process.data->in = stdinPipe[1]; process.data->out = stdoutPipe[0]; process.data->err = stderrPipe[0]; // Rather than directly exposing the future from process::reap, we // must use an explicit promise so that we can ensure we can receive // the termination signal. Otherwise, the caller can discard the // reap future, and we will not know when it is safe to close the // file descriptors. Promise<Option<int> >* promise = new Promise<Option<int> >(); process.data->status = promise->future(); // We need to bind a copy of this Subprocess into the onAny callback // below to ensure that we don't close the file descriptors before // the subprocess has terminated (i.e., because the caller doesn't // keep a copy of this Subprocess around themselves). process::reap(process.data->pid) .onAny(lambda::bind(internal::cleanup, lambda::_1, promise, process)); return process; }
void close_and_destroy(Promise<> promise) { binlog_->close_and_destroy().ensure(); promise.set_value(Unit()); LOG(INFO) << "close_and_destroy: done"; stop(); }
TEST(Timekeeper, futureGetTimeout) { Promise<int> p; EXPECT_THROW(p.getFuture().get(one_ms), folly::TimedOut); }
bool ToJSValue(JSContext* aCx, Promise& aArgument, JS::MutableHandle<JS::Value> aValue) { aValue.setObject(*aArgument.PromiseObj()); return MaybeWrapObjectValue(aCx, aValue); }
TEST(Future, getFutureAfterSetValue) { Promise<int> p; p.setValue(42); EXPECT_EQ(42, p.getFuture().value()); }
TEST(Future, getFutureAfterSetException) { Promise<Unit> p; p.setWith([]() -> void { throw std::logic_error("foo"); }); EXPECT_THROW(p.getFuture().value(), std::logic_error); }
Future<Unit> at(std::chrono::time_point<Clock> when) { Promise<Unit> p; auto f = p.getFuture(); promises_.push_back(std::move(p)); return std::move(f); }
TEST(Future, futureNotReady) { Promise<int> p; Future<int> f = p.getFuture(); EXPECT_THROW(f.value(), eggs_t); }
virtual Future<Unit> after(Duration dur) { Promise<Unit> p; auto f = p.getFuture(); promises_.push_back(std::move(p)); return std::move(f); }
TEST(Unit, promiseSetValue) { Promise<Unit> p; p.setValue(); }
inline void set_result(Promise& p, void_) { p.set_result(); }
TEST(Timekeeper, futureWithinException) { Promise<Unit> p; auto f = p.getFuture().within(awhile, std::runtime_error("expected")); EXPECT_THROW(f.get(), std::runtime_error); }
// This test verifies that two tasks each launched on a different // slave with same executor id but different executor info are // allowed even when the first task is pending due to authorization. TEST_F(MasterAuthorizationTest, PendingExecutorInfoDiffersOnDifferentSlaves) { MockAuthorizer authorizer; Try<PID<Master> > master = StartMaster(&authorizer); ASSERT_SOME(master); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); Future<Nothing> registered; EXPECT_CALL(sched, registered(&driver, _, _)) .WillOnce(FutureSatisfy(®istered)); driver.start(); AWAIT_READY(registered); Future<vector<Offer> > offers1; EXPECT_CALL(sched, resourceOffers(&driver, _)) .WillOnce(FutureArg<1>(&offers1)); // Start the first slave. MockExecutor exec1(DEFAULT_EXECUTOR_ID); Try<PID<Slave> > slave1 = StartSlave(&exec1); ASSERT_SOME(slave1); AWAIT_READY(offers1); EXPECT_NE(0u, offers1.get().size()); // Launch the first task with the default executor id. ExecutorInfo executor1; executor1 = DEFAULT_EXECUTOR_INFO; executor1.mutable_command()->set_value("exit 1"); TaskInfo task1 = createTask( offers1.get()[0], executor1.command().value(), executor1.executor_id()); vector<TaskInfo> tasks1; tasks1.push_back(task1); // Return a pending future from authorizer. Future<Nothing> future; Promise<bool> promise; EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>())) .WillOnce(DoAll(FutureSatisfy(&future), Return(promise.future()))); driver.launchTasks(offers1.get()[0].id(), tasks1); // Wait until authorization is in progress. AWAIT_READY(future); Future<vector<Offer> > offers2; EXPECT_CALL(sched, resourceOffers(&driver, _)) .WillOnce(FutureArg<1>(&offers2)) .WillRepeatedly(Return()); // Ignore subsequent offers. // Now start the second slave. MockExecutor exec2(DEFAULT_EXECUTOR_ID); Try<PID<Slave> > slave2 = StartSlave(&exec2); ASSERT_SOME(slave2); AWAIT_READY(offers2); EXPECT_NE(0u, offers2.get().size()); // Now launch the second task with the same executor id but // a different executor command. ExecutorInfo executor2; executor2 = executor1; executor2.mutable_command()->set_value("exit 2"); TaskInfo task2 = createTask( offers2.get()[0], executor2.command().value(), executor2.executor_id()); vector<TaskInfo> tasks2; tasks2.push_back(task2); EXPECT_CALL(exec2, registered(_, _, _, _)) .Times(1); EXPECT_CALL(exec2, launchTask(_, _)) .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING)); Future<TaskStatus> status2; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&status2)); EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTask&>())) .WillOnce(Return(true)); driver.launchTasks(offers2.get()[0].id(), tasks2); AWAIT_READY(status2); ASSERT_EQ(TASK_RUNNING, status2.get().state()); EXPECT_CALL(exec1, registered(_, _, _, _)) .Times(1); EXPECT_CALL(exec1, launchTask(_, _)) .WillOnce(SendStatusUpdateFromTask(TASK_RUNNING)); Future<TaskStatus> status1; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&status1)); // Complete authorization of 'task1'. promise.set(true); AWAIT_READY(status1); ASSERT_EQ(TASK_RUNNING, status1.get().state()); EXPECT_CALL(exec1, shutdown(_)) .Times(AtMost(1)); EXPECT_CALL(exec2, shutdown(_)) .Times(AtMost(1)); driver.stop(); driver.join(); Shutdown(); }
TEST(Timekeeper, futureGet) { Promise<int> p; auto t = std::thread([&]{ p.setValue(42); }); EXPECT_EQ(42, p.getFuture().get()); t.join(); }
void FileStatsWorker::get_stats(bool need_all_files, bool split_by_owner_dialog_id, Promise<FileStats> promise) { if (!G()->parameters().use_chat_info_db) { split_by_owner_dialog_id = false; } if (!split_by_owner_dialog_id) { FileStats file_stats; file_stats.need_all_files = need_all_files; auto start = Time::now(); scan_fs([&](FsFileInfo &fs_info) { FullFileInfo info; info.file_type = fs_info.file_type; info.path = std::move(fs_info.path); info.size = fs_info.size; info.atime_nsec = fs_info.atime_nsec; info.mtime_nsec = fs_info.mtime_nsec; file_stats.add(std::move(info)); }); auto passed = Time::now() - start; LOG_IF(INFO, passed > 0.5) << "Get file stats took: " << format::as_time(passed); promise.set_value(std::move(file_stats)); } else { auto start = Time::now(); std::vector<FullFileInfo> full_infos; scan_fs([&](FsFileInfo &fs_info) { FullFileInfo info; info.file_type = fs_info.file_type; info.path = std::move(fs_info.path); info.size = fs_info.size; info.atime_nsec = fs_info.atime_nsec; info.mtime_nsec = fs_info.mtime_nsec; // LOG(INFO) << "Found file of size " << info.size << " at " << info.path; full_infos.push_back(std::move(info)); }); std::unordered_map<size_t, size_t> hash_to_pos; size_t pos = 0; for (auto &full_info : full_infos) { hash_to_pos[std::hash<std::string>()(full_info.path)] = pos; pos++; } scan_db([&](DbFileInfo &db_info) { auto it = hash_to_pos.find(std::hash<std::string>()(db_info.path)); if (it == hash_to_pos.end()) { return; } // LOG(INFO) << "Match! " << db_info.path << " from " << db_info.owner_dialog_id; full_infos[it->second].owner_dialog_id = db_info.owner_dialog_id; }); FileStats file_stats; file_stats.need_all_files = need_all_files; file_stats.split_by_owner_dialog_id = split_by_owner_dialog_id; for (auto &full_info : full_infos) { file_stats.add(std::move(full_info)); } auto passed = Time::now() - start; LOG_IF(INFO, passed > 0.5) << "Get file stats took: " << format::as_time(passed); promise.set_value(std::move(file_stats)); } }
TEST(FutureTest, Stringify) { Future<bool> future; EXPECT_EQ("Abandoned", stringify(future)); { Owned<Promise<bool>> promise(new Promise<bool>()); future = promise->future(); promise.reset(); EXPECT_EQ("Abandoned", stringify(future)); } { Owned<Promise<bool>> promise(new Promise<bool>()); future = promise->future(); promise->future().discard(); promise.reset(); EXPECT_EQ("Abandoned (with discard)", stringify(future)); } { Promise<bool> promise; future = promise.future(); EXPECT_EQ("Pending", stringify(future)); promise.future().discard(); EXPECT_EQ("Pending (with discard)", stringify(future)); } { Promise<bool> promise; future = promise.future(); promise.set(true); EXPECT_EQ("Ready", stringify(future)); } { Promise<bool> promise; future = promise.future(); promise.future().discard(); promise.set(true); EXPECT_EQ("Ready (with discard)", stringify(future)); } { Promise<bool> promise; future = promise.future(); promise.fail("Failure"); EXPECT_EQ("Failed: Failure", stringify(future)); } { Promise<bool> promise; future = promise.future(); promise.future().discard(); promise.fail("Failure"); EXPECT_EQ("Failed (with discard): Failure", stringify(future)); } { Promise<bool> promise; future = promise.future(); promise.discard(); EXPECT_EQ("Discarded", stringify(future)); } { Promise<bool> promise; future = promise.future(); promise.future().discard(); promise.discard(); EXPECT_EQ("Discarded (with discard)", stringify(future)); } }
TEST(Poll, ready) { Promise<int> p; auto f = p.getFuture(); p.setValue(42); EXPECT_EQ(42, f.poll().value().value()); }
void SET_PRVALUE(SEXP x, SEXP v) { Promise* prom = SEXP_downcast<Promise*>(x); prom->setValue(v); }
TEST(Poll, notReady) { Promise<int> p; auto f = p.getFuture(); EXPECT_FALSE(f.poll().hasValue()); }
/* static */ void PromiseDebugging::GetDependentPromises(GlobalObject&, Promise& aPromise, nsTArray<nsRefPtr<Promise>>& aPromises) { aPromise.GetDependentPromises(aPromises); }
TEST(Poll, exception) { Promise<Unit> p; auto f = p.getFuture(); p.setWith([] { throw std::runtime_error("Runtime"); }); EXPECT_TRUE(f.poll().value().hasException()); }
void change_key(DbKey db_key, Promise<> promise) { binlog_->change_key(std::move(db_key)); promise.set_value(Unit()); }
TEST(Promise, getFuture) { Promise<int> p; Future<int> f = p.getFuture(); EXPECT_FALSE(f.isReady()); }
void AudioContext::OnStateChanged(void* aPromise, AudioContextState aNewState) { MOZ_ASSERT(NS_IsMainThread()); // This can happen if close() was called right after creating the // AudioContext, before the context has switched to "running". if (mAudioContextState == AudioContextState::Closed && aNewState == AudioContextState::Running && !aPromise) { return; } // This can happen if this is called in reaction to a // MediaStreamGraph shutdown, and a AudioContext was being // suspended at the same time, for example if a page was being // closed. if (mAudioContextState == AudioContextState::Closed && aNewState == AudioContextState::Suspended) { return; } #ifndef WIN32 // Bug 1170547 #ifndef XP_MACOSX #ifdef DEBUG if (!((mAudioContextState == AudioContextState::Suspended && aNewState == AudioContextState::Running) || (mAudioContextState == AudioContextState::Running && aNewState == AudioContextState::Suspended) || (mAudioContextState == AudioContextState::Running && aNewState == AudioContextState::Closed) || (mAudioContextState == AudioContextState::Suspended && aNewState == AudioContextState::Closed) || (mAudioContextState == aNewState))) { fprintf(stderr, "Invalid transition: mAudioContextState: %d -> aNewState %d\n", static_cast<int>(mAudioContextState), static_cast<int>(aNewState)); MOZ_ASSERT(false); } #endif // DEBUG #endif // XP_MACOSX #endif // WIN32 MOZ_ASSERT( mIsOffline || aPromise || aNewState == AudioContextState::Running, "We should have a promise here if this is a real-time AudioContext." "Or this is the first time we switch to \"running\"."); if (aPromise) { Promise* promise = reinterpret_cast<Promise*>(aPromise); promise->MaybeResolveWithUndefined(); DebugOnly<bool> rv = mPromiseGripArray.RemoveElement(promise); MOZ_ASSERT(rv, "Promise wasn't in the grip array?"); } if (mAudioContextState != aNewState) { RefPtr<OnStateChangeTask> onStateChangeTask = new OnStateChangeTask(this); NS_DispatchToMainThread(onStateChangeTask); } mAudioContextState = aNewState; }
TEST(Promise, setValue) { Promise<int> fund; auto ffund = fund.getFuture(); fund.setValue(42); EXPECT_EQ(42, ffund.value()); struct Foo { string name; int value; }; Promise<Foo> pod; auto fpod = pod.getFuture(); Foo f = {"the answer", 42}; pod.setValue(f); Foo f2 = fpod.value(); EXPECT_EQ(f.name, f2.name); EXPECT_EQ(f.value, f2.value); pod = Promise<Foo>(); fpod = pod.getFuture(); pod.setValue(std::move(f2)); Foo f3 = fpod.value(); EXPECT_EQ(f.name, f3.name); EXPECT_EQ(f.value, f3.value); Promise<unique_ptr<int>> mov; auto fmov = mov.getFuture(); mov.setValue(unique_ptr<int>(new int(42))); unique_ptr<int> ptr = std::move(fmov.value()); EXPECT_EQ(42, *ptr); Promise<Unit> v; auto fv = v.getFuture(); v.setValue(); EXPECT_TRUE(fv.isReady()); }
// This test verifies that a 'killTask()' that comes before // '_launchTasks()' is called results in TASK_KILLED. TEST_F(MasterAuthorizationTest, KillTask) { MockAuthorizer authorizer; Try<PID<Master> > master = StartMaster(&authorizer); ASSERT_SOME(master); MockExecutor exec(DEFAULT_EXECUTOR_ID); Try<PID<Slave> > slave = StartSlave(&exec); ASSERT_SOME(slave); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); EXPECT_CALL(sched, registered(&driver, _, _)) .Times(1); Future<vector<Offer> > offers; EXPECT_CALL(sched, resourceOffers(&driver, _)) .WillOnce(FutureArg<1>(&offers)) .WillRepeatedly(Return()); // Ignore subsequent offers. driver.start(); AWAIT_READY(offers); EXPECT_NE(0u, offers.get().size()); TaskInfo task = createTask(offers.get()[0], "", DEFAULT_EXECUTOR_ID); vector<TaskInfo> tasks; tasks.push_back(task); // Return a pending future from authorizer. Future<Nothing> future; Promise<bool> promise; EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>())) .WillOnce(DoAll(FutureSatisfy(&future), Return(promise.future()))); driver.launchTasks(offers.get()[0].id(), tasks); // Wait until authorization is in progress. AWAIT_READY(future); Future<TaskStatus> status; EXPECT_CALL(sched, statusUpdate(&driver, _)) .WillOnce(FutureArg<1>(&status)); // Now kill the task. driver.killTask(task.task_id()); // Framework should get a TASK_KILLED right away. AWAIT_READY(status); EXPECT_EQ(TASK_KILLED, status.get().state()); Future<Nothing> resourcesUnused = FUTURE_DISPATCH(_, &AllocatorProcess::resourcesUnused); // Now complete authorization. promise.set(true); // No task launch should happen resulting in all resources being // returned to the allocator. AWAIT_READY(resourcesUnused); driver.stop(); driver.join(); Shutdown(); // Must shutdown before 'containerizer' gets deallocated. }
// This test verifies that a reconciliation request that comes before // '_launchTasks()' is ignored. TEST_F(MasterAuthorizationTest, ReconcileTask) { MockAuthorizer authorizer; Try<PID<Master> > master = StartMaster(&authorizer); ASSERT_SOME(master); MockExecutor exec(DEFAULT_EXECUTOR_ID); Try<PID<Slave> > slave = StartSlave(&exec); ASSERT_SOME(slave); MockScheduler sched; MesosSchedulerDriver driver( &sched, DEFAULT_FRAMEWORK_INFO, master.get(), DEFAULT_CREDENTIAL); EXPECT_CALL(sched, registered(&driver, _, _)) .Times(1); Future<vector<Offer> > offers; EXPECT_CALL(sched, resourceOffers(&driver, _)) .WillOnce(FutureArg<1>(&offers)) .WillRepeatedly(Return()); // Ignore subsequent offers. driver.start(); AWAIT_READY(offers); EXPECT_NE(0u, offers.get().size()); TaskInfo task = createTask(offers.get()[0], "", DEFAULT_EXECUTOR_ID); vector<TaskInfo> tasks; tasks.push_back(task); // Return a pending future from authorizer. Future<Nothing> future; Promise<bool> promise; EXPECT_CALL(authorizer, authorize(An<const mesos::ACL::RunTasks&>())) .WillOnce(DoAll(FutureSatisfy(&future), Return(promise.future()))); driver.launchTasks(offers.get()[0].id(), tasks); // Wait until authorization is in progress. AWAIT_READY(future); // Scheduler shouldn't get an update from reconciliation. EXPECT_CALL(sched, statusUpdate(&driver, _)) .Times(0); Future<ReconcileTasksMessage> reconcileTasksMessage = FUTURE_PROTOBUF(ReconcileTasksMessage(), _, _); vector<TaskStatus> statuses; TaskStatus status; status.mutable_task_id()->CopyFrom(task.task_id()); status.mutable_slave_id()->CopyFrom(offers.get()[0].slave_id()); status.set_state(TASK_STAGING); statuses.push_back(status); driver.reconcileTasks(statuses); AWAIT_READY(reconcileTasksMessage); // Make sure the framework doesn't receive any update. Clock::pause(); Clock::settle(); // Now stop the framework. driver.stop(); driver.join(); Shutdown(); // Must shutdown before 'containerizer' gets deallocated. }