Home | History | Annotate | Download | only in win
      1 // Copyright (c) 2012 The Chromium 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 // Unit tests for event trace consumer base class.
      6 #include "base/win/event_trace_consumer.h"
      7 
      8 #include <list>
      9 
     10 #include <objbase.h>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/file_util.h"
     14 #include "base/files/file_path.h"
     15 #include "base/files/scoped_temp_dir.h"
     16 #include "base/logging.h"
     17 #include "base/process/process.h"
     18 #include "base/strings/stringprintf.h"
     19 #include "base/win/event_trace_controller.h"
     20 #include "base/win/event_trace_provider.h"
     21 #include "base/win/scoped_handle.h"
     22 #include "testing/gtest/include/gtest/gtest.h"
     23 
     24 #include <initguid.h>  // NOLINT - has to be last
     25 
     26 namespace base {
     27 namespace win {
     28 
     29 namespace {
     30 
     31 typedef std::list<EVENT_TRACE> EventQueue;
     32 
     33 class TestConsumer: public EtwTraceConsumerBase<TestConsumer> {
     34  public:
     35   TestConsumer() {
     36     sank_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
     37     ClearQueue();
     38   }
     39 
     40   ~TestConsumer() {
     41     ClearQueue();
     42     sank_event_.Close();
     43   }
     44 
     45   void ClearQueue() {
     46     EventQueue::const_iterator it(events_.begin()), end(events_.end());
     47 
     48     for (; it != end; ++it) {
     49       delete [] it->MofData;
     50     }
     51 
     52     events_.clear();
     53   }
     54 
     55   static void EnqueueEvent(EVENT_TRACE* event) {
     56     events_.push_back(*event);
     57     EVENT_TRACE& back = events_.back();
     58 
     59     if (NULL != event->MofData && 0 != event->MofLength) {
     60       back.MofData = new char[event->MofLength];
     61       memcpy(back.MofData, event->MofData, event->MofLength);
     62     }
     63   }
     64 
     65   static void ProcessEvent(EVENT_TRACE* event) {
     66     EnqueueEvent(event);
     67     ::SetEvent(sank_event_.Get());
     68   }
     69 
     70   static ScopedHandle sank_event_;
     71   static EventQueue events_;
     72 
     73  private:
     74   DISALLOW_COPY_AND_ASSIGN(TestConsumer);
     75 };
     76 
     77 ScopedHandle TestConsumer::sank_event_;
     78 EventQueue TestConsumer::events_;
     79 
     80 class EtwTraceConsumerBaseTest: public testing::Test {
     81  public:
     82   EtwTraceConsumerBaseTest()
     83       : session_name_(StringPrintf(L"TestSession-%d",
     84                                    Process::Current().pid())) {
     85   }
     86 
     87   virtual void SetUp() {
     88     // Cleanup any potentially dangling sessions.
     89     EtwTraceProperties ignore;
     90     EtwTraceController::Stop(session_name_.c_str(), &ignore);
     91 
     92     // Allocate a new GUID for each provider test.
     93     ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
     94   }
     95 
     96   virtual void TearDown() {
     97     // Cleanup any potentially danging sessions.
     98     EtwTraceProperties ignore;
     99     EtwTraceController::Stop(session_name_.c_str(), &ignore);
    100   }
    101 
    102  protected:
    103   GUID test_provider_;
    104   std::wstring session_name_;
    105 };
    106 
    107 }  // namespace
    108 
    109 TEST_F(EtwTraceConsumerBaseTest, Initialize) {
    110   TestConsumer consumer_;
    111 }
    112 
    113 TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) {
    114   TestConsumer consumer_;
    115 
    116   ASSERT_HRESULT_SUCCEEDED(
    117       consumer_.OpenRealtimeSession(session_name_.c_str()));
    118 }
    119 
    120 TEST_F(EtwTraceConsumerBaseTest, ConsumerImmediateFailureWhenNoSession) {
    121   TestConsumer consumer_;
    122 
    123   ASSERT_HRESULT_SUCCEEDED(
    124       consumer_.OpenRealtimeSession(session_name_.c_str()));
    125   ASSERT_HRESULT_FAILED(consumer_.Consume());
    126 }
    127 
    128 namespace {
    129 
    130 class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
    131  public:
    132   virtual void SetUp() {
    133     EtwTraceConsumerBaseTest::SetUp();
    134 
    135     ASSERT_HRESULT_SUCCEEDED(
    136         consumer_.OpenRealtimeSession(session_name_.c_str()));
    137   }
    138 
    139   virtual void TearDown() {
    140     consumer_.Close();
    141 
    142     EtwTraceConsumerBaseTest::TearDown();
    143   }
    144 
    145   DWORD ConsumerThread() {
    146     ::SetEvent(consumer_ready_.Get());
    147 
    148     HRESULT hr = consumer_.Consume();
    149     return hr;
    150   }
    151 
    152   static DWORD WINAPI ConsumerThreadMainProc(void* arg) {
    153     return reinterpret_cast<EtwTraceConsumerRealtimeTest*>(arg)->
    154         ConsumerThread();
    155   }
    156 
    157   HRESULT StartConsumerThread() {
    158     consumer_ready_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
    159     EXPECT_TRUE(consumer_ready_ != NULL);
    160     consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc,
    161         this, 0, NULL));
    162     if (NULL == consumer_thread_.Get())
    163       return HRESULT_FROM_WIN32(::GetLastError());
    164 
    165     HRESULT hr = S_OK;
    166     HANDLE events[] = { consumer_ready_, consumer_thread_ };
    167     DWORD result = ::WaitForMultipleObjects(arraysize(events), events,
    168                                             FALSE, INFINITE);
    169     switch (result) {
    170       case WAIT_OBJECT_0:
    171         // The event was set, the consumer_ is ready.
    172         return S_OK;
    173       case WAIT_OBJECT_0 + 1: {
    174           // The thread finished. This may race with the event, so check
    175           // explicitly for the event here, before concluding there's trouble.
    176           if (WAIT_OBJECT_0 == ::WaitForSingleObject(consumer_ready_, 0))
    177             return S_OK;
    178           DWORD exit_code = 0;
    179           if (::GetExitCodeThread(consumer_thread_, &exit_code))
    180             return exit_code;
    181           else
    182             return HRESULT_FROM_WIN32(::GetLastError());
    183           break;
    184         }
    185       default:
    186         return E_UNEXPECTED;
    187         break;
    188     }
    189 
    190     return hr;
    191   }
    192 
    193   // Waits for consumer_ thread to exit, and returns its exit code.
    194   HRESULT JoinConsumerThread() {
    195     if (WAIT_OBJECT_0 != ::WaitForSingleObject(consumer_thread_, INFINITE))
    196       return HRESULT_FROM_WIN32(::GetLastError());
    197 
    198     DWORD exit_code = 0;
    199     if (::GetExitCodeThread(consumer_thread_, &exit_code))
    200       return exit_code;
    201 
    202     return HRESULT_FROM_WIN32(::GetLastError());
    203   }
    204 
    205   TestConsumer consumer_;
    206   ScopedHandle consumer_ready_;
    207   ScopedHandle consumer_thread_;
    208 };
    209 
    210 }  // namespace
    211 
    212 TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) {
    213   EtwTraceController controller;
    214 
    215   HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
    216                                                100 * 1024);
    217   if (hr == E_ACCESSDENIED) {
    218     VLOG(1) << "You must be an administrator to run this test on Vista";
    219     return;
    220   }
    221 
    222   // Start the consumer_.
    223   ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
    224 
    225   // Wait around for the consumer_ thread a bit.
    226   ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_, 50));
    227 
    228   ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
    229 
    230   // The consumer_ returns success on session stop.
    231   ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
    232 }
    233 
    234 namespace {
    235 
    236 // {57E47923-A549-476f-86CA-503D57F59E62}
    237 DEFINE_GUID(kTestEventType,
    238   0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
    239 
    240 }  // namespace
    241 
    242 TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) {
    243   EtwTraceController controller;
    244   HRESULT hr = controller.StartRealtimeSession(session_name_.c_str(),
    245                                                100 * 1024);
    246   if (hr == E_ACCESSDENIED) {
    247     VLOG(1) << "You must be an administrator to run this test on Vista";
    248     return;
    249   }
    250 
    251   ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
    252       TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
    253 
    254   EtwTraceProvider provider(test_provider_);
    255   ASSERT_EQ(ERROR_SUCCESS, provider.Register());
    256 
    257   // Start the consumer_.
    258   ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
    259 
    260   ASSERT_EQ(0, TestConsumer::events_.size());
    261 
    262   EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
    263   EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header));
    264 
    265   EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(TestConsumer::sank_event_,
    266                                                  INFINITE));
    267   ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
    268   ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
    269   ASSERT_NE(0u, TestConsumer::events_.size());
    270 }
    271 
    272 namespace {
    273 
    274 // We run events through a file session to assert that
    275 // the content comes through.
    276 class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest {
    277  public:
    278   EtwTraceConsumerDataTest() {
    279   }
    280 
    281   virtual void SetUp() {
    282     EtwTraceConsumerBaseTest::SetUp();
    283 
    284     EtwTraceProperties prop;
    285     EtwTraceController::Stop(session_name_.c_str(), &prop);
    286 
    287     // Create a temp dir for this test.
    288     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    289     // Construct a temp file name in our dir.
    290     temp_file_ = temp_dir_.path().Append(L"test.etl");
    291   }
    292 
    293   virtual void TearDown() {
    294     EXPECT_TRUE(base::DeleteFile(temp_file_, false));
    295 
    296     EtwTraceConsumerBaseTest::TearDown();
    297   }
    298 
    299   HRESULT LogEventToTempSession(PEVENT_TRACE_HEADER header) {
    300     EtwTraceController controller;
    301 
    302     // Set up a file session.
    303     HRESULT hr = controller.StartFileSession(session_name_.c_str(),
    304                                              temp_file_.value().c_str());
    305     if (FAILED(hr))
    306       return hr;
    307 
    308     // Enable our provider.
    309     EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(test_provider_,
    310         TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
    311 
    312     EtwTraceProvider provider(test_provider_);
    313     // Then register our provider, means we get a session handle immediately.
    314     EXPECT_EQ(ERROR_SUCCESS, provider.Register());
    315     // Trace the event, it goes to the temp file.
    316     EXPECT_EQ(ERROR_SUCCESS, provider.Log(header));
    317     EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
    318     EXPECT_HRESULT_SUCCEEDED(provider.Unregister());
    319     EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL));
    320     EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
    321 
    322     return S_OK;
    323   }
    324 
    325   HRESULT ConsumeEventFromTempSession() {
    326     // Now consume the event(s).
    327     TestConsumer consumer_;
    328     HRESULT hr = consumer_.OpenFileSession(temp_file_.value().c_str());
    329     if (SUCCEEDED(hr))
    330       hr = consumer_.Consume();
    331     consumer_.Close();
    332     // And nab the result.
    333     events_.swap(TestConsumer::events_);
    334     return hr;
    335   }
    336 
    337   HRESULT RoundTripEvent(PEVENT_TRACE_HEADER header, PEVENT_TRACE* trace) {
    338     base::DeleteFile(temp_file_, false);
    339 
    340     HRESULT hr = LogEventToTempSession(header);
    341     if (SUCCEEDED(hr))
    342       hr = ConsumeEventFromTempSession();
    343 
    344     if (FAILED(hr))
    345       return hr;
    346 
    347     // We should now have the event in the queue.
    348     if (events_.empty())
    349       return E_FAIL;
    350 
    351     *trace = &events_.back();
    352     return S_OK;
    353   }
    354 
    355   EventQueue events_;
    356   ScopedTempDir temp_dir_;
    357   FilePath temp_file_;
    358 };
    359 
    360 }  // namespace
    361 
    362 
    363 TEST_F(EtwTraceConsumerDataTest, RoundTrip) {
    364   EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
    365 
    366   static const char kData[] = "This is but test data";
    367   event.fields[0].DataPtr = reinterpret_cast<ULONG64>(kData);
    368   event.fields[0].Length = sizeof(kData);
    369 
    370   PEVENT_TRACE trace = NULL;
    371   HRESULT hr = RoundTripEvent(&event.header, &trace);
    372   if (hr == E_ACCESSDENIED) {
    373     VLOG(1) << "You must be an administrator to run this test on Vista";
    374     return;
    375   }
    376   ASSERT_HRESULT_SUCCEEDED(hr) << "RoundTripEvent failed";
    377   ASSERT_TRUE(NULL != trace);
    378   ASSERT_EQ(sizeof(kData), trace->MofLength);
    379   ASSERT_STREQ(kData, reinterpret_cast<const char*>(trace->MofData));
    380 }
    381 
    382 }  // namespace win
    383 }  // namespace base
    384