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