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/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
31 typedef std::list
<EVENT_TRACE
> EventQueue
;
33 class TestConsumer
: public EtwTraceConsumerBase
<TestConsumer
> {
36 sank_event_
.Set(::CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
46 for (EventQueue::const_iterator
it(events_
.begin()), end(events_
.end());
48 delete[] reinterpret_cast<char*>(it
->MofData
);
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
) {
66 ::SetEvent(sank_event_
.Get());
69 static ScopedHandle sank_event_
;
70 static EventQueue events_
;
73 DISALLOW_COPY_AND_ASSIGN(TestConsumer
);
76 ScopedHandle
TestConsumer::sank_event_
;
77 EventQueue
TestConsumer::events_
;
79 class EtwTraceConsumerBaseTest
: public testing::Test
{
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
);
102 std::wstring session_name_
;
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());
126 class EtwTraceConsumerRealtimeTest
: public EtwTraceConsumerBaseTest
{
128 void SetUp() override
{
129 EtwTraceConsumerBaseTest::SetUp();
130 ASSERT_HRESULT_SUCCEEDED(
131 consumer_
.OpenRealtimeSession(session_name_
.c_str()));
134 void TearDown() override
{
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
)->
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,
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
,
162 // The event was set, the consumer_ is ready.
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
)
170 if (::GetExitCodeThread(consumer_thread_
.Get(), &exit_code
))
172 return HRESULT_FROM_WIN32(::GetLastError());
179 // Waits for consumer_ thread to exit, and returns its exit code.
180 HRESULT
JoinConsumerThread() {
181 if (::WaitForSingleObject(consumer_thread_
.Get(), INFINITE
) !=
183 return HRESULT_FROM_WIN32(::GetLastError());
187 if (::GetExitCodeThread(consumer_thread_
.Get(), &exit_code
))
190 return HRESULT_FROM_WIN32(::GetLastError());
193 TestConsumer consumer_
;
194 ScopedHandle consumer_ready_
;
195 ScopedHandle consumer_thread_
;
200 TEST_F(EtwTraceConsumerRealtimeTest
, ConsumerReturnsWhenSessionClosed
) {
201 EtwTraceController controller
;
202 if (controller
.StartRealtimeSession(session_name_
.c_str(), 100 * 1024) ==
204 VLOG(1) << "You must be an administrator to run this test on Vista";
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());
221 // {57E47923-A549-476f-86CA-503D57F59E62}
224 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
228 TEST_F(EtwTraceConsumerRealtimeTest
, ConsumeEvent
) {
229 EtwTraceController controller
;
230 if (controller
.StartRealtimeSession(session_name_
.c_str(), 100 * 1024) ==
232 VLOG(1) << "You must be an administrator to run this test on Vista";
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());
257 // We run events through a file session to assert that
258 // the content comes through.
259 class EtwTraceConsumerDataTest
: public EtwTraceConsumerBaseTest
{
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());
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
));
308 HRESULT
ConsumeEventFromTempSession() {
309 // Now consume the event(s).
310 TestConsumer consumer_
;
311 HRESULT hr
= consumer_
.OpenFileSession(temp_file_
.value().c_str());
313 hr
= consumer_
.Consume();
315 // And nab the result.
316 events_
.swap(TestConsumer::events_
);
320 HRESULT
RoundTripEvent(PEVENT_TRACE_HEADER header
, PEVENT_TRACE
* trace
) {
321 base::DeleteFile(temp_file_
, false);
323 HRESULT hr
= LogEventToTempSession(header
);
325 hr
= ConsumeEventFromTempSession();
330 // We should now have the event in the queue.
334 *trace
= &events_
.back();
339 ScopedTempDir temp_dir_
;
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";
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
));