| 289 | } |
| 290 | |
| 291 | void TestFinishNotSticky(std::function<std::shared_ptr<TaskGroup>()> factory) { |
| 292 | // If a task is added that runs very quickly it might decrement the task counter back |
| 293 | // down to 0 and mark the completion future as complete before all tasks are added. |
| 294 | // The "finished future" of the task group could get stuck to complete. |
| 295 | // |
| 296 | // Instead the task group should not allow the finished future to be marked complete |
| 297 | // until after FinishAsync has been called. |
| 298 | const int NTASKS = 100; |
| 299 | for (int i = 0; i < NTASKS; ++i) { |
| 300 | auto task_group = factory(); |
| 301 | // Add a task and let it complete |
| 302 | task_group->Append([] { return Status::OK(); }); |
| 303 | // Wait a little bit, if the task group was going to lock the finish hopefully it |
| 304 | // would do so here while we wait |
| 305 | SleepFor(1e-2); |
| 306 | |
| 307 | // Add a new task that will still be running |
| 308 | std::atomic<bool> ready(false); |
| 309 | std::mutex m; |
| 310 | std::condition_variable cv; |
| 311 | task_group->Append([&m, &cv, &ready] { |
| 312 | std::unique_lock<std::mutex> lk(m); |
| 313 | cv.wait(lk, [&ready] { return ready.load(); }); |
| 314 | return Status::OK(); |
| 315 | }); |
| 316 | |
| 317 | // Ensure task group not finished already |
| 318 | auto finished = task_group->FinishAsync(); |
| 319 | ASSERT_FALSE(finished.is_finished()); |
| 320 | |
| 321 | std::unique_lock<std::mutex> lk(m); |
| 322 | ready = true; |
| 323 | lk.unlock(); |
| 324 | cv.notify_one(); |
| 325 | |
| 326 | ASSERT_FINISHES_OK(finished); |
| 327 | } |
| 328 | } |
| 329 | |
| 330 | void TestFinishNeverStarted(std::shared_ptr<TaskGroup> task_group) { |
| 331 | // If we call FinishAsync we are done adding tasks so if we never added any it should be |
no test coverage detected