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