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