Refactored not to expose raw pointers on ProxyList class.
[chromium-blink-merge.git] / base / win / event_trace_consumer_unittest.cc
blobecbf238bea48c88429e22930957e10bdf82280ab
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"
8 #include <list>
10 #include <objbase.h>
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"
24 #include <initguid.h> // NOLINT - has to be last
26 namespace base {
27 namespace win {
29 namespace {
31 typedef std::list<EVENT_TRACE> EventQueue;
33 class TestConsumer: public EtwTraceConsumerBase<TestConsumer> {
34 public:
35 TestConsumer() {
36 sank_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
37 ClearQueue();
40 ~TestConsumer() {
41 ClearQueue();
42 sank_event_.Close();
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);
51 events_.clear();
54 static void EnqueueEvent(EVENT_TRACE* event) {
55 events_.push_back(*event);
56 EVENT_TRACE& back = events_.back();
58 if (event->MofData != NULL && event->MofLength != 0) {
59 back.MofData = new char[event->MofLength];
60 memcpy(back.MofData, event->MofData, event->MofLength);
64 static void ProcessEvent(EVENT_TRACE* event) {
65 EnqueueEvent(event);
66 ::SetEvent(sank_event_.Get());
69 static ScopedHandle sank_event_;
70 static EventQueue events_;
72 private:
73 DISALLOW_COPY_AND_ASSIGN(TestConsumer);
76 ScopedHandle TestConsumer::sank_event_;
77 EventQueue TestConsumer::events_;
79 class EtwTraceConsumerBaseTest: public testing::Test {
80 public:
81 EtwTraceConsumerBaseTest()
82 : session_name_(StringPrintf(L"TestSession-%d", GetCurrentProcId())) {
85 void SetUp() override {
86 // Cleanup any potentially dangling sessions.
87 EtwTraceProperties ignore;
88 EtwTraceController::Stop(session_name_.c_str(), &ignore);
90 // Allocate a new GUID for each provider test.
91 ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
94 void TearDown() override {
95 // Cleanup any potentially dangling sessions.
96 EtwTraceProperties ignore;
97 EtwTraceController::Stop(session_name_.c_str(), &ignore);
100 protected:
101 GUID test_provider_;
102 std::wstring session_name_;
105 } // namespace
107 TEST_F(EtwTraceConsumerBaseTest, Initialize) {
108 TestConsumer consumer_;
111 TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) {
112 TestConsumer consumer_;
113 ASSERT_HRESULT_SUCCEEDED(
114 consumer_.OpenRealtimeSession(session_name_.c_str()));
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());
124 namespace {
126 class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
127 public:
128 void SetUp() override {
129 EtwTraceConsumerBaseTest::SetUp();
130 ASSERT_HRESULT_SUCCEEDED(
131 consumer_.OpenRealtimeSession(session_name_.c_str()));
134 void TearDown() override {
135 consumer_.Close();
136 EtwTraceConsumerBaseTest::TearDown();
139 DWORD ConsumerThread() {
140 ::SetEvent(consumer_ready_.Get());
141 return consumer_.Consume();
144 static DWORD WINAPI ConsumerThreadMainProc(void* arg) {
145 return reinterpret_cast<EtwTraceConsumerRealtimeTest*>(arg)->
146 ConsumerThread();
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());
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());
174 default:
175 return E_UNEXPECTED;
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());
186 DWORD exit_code = 0;
187 if (::GetExitCodeThread(consumer_thread_.Get(), &exit_code))
188 return exit_code;
190 return HRESULT_FROM_WIN32(::GetLastError());
193 TestConsumer consumer_;
194 ScopedHandle consumer_ready_;
195 ScopedHandle consumer_thread_;
198 } // namespace
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;
208 // Start the consumer_.
209 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
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));
215 // The consumer_ returns success on session stop.
216 ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
219 namespace {
221 // {57E47923-A549-476f-86CA-503D57F59E62}
222 DEFINE_GUID(
223 kTestEventType,
224 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
226 } // namespace
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;
236 ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(
237 test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
239 EtwTraceProvider provider(test_provider_);
240 ASSERT_EQ(ERROR_SUCCESS, provider.Register());
242 // Start the consumer_.
243 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
244 ASSERT_EQ(0, TestConsumer::events_.size());
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());
255 namespace {
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() {
264 void SetUp() override {
265 EtwTraceConsumerBaseTest::SetUp();
267 EtwTraceProperties prop;
268 EtwTraceController::Stop(session_name_.c_str(), &prop);
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");
276 void TearDown() override {
277 EXPECT_TRUE(base::DeleteFile(temp_file_, false));
279 EtwTraceConsumerBaseTest::TearDown();
282 HRESULT LogEventToTempSession(PEVENT_TRACE_HEADER header) {
283 EtwTraceController controller;
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;
291 // Enable our provider.
292 EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(
293 test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
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));
305 return S_OK;
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;
320 HRESULT RoundTripEvent(PEVENT_TRACE_HEADER header, PEVENT_TRACE* trace) {
321 base::DeleteFile(temp_file_, false);
323 HRESULT hr = LogEventToTempSession(header);
324 if (SUCCEEDED(hr))
325 hr = ConsumeEventFromTempSession();
327 if (FAILED(hr))
328 return hr;
330 // We should now have the event in the queue.
331 if (events_.empty())
332 return E_FAIL;
334 *trace = &events_.back();
335 return S_OK;
338 EventQueue events_;
339 ScopedTempDir temp_dir_;
340 FilePath temp_file_;
343 } // namespace
346 TEST_F(EtwTraceConsumerDataTest, RoundTrip) {
347 EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
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);
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;
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));
365 } // namespace win
366 } // namespace base