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.
5 // Unit tests for event trace consumer base class.
6 #include "base/win/event_trace_consumer.h"
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"
24 #include <initguid.h> // NOLINT - has to be last
31 typedef std::list
<EVENT_TRACE
> EventQueue
;
33 class TestConsumer
: public EtwTraceConsumerBase
<TestConsumer
> {
36 sank_event_
.Set(::CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
46 EventQueue::const_iterator
it(events_
.begin()), end(events_
.end());
48 for (; it
!= end
; ++it
) {
49 delete [] it
->MofData
;
55 static void EnqueueEvent(EVENT_TRACE
* event
) {
56 events_
.push_back(*event
);
57 EVENT_TRACE
& back
= events_
.back();
59 if (NULL
!= event
->MofData
&& 0 != event
->MofLength
) {
60 back
.MofData
= new char[event
->MofLength
];
61 memcpy(back
.MofData
, event
->MofData
, event
->MofLength
);
65 static void ProcessEvent(EVENT_TRACE
* event
) {
67 ::SetEvent(sank_event_
.Get());
70 static ScopedHandle sank_event_
;
71 static EventQueue events_
;
74 DISALLOW_COPY_AND_ASSIGN(TestConsumer
);
77 ScopedHandle
TestConsumer::sank_event_
;
78 EventQueue
TestConsumer::events_
;
80 class EtwTraceConsumerBaseTest
: public testing::Test
{
82 EtwTraceConsumerBaseTest()
83 : session_name_(StringPrintf(L
"TestSession-%d",
84 Process::Current().pid())) {
87 virtual void SetUp() {
88 // Cleanup any potentially dangling sessions.
89 EtwTraceProperties ignore
;
90 EtwTraceController::Stop(session_name_
.c_str(), &ignore
);
92 // Allocate a new GUID for each provider test.
93 ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_
));
96 virtual void TearDown() {
97 // Cleanup any potentially danging sessions.
98 EtwTraceProperties ignore
;
99 EtwTraceController::Stop(session_name_
.c_str(), &ignore
);
104 std::wstring session_name_
;
109 TEST_F(EtwTraceConsumerBaseTest
, Initialize
) {
110 TestConsumer consumer_
;
113 TEST_F(EtwTraceConsumerBaseTest
, OpenRealtimeSucceedsWhenNoSession
) {
114 TestConsumer consumer_
;
116 ASSERT_HRESULT_SUCCEEDED(
117 consumer_
.OpenRealtimeSession(session_name_
.c_str()));
120 TEST_F(EtwTraceConsumerBaseTest
, ConsumerImmediateFailureWhenNoSession
) {
121 TestConsumer consumer_
;
123 ASSERT_HRESULT_SUCCEEDED(
124 consumer_
.OpenRealtimeSession(session_name_
.c_str()));
125 ASSERT_HRESULT_FAILED(consumer_
.Consume());
130 class EtwTraceConsumerRealtimeTest
: public EtwTraceConsumerBaseTest
{
132 virtual void SetUp() {
133 EtwTraceConsumerBaseTest::SetUp();
135 ASSERT_HRESULT_SUCCEEDED(
136 consumer_
.OpenRealtimeSession(session_name_
.c_str()));
139 virtual void TearDown() {
142 EtwTraceConsumerBaseTest::TearDown();
145 DWORD
ConsumerThread() {
146 ::SetEvent(consumer_ready_
.Get());
148 HRESULT hr
= consumer_
.Consume();
152 static DWORD WINAPI
ConsumerThreadMainProc(void* arg
) {
153 return reinterpret_cast<EtwTraceConsumerRealtimeTest
*>(arg
)->
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
,
162 if (NULL
== consumer_thread_
.Get())
163 return HRESULT_FROM_WIN32(::GetLastError());
166 HANDLE events
[] = { consumer_ready_
, consumer_thread_
};
167 DWORD result
= ::WaitForMultipleObjects(arraysize(events
), events
,
171 // The event was set, the consumer_ is ready.
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))
179 if (::GetExitCodeThread(consumer_thread_
, &exit_code
))
182 return HRESULT_FROM_WIN32(::GetLastError());
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());
199 if (::GetExitCodeThread(consumer_thread_
, &exit_code
))
202 return HRESULT_FROM_WIN32(::GetLastError());
205 TestConsumer consumer_
;
206 ScopedHandle consumer_ready_
;
207 ScopedHandle consumer_thread_
;
212 TEST_F(EtwTraceConsumerRealtimeTest
, ConsumerReturnsWhenSessionClosed
) {
213 EtwTraceController controller
;
215 HRESULT hr
= controller
.StartRealtimeSession(session_name_
.c_str(),
217 if (hr
== E_ACCESSDENIED
) {
218 VLOG(1) << "You must be an administrator to run this test on Vista";
222 // Start the consumer_.
223 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
225 // Wait around for the consumer_ thread a bit.
226 ASSERT_EQ(WAIT_TIMEOUT
, ::WaitForSingleObject(consumer_thread_
, 50));
228 ASSERT_HRESULT_SUCCEEDED(controller
.Stop(NULL
));
230 // The consumer_ returns success on session stop.
231 ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
236 // {57E47923-A549-476f-86CA-503D57F59E62}
237 DEFINE_GUID(kTestEventType
,
238 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
242 TEST_F(EtwTraceConsumerRealtimeTest
, ConsumeEvent
) {
243 EtwTraceController controller
;
244 HRESULT hr
= controller
.StartRealtimeSession(session_name_
.c_str(),
246 if (hr
== E_ACCESSDENIED
) {
247 VLOG(1) << "You must be an administrator to run this test on Vista";
251 ASSERT_HRESULT_SUCCEEDED(controller
.EnableProvider(test_provider_
,
252 TRACE_LEVEL_VERBOSE
, 0xFFFFFFFF));
254 EtwTraceProvider
provider(test_provider_
);
255 ASSERT_EQ(ERROR_SUCCESS
, provider
.Register());
257 // Start the consumer_.
258 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
260 ASSERT_EQ(0, TestConsumer::events_
.size());
262 EtwMofEvent
<1> event(kTestEventType
, 1, TRACE_LEVEL_ERROR
);
263 EXPECT_EQ(ERROR_SUCCESS
, provider
.Log(&event
.header
));
265 EXPECT_EQ(WAIT_OBJECT_0
, ::WaitForSingleObject(TestConsumer::sank_event_
,
267 ASSERT_HRESULT_SUCCEEDED(controller
.Stop(NULL
));
268 ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
269 ASSERT_NE(0u, TestConsumer::events_
.size());
274 // We run events through a file session to assert that
275 // the content comes through.
276 class EtwTraceConsumerDataTest
: public EtwTraceConsumerBaseTest
{
278 EtwTraceConsumerDataTest() {
281 virtual void SetUp() {
282 EtwTraceConsumerBaseTest::SetUp();
284 EtwTraceProperties prop
;
285 EtwTraceController::Stop(session_name_
.c_str(), &prop
);
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");
293 virtual void TearDown() {
294 EXPECT_TRUE(base::DeleteFile(temp_file_
, false));
296 EtwTraceConsumerBaseTest::TearDown();
299 HRESULT
LogEventToTempSession(PEVENT_TRACE_HEADER header
) {
300 EtwTraceController controller
;
302 // Set up a file session.
303 HRESULT hr
= controller
.StartFileSession(session_name_
.c_str(),
304 temp_file_
.value().c_str());
308 // Enable our provider.
309 EXPECT_HRESULT_SUCCEEDED(controller
.EnableProvider(test_provider_
,
310 TRACE_LEVEL_VERBOSE
, 0xFFFFFFFF));
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
));
325 HRESULT
ConsumeEventFromTempSession() {
326 // Now consume the event(s).
327 TestConsumer consumer_
;
328 HRESULT hr
= consumer_
.OpenFileSession(temp_file_
.value().c_str());
330 hr
= consumer_
.Consume();
332 // And nab the result.
333 events_
.swap(TestConsumer::events_
);
337 HRESULT
RoundTripEvent(PEVENT_TRACE_HEADER header
, PEVENT_TRACE
* trace
) {
338 base::DeleteFile(temp_file_
, false);
340 HRESULT hr
= LogEventToTempSession(header
);
342 hr
= ConsumeEventFromTempSession();
347 // We should now have the event in the queue.
351 *trace
= &events_
.back();
356 ScopedTempDir temp_dir_
;
363 TEST_F(EtwTraceConsumerDataTest
, RoundTrip
) {
364 EtwMofEvent
<1> event(kTestEventType
, 1, TRACE_LEVEL_ERROR
);
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
);
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";
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
));