LCOV - code coverage report
Current view: top level - test/unittests - cancelable-tasks-unittest.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 130 133 97.7 %
Date: 2019-04-17 Functions: 28 42 66.7 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/base/atomicops.h"
       6             : #include "src/base/platform/platform.h"
       7             : #include "src/cancelable-task.h"
       8             : #include "testing/gmock/include/gmock/gmock.h"
       9             : #include "testing/gtest/include/gtest/gtest.h"
      10             : 
      11             : namespace v8 {
      12             : namespace internal {
      13             : 
      14             : namespace {
      15             : 
      16             : using ResultType = std::atomic<CancelableTaskManager::Id>;
      17             : 
      18             : class CancelableTaskManagerTest;
      19             : 
      20          26 : class TestTask : public Task, public Cancelable {
      21             :  public:
      22             :   enum Mode { kDoNothing, kWaitTillCancelTriggered, kCheckNotRun };
      23             : 
      24             :   TestTask(CancelableTaskManagerTest* test, ResultType* result, Mode mode);
      25             : 
      26             :   // Task override.
      27             :   void Run() final;
      28             : 
      29             :  private:
      30             :   ResultType* const result_;
      31             :   const Mode mode_;
      32             :   CancelableTaskManagerTest* const test_;
      33             : };
      34             : 
      35           3 : class SequentialRunner {
      36             :  public:
      37             :   explicit SequentialRunner(std::unique_ptr<TestTask> task)
      38           3 :       : task_(std::move(task)), task_id_(task_->id()) {}
      39             : 
      40           3 :   void Run() {
      41           3 :     task_->Run();
      42             :     task_.reset();
      43           3 :   }
      44             : 
      45             :   CancelableTaskManager::Id task_id() const { return task_id_; }
      46             : 
      47             :  private:
      48             :   std::unique_ptr<TestTask> task_;
      49             :   const CancelableTaskManager::Id task_id_;
      50             : };
      51             : 
      52          20 : class ThreadedRunner final : public base::Thread {
      53             :  public:
      54             :   explicit ThreadedRunner(std::unique_ptr<TestTask> task)
      55             :       : Thread(Options("runner thread")),
      56             :         task_(std::move(task)),
      57          20 :         task_id_(task_->id()) {}
      58             : 
      59          10 :   void Run() override {
      60          10 :     task_->Run();
      61             :     task_.reset();
      62          10 :   }
      63             : 
      64             :   CancelableTaskManager::Id task_id() const { return task_id_; }
      65             : 
      66             :  private:
      67             :   std::unique_ptr<TestTask> task_;
      68             :   const CancelableTaskManager::Id task_id_;
      69             : };
      70             : 
      71          22 : class CancelableTaskManagerTest : public ::testing::Test {
      72             :  public:
      73          15 :   CancelableTaskManager* manager() { return &manager_; }
      74             : 
      75             :   std::unique_ptr<TestTask> NewTask(
      76             :       ResultType* result, TestTask::Mode mode = TestTask::kDoNothing) {
      77          13 :     return base::make_unique<TestTask>(this, result, mode);
      78             :   }
      79             : 
      80             :   void CancelAndWait() {
      81             :     cancel_triggered_.store(true);
      82          11 :     manager_.CancelAndWait();
      83             :   }
      84             : 
      85             :   TryAbortResult TryAbortAll() {
      86             :     cancel_triggered_.store(true);
      87           3 :     return manager_.TryAbortAll();
      88             :   }
      89             : 
      90             :   bool cancel_triggered() const { return cancel_triggered_.load(); }
      91             : 
      92             :  private:
      93             :   CancelableTaskManager manager_;
      94             :   std::atomic<bool> cancel_triggered_{false};
      95             : };
      96             : 
      97             : TestTask::TestTask(CancelableTaskManagerTest* test, ResultType* result,
      98             :                    Mode mode)
      99          26 :     : Cancelable(test->manager()), result_(result), mode_(mode), test_(test) {}
     100             : 
     101          13 : void TestTask::Run() {
     102          13 :   if (!TryRun()) return;
     103             : 
     104           6 :   result_->store(id());
     105             : 
     106           6 :   switch (mode_) {
     107             :     case kWaitTillCancelTriggered:
     108             :       // Simple busy wait until the main thread tried to cancel.
     109     1698810 :       while (!test_->cancel_triggered()) {
     110             :       }
     111             :       break;
     112             :     case kCheckNotRun:
     113             :       // Check that we never execute {RunInternal}.
     114           0 :       EXPECT_TRUE(false);
     115           0 :       break;
     116             :     default:
     117             :       break;
     118             :   }
     119             : }
     120             : 
     121             : }  // namespace
     122             : 
     123       15444 : TEST_F(CancelableTaskManagerTest, EmptyCancelableTaskManager) {
     124             :   CancelAndWait();
     125           1 : }
     126             : 
     127       15444 : TEST_F(CancelableTaskManagerTest, SequentialCancelAndWait) {
     128           1 :   ResultType result1{0};
     129           2 :   SequentialRunner runner1(NewTask(&result1, TestTask::kCheckNotRun));
     130           2 :   EXPECT_EQ(0u, result1);
     131             :   CancelAndWait();
     132           2 :   EXPECT_EQ(0u, result1);
     133           1 :   runner1.Run();
     134           2 :   EXPECT_EQ(0u, result1);
     135           1 : }
     136             : 
     137       15444 : TEST_F(CancelableTaskManagerTest, SequentialMultipleTasks) {
     138           1 :   ResultType result1{0};
     139           1 :   ResultType result2{0};
     140           2 :   SequentialRunner runner1(NewTask(&result1));
     141           1 :   SequentialRunner runner2(NewTask(&result2));
     142           2 :   EXPECT_EQ(1u, runner1.task_id());
     143           2 :   EXPECT_EQ(2u, runner2.task_id());
     144             : 
     145           2 :   EXPECT_EQ(0u, result1);
     146           1 :   runner1.Run();
     147           2 :   EXPECT_EQ(1u, result1);
     148             : 
     149           2 :   EXPECT_EQ(0u, result2);
     150           1 :   runner2.Run();
     151           2 :   EXPECT_EQ(2u, result2);
     152             : 
     153             :   CancelAndWait();
     154           2 :   EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(1));
     155           2 :   EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(2));
     156           1 : }
     157             : 
     158       15444 : TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksStarted) {
     159           1 :   ResultType result1{0};
     160           1 :   ResultType result2{0};
     161           3 :   ThreadedRunner runner1(NewTask(&result1, TestTask::kWaitTillCancelTriggered));
     162           2 :   ThreadedRunner runner2(NewTask(&result2, TestTask::kWaitTillCancelTriggered));
     163           1 :   runner1.Start();
     164           1 :   runner2.Start();
     165             :   // Busy wait on result to make sure both tasks are done.
     166     8514878 :   while (result1.load() == 0 || result2.load() == 0) {
     167             :   }
     168             :   CancelAndWait();
     169           1 :   runner1.Join();
     170           1 :   runner2.Join();
     171           2 :   EXPECT_EQ(1u, result1);
     172           2 :   EXPECT_EQ(2u, result2);
     173           1 : }
     174             : 
     175       15444 : TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksNotRun) {
     176           1 :   ResultType result1{0};
     177           1 :   ResultType result2{0};
     178           3 :   ThreadedRunner runner1(NewTask(&result1, TestTask::kCheckNotRun));
     179           2 :   ThreadedRunner runner2(NewTask(&result2, TestTask::kCheckNotRun));
     180             :   CancelAndWait();
     181             :   // Tasks are canceled, hence the runner will bail out and not update result.
     182           1 :   runner1.Start();
     183           1 :   runner2.Start();
     184           1 :   runner1.Join();
     185           1 :   runner2.Join();
     186           2 :   EXPECT_EQ(0u, result1);
     187           2 :   EXPECT_EQ(0u, result2);
     188           1 : }
     189             : 
     190       15444 : TEST_F(CancelableTaskManagerTest, RemoveBeforeCancelAndWait) {
     191           1 :   ResultType result1{0};
     192           3 :   ThreadedRunner runner1(NewTask(&result1, TestTask::kCheckNotRun));
     193           1 :   CancelableTaskManager::Id id = runner1.task_id();
     194           2 :   EXPECT_EQ(1u, id);
     195           3 :   EXPECT_EQ(TryAbortResult::kTaskAborted, manager()->TryAbort(id));
     196           1 :   runner1.Start();
     197           1 :   runner1.Join();
     198             :   CancelAndWait();
     199           2 :   EXPECT_EQ(0u, result1);
     200           1 : }
     201             : 
     202       15444 : TEST_F(CancelableTaskManagerTest, RemoveAfterCancelAndWait) {
     203           1 :   ResultType result1{0};
     204           3 :   ThreadedRunner runner1(NewTask(&result1));
     205           1 :   CancelableTaskManager::Id id = runner1.task_id();
     206           2 :   EXPECT_EQ(1u, id);
     207           1 :   runner1.Start();
     208           1 :   runner1.Join();
     209             :   CancelAndWait();
     210           2 :   EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(id));
     211           2 :   EXPECT_EQ(1u, result1);
     212           1 : }
     213             : 
     214       15444 : TEST_F(CancelableTaskManagerTest, RemoveUnmanagedId) {
     215           2 :   EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(1));
     216           2 :   EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(2));
     217             :   CancelAndWait();
     218           2 :   EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(1));
     219           2 :   EXPECT_EQ(TryAbortResult::kTaskRemoved, manager()->TryAbort(3));
     220           1 : }
     221             : 
     222       15444 : TEST_F(CancelableTaskManagerTest, EmptyTryAbortAll) {
     223           2 :   EXPECT_EQ(TryAbortResult::kTaskRemoved, TryAbortAll());
     224             :   CancelAndWait();
     225           1 : }
     226             : 
     227       15444 : TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksNotRunTryAbortAll) {
     228           1 :   ResultType result1{0};
     229           1 :   ResultType result2{0};
     230           3 :   ThreadedRunner runner1(NewTask(&result1, TestTask::kCheckNotRun));
     231           2 :   ThreadedRunner runner2(NewTask(&result2, TestTask::kCheckNotRun));
     232           2 :   EXPECT_EQ(TryAbortResult::kTaskAborted, TryAbortAll());
     233             :   // Tasks are canceled, hence the runner will bail out and not update result.
     234           1 :   runner1.Start();
     235           1 :   runner2.Start();
     236           1 :   runner1.Join();
     237           1 :   runner2.Join();
     238           2 :   EXPECT_EQ(0u, result1);
     239           2 :   EXPECT_EQ(0u, result2);
     240             :   CancelAndWait();
     241           1 : }
     242             : 
     243       15444 : TEST_F(CancelableTaskManagerTest, ThreadedMultipleTasksStartedTryAbortAll) {
     244           1 :   ResultType result1{0};
     245           1 :   ResultType result2{0};
     246           3 :   ThreadedRunner runner1(NewTask(&result1, TestTask::kWaitTillCancelTriggered));
     247           2 :   ThreadedRunner runner2(NewTask(&result2, TestTask::kWaitTillCancelTriggered));
     248           1 :   runner1.Start();
     249             :   // Busy wait on result to make sure task1 is done.
     250     6463771 :   while (result1.load() == 0) {
     251             :   }
     252             :   // If the task saw that we triggered the cancel and finished *before* the
     253             :   // actual cancel happened, we get {kTaskAborted}. Otherwise, we get
     254             :   // {kTaskRunning}.
     255           2 :   EXPECT_THAT(TryAbortAll(),
     256             :               testing::AnyOf(testing::Eq(TryAbortResult::kTaskAborted),
     257           0 :                              testing::Eq(TryAbortResult::kTaskRunning)));
     258           1 :   runner2.Start();
     259           1 :   runner1.Join();
     260           1 :   runner2.Join();
     261           2 :   EXPECT_EQ(1u, result1);
     262           2 :   EXPECT_EQ(0u, result2);
     263             :   CancelAndWait();
     264           1 : }
     265             : 
     266             : }  // namespace internal
     267        9264 : }  // namespace v8

Generated by: LCOV version 1.10