Coverage for /Syzygy/agent/common/thread_state_unittest.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%1061060.C++test

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/agent/common/thread_state.h"
  16    :  
  17    :  #include "base/atomic_ref_count.h"
  18    :  #include "base/bind.h"
  19    :  #include "base/synchronization/waitable_event.h"
  20    :  #include "base/threading/thread.h"
  21    :  #include "gtest/gtest.h"
  22    :  
  23    :  namespace agent {
  24    :  namespace common {
  25    :  namespace {
  26    :  
  27    :  // A ThreadStateBase derived class for unit-testing.
  28    :  class TestThreadState : public ThreadStateBase {
  29    :   public:
  30    :    // Expose protected members for unit-testing.
  31    :    using ThreadStateBase::entry_;
  32    :  
  33  E :    explicit TestThreadState(base::AtomicRefCount* ref) : ref_(ref) {
  34  E :      base::AtomicRefCountInc(ref_);
  35  E :    }
  36  E :    virtual ~TestThreadState() {
  37  E :      base::AtomicRefCountDec(ref_);
  38  E :    }
  39    :  
  40    :   private:
  41    :    base::AtomicRefCount* ref_;
  42    :  };
  43    :  
  44    :  // A ThreadStateManager derived class for unit-testing.
  45    :  class TestThreadStateManager : public ThreadStateManager {
  46    :   public:
  47    :    // Expose protected members for unit-testing.
  48    :    using ThreadStateManager::Scavenge;
  49    :    using ThreadStateManager::IsThreadDead;
  50    :  
  51    :    // Returns true if the there are no active thread state items being managed.
  52  E :    bool HasActiveItems() {
  53  E :      base::AutoLock auto_lock(lock_);
  54  E :      return !IsListEmpty(&active_items_);
  55  E :    }
  56    :  
  57    :    // Returns true if the there are no death row thread state items being
  58    :    // managed. If this returns true, it does not necessarily mean that there
  59    :    // are items ready to be scavenged.
  60  E :    bool HasDeathRowItems() {
  61  E :      base::AutoLock auto_lock(lock_);
  62  E :      return !IsListEmpty(&death_row_items_);
  63  E :    }
  64    :  
  65    :    // Returns true iff @p item is in the active items list.
  66  E :    bool IsActive(const TestThreadState* item) {
  67  E :      base::AutoLock auto_lock(lock_);
  68  E :      return ListContains(&active_items_, item);
  69  E :    }
  70    :  
  71    :    // Returns true iff @p items is in the death_row list.
  72  E :    bool IsOnDeathRow(const TestThreadState* item) {
  73  E :      base::AutoLock auto_lock(lock_);
  74  E :      return ListContains(&death_row_items_, item);
  75  E :    }
  76    :  
  77    :   protected:
  78    :    // A helper function to check if a item is in the given list.
  79    :    static bool ListContains(const LIST_ENTRY* list,
  80  E :                             const TestThreadState* item) {
  81    :      return IsNodeOnList(const_cast<LIST_ENTRY*>(list),
  82  E :                          const_cast<LIST_ENTRY*>(&item->entry_));
  83  E :    }
  84    :  };
  85    :  
  86    :  // The test fixture for the thread state related tests.
  87    :  class ThreadStateTest : public testing::Test {
  88    :   public:
  89    :    ThreadStateTest()
  90    :        : worker_thread_("test"),
  91    :          manager_(),
  92  E :          thread_states_(0) {
  93  E :    }
  94    :  
  95    :    // A setup function run before each test.
  96  E :    virtual void SetUp() override {
  97  E :      manager_.reset(new TestThreadStateManager);
  98  E :      ASSERT_TRUE(worker_thread_.Start());
  99  E :    }
 100    :  
 101    :    // A helper factory function for creating a TestThreadState.
 102  E :    void CreateThreadStateImpl(TestThreadState** thread_state) {
 103  E :      ASSERT_TRUE(thread_state != NULL);
 104  E :      *thread_state = new TestThreadState(&thread_states_);
 105  E :    }
 106    :  
 107    :    // Creates (and returns) a thread state object on the worker thread.
 108  E :    void CreateThreadState(TestThreadState** state) {
 109  E :      ASSERT_TRUE(state != NULL);
 110    :      CallOnWorkerThread(
 111    :          base::Bind(&ThreadStateTest::CreateThreadStateImpl,
 112    :                     base::Unretained(this),
 113  E :                     state));
 114  E :      ASSERT_TRUE(*state != NULL);
 115  E :    }
 116    :  
 117    :    // Activates a thread state object on the worker thread.
 118  E :    void RegisterThreadState(ThreadStateBase* state) {
 119    :      CallOnWorkerThread(
 120    :          base::Bind(&TestThreadStateManager::Register,
 121    :                     base::Unretained(manager_.get()),
 122  E :                     state));
 123  E :    }
 124    :  
 125    :    // Unregisters a thread state object on the worker thread.
 126  E :    void UnregisterThreadState(ThreadStateBase* state) {
 127    :      CallOnWorkerThread(
 128    :          base::Bind(&TestThreadStateManager::Unregister,
 129    :                     base::Unretained(manager_.get()),
 130  E :                     state));
 131  E :    }
 132    :  
 133    :    // Marks a thread state object for death on the worker thread.
 134  E :    void MarkThreadStateForDeath(ThreadStateBase* state) {
 135    :      CallOnWorkerThread(
 136    :          base::Bind(&TestThreadStateManager::MarkForDeath,
 137    :                     base::Unretained(manager_.get()),
 138  E :                     state));
 139  E :    }
 140    :  
 141    :   protected:
 142    :    // Callback function to execute a TestThreadStateManager method on
 143    :    // worker_thread_ and signal its completion.
 144    :    void CallbackImpl(
 145    :        base::Closure task,
 146  E :        base::WaitableEvent* event) {
 147  E :      ASSERT_TRUE(event != NULL);
 148  E :      ASSERT_EQ(base::MessageLoop::current(), worker_thread_.message_loop());
 149  E :      task.Run();
 150  E :      event->Signal();
 151  E :    }
 152    :  
 153    :    // Helper function to call a closure on worker_thread_
 154    :    // and wait until its completion has been signaled.
 155  E :    void CallOnWorkerThread(base::Closure task) {
 156  E :      base::WaitableEvent event(false, false);
 157    :      worker_thread_.message_loop()->PostTask(
 158    :          FROM_HERE,
 159    :          base::Bind(&ThreadStateTest::CallbackImpl,
 160    :                     base::Unretained(this),
 161    :                     task,
 162  E :                     &event));
 163  E :      event.Wait();
 164  E :    }
 165    :  
 166    :    // A counter for the number of outstanding thread states.
 167    :    base::AtomicRefCount thread_states_;
 168    :  
 169    :    // The worker thread on which the state management functions will be
 170    :    // exercised.
 171    :    base::Thread worker_thread_;
 172    :  
 173    :    // The thread state manager under test.
 174    :    scoped_ptr<TestThreadStateManager> manager_;
 175    :  };
 176    :  
 177    :  }  // namespace
 178    :  
 179  E :  TEST_F(ThreadStateTest, LifeCycle) {
 180    :    // Check the base state of the thread state manager_->
 181  E :    EXPECT_FALSE(manager_->HasActiveItems());
 182  E :    EXPECT_FALSE(manager_->HasDeathRowItems());
 183    :  
 184    :    // Create a thread state item.
 185  E :    TestThreadState* thread_state = NULL;
 186  E :    ASSERT_NO_FATAL_FAILURE(CreateThreadState(&thread_state));
 187  E :    EXPECT_FALSE(manager_->IsThreadDead(thread_state));
 188    :  
 189    :    // Register the thread state item.
 190  E :    ASSERT_NO_FATAL_FAILURE(RegisterThreadState(thread_state));
 191  E :    EXPECT_TRUE(manager_->HasActiveItems());
 192  E :    EXPECT_TRUE(manager_->IsActive(thread_state));
 193  E :    EXPECT_FALSE(manager_->HasDeathRowItems());
 194    :  
 195    :    // Unregister the thread state item.
 196  E :    ASSERT_NO_FATAL_FAILURE(UnregisterThreadState(thread_state));
 197  E :    EXPECT_FALSE(manager_->HasActiveItems());
 198  E :    EXPECT_FALSE(manager_->HasDeathRowItems());
 199    :  
 200    :    // Re-register the thread state item.
 201  E :    ASSERT_NO_FATAL_FAILURE(RegisterThreadState(thread_state));
 202  E :    EXPECT_TRUE(manager_->HasActiveItems());
 203  E :    EXPECT_TRUE(manager_->IsActive(thread_state));
 204  E :    EXPECT_FALSE(manager_->HasDeathRowItems());
 205    :  
 206    :    // Mark the thread state for death.
 207  E :    ASSERT_NO_FATAL_FAILURE(MarkThreadStateForDeath(thread_state));
 208  E :    EXPECT_FALSE(manager_->HasActiveItems());
 209  E :    EXPECT_TRUE(manager_->HasDeathRowItems());
 210  E :    EXPECT_TRUE(manager_->IsOnDeathRow(thread_state));
 211    :  
 212    :    // A list to which we'll scavenge thread state items.
 213  E :    bool has_items = false;
 214    :    LIST_ENTRY dead_items;
 215  E :    InitializeListHead(&dead_items);
 216    :  
 217    :    // Scavenge from death row while the thread is still running. Note that we
 218    :    // test this using the internal function that usually isn't exposed to
 219    :    // callers.
 220  E :    has_items = manager_->Scavenge();
 221  E :    EXPECT_TRUE(has_items);
 222  E :    EXPECT_TRUE(IsListEmpty(&dead_items));
 223  E :    EXPECT_FALSE(manager_->HasActiveItems());
 224  E :    EXPECT_TRUE(manager_->HasDeathRowItems());
 225  E :    EXPECT_TRUE(manager_->IsOnDeathRow(thread_state));
 226    :  
 227    :    // Stop thread then scavenge from death row. Note that we test this using
 228    :    // the internal function that usually isn't exposed to callers.
 229  E :    worker_thread_.Stop();
 230  E :    EXPECT_TRUE(manager_->IsThreadDead(thread_state));
 231  E :    EXPECT_TRUE(base::AtomicRefCountIsOne(&thread_states_));
 232  E :    has_items = manager_->Scavenge();
 233  E :    EXPECT_FALSE(has_items);
 234  E :    EXPECT_FALSE(manager_->HasActiveItems());
 235  E :    EXPECT_FALSE(manager_->HasDeathRowItems());
 236  E :    EXPECT_TRUE(base::AtomicRefCountIsZero(&thread_states_));
 237  E :  }
 238    :  
 239  E :  TEST_F(ThreadStateTest, DeletesAllThreadStatesOnDestruction) {
 240  E :    TestThreadState* thread_state = NULL;
 241  E :    ASSERT_NO_FATAL_FAILURE(CreateThreadState(&thread_state));
 242  E :    ASSERT_NO_FATAL_FAILURE(RegisterThreadState(thread_state));
 243    :  
 244    :    // We expect the thread state to be destroyed on deletion of the manager.
 245  E :    EXPECT_TRUE(base::AtomicRefCountIsOne(&thread_states_));
 246    :  
 247  E :    manager_.reset();
 248    :  
 249  E :    EXPECT_TRUE(base::AtomicRefCountIsZero(&thread_states_));
 250  E :  }
 251    :  
 252    :  }  // namespace common
 253    :  }  // namespace agent

Coverage information generated Thu Jan 14 17:40:38 2016.