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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
97.0%971000.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/bind.h"
  18    :  #include "base/synchronization/waitable_event.h"
  19    :  #include "base/threading/thread.h"
  20    :  #include "gmock/gmock.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 MockThreadState : public ThreadStateBase {
  29    :   public:
  30    :    // Expose protected members for unit-testing.
  31    :    using ThreadStateBase::entry_;
  32    :  
  33    :    // Create a mock for the destructor so that we can track when it is called.
  34  E :    virtual ~MockThreadState() { OnDestruction(); }
  35  E :    MOCK_METHOD0(OnDestruction, void());
  36    :  };
  37    :  
  38    :  // A ThreadSTateManager derived class for unit-testing.
  39    :  class TestThreadStateManager : public ThreadStateManager {
  40    :   public:
  41    :    // Expose protected members for unit-testing.
  42    :    using ThreadStateManager::Scavenge;
  43    :    using ThreadStateManager::IsThreadDead;
  44    :  
  45    :    // A helper factory function for creating a MockThreadState. This is added
  46    :    // to this ThreadStateManager derived class as a helper which is callable
  47    :    // via ThreadStateTest::CallOnWorkerThread.
  48  E :    void CreateThreadState(MockThreadState** thread_state) {
  49  E :      ASSERT_TRUE(thread_state != NULL);
  50  E :      *thread_state = new testing::StrictMock<MockThreadState>();
  51  E :    }
  52    :  
  53    :    // Returns true if the there are no active thread state items being managed.
  54  E :    bool HasActiveItems() {
  55  E :      base::AutoLock auto_lock(lock_);
  56  E :      return !IsListEmpty(&active_items_);
  57  E :    }
  58    :  
  59    :    // Returns true if the there are no death row thread state items being
  60    :    // managed. If this returns true, it does not necessarily mean that there
  61    :    // are items ready to be scavenged.
  62  E :    bool HasDeathRowItems() {
  63  E :      base::AutoLock auto_lock(lock_);
  64  E :      return !IsListEmpty(&death_row_items_);
  65  E :    }
  66    :  
  67    :    // Returns true iff @p item is in the active items list.
  68  E :    bool IsActive(const MockThreadState* item) {
  69  E :      base::AutoLock auto_lock(lock_);
  70  E :      return ListContains(&active_items_, item);
  71  E :    }
  72    :  
  73    :    // Returns true iff @p items is in the death_row list.
  74  E :    bool IsOnDeathRow(const MockThreadState* item) {
  75  E :      base::AutoLock auto_lock(lock_);
  76  E :      return ListContains(&death_row_items_, item);
  77  E :    }
  78    :  
  79    :   protected:
  80    :    // A helper function to check if a item is in the given list.
  81    :    static bool ListContains(const LIST_ENTRY* list,
  82  E :                             const MockThreadState* item) {
  83  E :      const LIST_ENTRY* current = list;
  84  E :      const LIST_ENTRY* entry = &item->entry_;
  85  E :      while (current != NULL) {
  86  E :        if (current->Flink == entry)
  87  E :          return true;
  88  i :        current = current->Flink;
  89  i :      }
  90  i :      return true;
  91  E :    }
  92    :  };
  93    :  
  94    :  // The test fixture for the thread state related tests.
  95    :  class ThreadStateTest : public testing::Test {
  96    :   public:
  97  E :    ThreadStateTest() : worker_thread_("test") {
  98  E :    }
  99    :  
 100    :    // A setup function run before each test.
 101  E :    virtual void SetUp() OVERRIDE {
 102  E :      ASSERT_TRUE(worker_thread_.Start());
 103  E :    }
 104    :  
 105    :    // Creates (and returns) a thread state object on the worker thread.
 106  E :    void CreateThreadState(MockThreadState** state) {
 107  E :      ASSERT_TRUE(state != NULL);
 108  E :      CallOnWorkerThread(&TestThreadStateManager::CreateThreadState, state);
 109  E :      ASSERT_TRUE(*state != NULL);
 110  E :    }
 111    :  
 112    :    // Activates a thread state object on the worker thread.
 113  E :    void RegisterThreadState(ThreadStateBase* state) {
 114  E :      CallOnWorkerThread(&TestThreadStateManager::Register, state);
 115  E :    }
 116    :  
 117    :    // Unregisters a thread state object on the worker thread.
 118  E :    void UnregisterThreadState(ThreadStateBase* state) {
 119  E :      CallOnWorkerThread(&TestThreadStateManager::Unregister, state);
 120  E :    }
 121    :  
 122    :    // Marks a thread state object for death on the worker thread.
 123  E :    void MarkThreadStateForDeath(ThreadStateBase* state) {
 124  E :      CallOnWorkerThread(&TestThreadStateManager::MarkForDeath, state);
 125  E :    }
 126    :  
 127    :   protected:
 128    :    // Callback function to execute a TestThreadStateManager method on
 129    :    // worker_thread_ and signal its completion.
 130    :    template<typename ParamType>
 131    :    void CallbackImpl(
 132    :        void (TestThreadStateManager::*method)(ParamType),
 133    :        ParamType param,
 134  E :        base::WaitableEvent* event) {
 135  E :      ASSERT_TRUE(param != NULL);
 136  E :      ASSERT_TRUE(event != NULL);
 137  E :      ASSERT_EQ(MessageLoop::current(), worker_thread_.message_loop());
 138  E :      (manager_.*method)(param);
 139  E :      event->Signal();
 140  E :    }
 141    :  
 142    :    // Helper function to call a TestThreadStateManager method on worker_thread_
 143    :    // and wait until its completion has been signaled.
 144    :    template<typename ParamType>
 145    :    void CallOnWorkerThread(
 146    :        void (TestThreadStateManager::*method)(ParamType),
 147  E :        ParamType param) {
 148  E :      base::WaitableEvent event(false, false);
 149    :      worker_thread_.message_loop()->PostTask(
 150    :          FROM_HERE,
 151    :          base::Bind(&ThreadStateTest::CallbackImpl<ParamType>,
 152    :                     base::Unretained(this),
 153    :                     method,
 154    :                     param,
 155  E :                     &event));
 156  E :      event.Wait();
 157  E :    }
 158    :  
 159    :    // The worker thread on which the state management functions will be
 160    :    // exercised.
 161    :    base::Thread worker_thread_;
 162    :  
 163    :    // The thread state manager under test.
 164    :    TestThreadStateManager manager_;
 165    :  };
 166    :  
 167    :  }  // namespace
 168    :  
 169  E :  TEST_F(ThreadStateTest, LifeCycle) {
 170    :    // Check the base state of the thread state manager.
 171  E :    EXPECT_FALSE(manager_.HasActiveItems());
 172  E :    EXPECT_FALSE(manager_.HasDeathRowItems());
 173    :  
 174    :    // Create a thread state item.
 175  E :    MockThreadState* thread_state = NULL;
 176  E :    ASSERT_NO_FATAL_FAILURE(CreateThreadState(&thread_state));
 177  E :    EXPECT_FALSE(manager_.IsThreadDead(thread_state));
 178    :  
 179    :    // Register the thread state item.
 180  E :    ASSERT_NO_FATAL_FAILURE(RegisterThreadState(thread_state));
 181  E :    EXPECT_TRUE(manager_.HasActiveItems());
 182  E :    EXPECT_TRUE(manager_.IsActive(thread_state));
 183  E :    EXPECT_FALSE(manager_.HasDeathRowItems());
 184    :  
 185    :    // Unregister the thread state item.
 186  E :    ASSERT_NO_FATAL_FAILURE(UnregisterThreadState(thread_state));
 187  E :    EXPECT_FALSE(manager_.HasActiveItems());
 188  E :    EXPECT_FALSE(manager_.HasDeathRowItems());
 189    :  
 190    :    // Re-register the thread state item.
 191  E :    ASSERT_NO_FATAL_FAILURE(RegisterThreadState(thread_state));
 192  E :    EXPECT_TRUE(manager_.HasActiveItems());
 193  E :    EXPECT_TRUE(manager_.IsActive(thread_state));
 194  E :    EXPECT_FALSE(manager_.HasDeathRowItems());
 195    :  
 196    :    // Mark the thread state for death.
 197  E :    ASSERT_NO_FATAL_FAILURE(MarkThreadStateForDeath(thread_state));
 198  E :    EXPECT_FALSE(manager_.HasActiveItems());
 199  E :    EXPECT_TRUE(manager_.HasDeathRowItems());
 200  E :    EXPECT_TRUE(manager_.IsOnDeathRow(thread_state));
 201    :  
 202    :    // A list to which we'll scavenge thread state items.
 203  E :    bool has_items = false;
 204    :    LIST_ENTRY dead_items;
 205  E :    InitializeListHead(&dead_items);
 206    :  
 207    :    // Scavenge from death row while the thread is still running. Note that we
 208    :    // test this using the internal function that usually isn't exposed to
 209    :    // callers.
 210  E :    manager_.Scavenge(NULL, &has_items);
 211  E :    EXPECT_TRUE(has_items);
 212  E :    EXPECT_TRUE(IsListEmpty(&dead_items));
 213  E :    EXPECT_FALSE(manager_.HasActiveItems());
 214  E :    EXPECT_TRUE(manager_.HasDeathRowItems());
 215  E :    EXPECT_TRUE(manager_.IsOnDeathRow(thread_state));
 216    :  
 217    :    // Stop thread then scavenge from death row. Note that we test this using
 218    :    // the internal function that usually isn't exposed to callers.
 219  E :    worker_thread_.Stop();
 220  E :    EXPECT_TRUE(manager_.IsThreadDead(thread_state));
 221  E :    EXPECT_CALL(*thread_state, OnDestruction());
 222  E :    manager_.Scavenge(NULL, &has_items);
 223  E :    EXPECT_FALSE(has_items);
 224  E :    EXPECT_FALSE(manager_.HasActiveItems());
 225  E :    EXPECT_FALSE(manager_.HasDeathRowItems());
 226  E :  }
 227    :  
 228    :  }  // namespace common
 229    :  }  // namespace agent

Coverage information generated Thu Jul 04 09:34:53 2013.