- add sources.
[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/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