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.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",
83 Process::Current().pid())) {
86 virtual void SetUp() {
87 // Cleanup any potentially dangling sessions.
88 EtwTraceProperties ignore
;
89 EtwTraceController::Stop(session_name_
.c_str(), &ignore
);
91 // Allocate a new GUID for each provider test.
92 ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_
));
95 virtual void TearDown() {
96 // Cleanup any potentially dangling sessions.
97 EtwTraceProperties ignore
;
98 EtwTraceController::Stop(session_name_
.c_str(), &ignore
);
103 std::wstring session_name_
;
108 TEST_F(EtwTraceConsumerBaseTest
, Initialize
) {
109 TestConsumer consumer_
;
112 TEST_F(EtwTraceConsumerBaseTest
, OpenRealtimeSucceedsWhenNoSession
) {
113 TestConsumer consumer_
;
114 ASSERT_HRESULT_SUCCEEDED(
115 consumer_
.OpenRealtimeSession(session_name_
.c_str()));
118 TEST_F(EtwTraceConsumerBaseTest
, ConsumerImmediateFailureWhenNoSession
) {
119 TestConsumer consumer_
;
120 ASSERT_HRESULT_SUCCEEDED(
121 consumer_
.OpenRealtimeSession(session_name_
.c_str()));
122 ASSERT_HRESULT_FAILED(consumer_
.Consume());
127 class EtwTraceConsumerRealtimeTest
: public EtwTraceConsumerBaseTest
{
129 virtual void SetUp() {
130 EtwTraceConsumerBaseTest::SetUp();
131 ASSERT_HRESULT_SUCCEEDED(
132 consumer_
.OpenRealtimeSession(session_name_
.c_str()));
135 virtual void TearDown() {
137 EtwTraceConsumerBaseTest::TearDown();
140 DWORD
ConsumerThread() {
141 ::SetEvent(consumer_ready_
.Get());
142 return consumer_
.Consume();
145 static DWORD WINAPI
ConsumerThreadMainProc(void* arg
) {
146 return reinterpret_cast<EtwTraceConsumerRealtimeTest
*>(arg
)->
150 HRESULT
StartConsumerThread() {
151 consumer_ready_
.Set(::CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
152 EXPECT_TRUE(consumer_ready_
!= NULL
);
153 consumer_thread_
.Set(::CreateThread(NULL
, 0, ConsumerThreadMainProc
, this,
155 if (consumer_thread_
.Get() == NULL
)
156 return HRESULT_FROM_WIN32(::GetLastError());
158 HANDLE events
[] = { consumer_ready_
, consumer_thread_
};
159 DWORD result
= ::WaitForMultipleObjects(arraysize(events
), events
,
163 // The event was set, the consumer_ is ready.
165 case WAIT_OBJECT_0
+ 1: {
166 // The thread finished. This may race with the event, so check
167 // explicitly for the event here, before concluding there's trouble.
168 if (::WaitForSingleObject(consumer_ready_
, 0) == WAIT_OBJECT_0
)
171 if (::GetExitCodeThread(consumer_thread_
, &exit_code
))
173 return HRESULT_FROM_WIN32(::GetLastError());
180 // Waits for consumer_ thread to exit, and returns its exit code.
181 HRESULT
JoinConsumerThread() {
182 if (::WaitForSingleObject(consumer_thread_
, INFINITE
) != WAIT_OBJECT_0
)
183 return HRESULT_FROM_WIN32(::GetLastError());
186 if (::GetExitCodeThread(consumer_thread_
, &exit_code
))
189 return HRESULT_FROM_WIN32(::GetLastError());
192 TestConsumer consumer_
;
193 ScopedHandle consumer_ready_
;
194 ScopedHandle consumer_thread_
;
199 TEST_F(EtwTraceConsumerRealtimeTest
, ConsumerReturnsWhenSessionClosed
) {
200 EtwTraceController controller
;
201 if (controller
.StartRealtimeSession(session_name_
.c_str(), 100 * 1024) ==
203 VLOG(1) << "You must be an administrator to run this test on Vista";
207 // Start the consumer_.
208 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
210 // Wait around for the consumer_ thread a bit.
211 ASSERT_EQ(WAIT_TIMEOUT
, ::WaitForSingleObject(consumer_thread_
, 50));
212 ASSERT_HRESULT_SUCCEEDED(controller
.Stop(NULL
));
214 // The consumer_ returns success on session stop.
215 ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
220 // {57E47923-A549-476f-86CA-503D57F59E62}
223 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
227 TEST_F(EtwTraceConsumerRealtimeTest
, ConsumeEvent
) {
228 EtwTraceController controller
;
229 if (controller
.StartRealtimeSession(session_name_
.c_str(), 100 * 1024) ==
231 VLOG(1) << "You must be an administrator to run this test on Vista";
235 ASSERT_HRESULT_SUCCEEDED(controller
.EnableProvider(
236 test_provider_
, TRACE_LEVEL_VERBOSE
, 0xFFFFFFFF));
238 EtwTraceProvider
provider(test_provider_
);
239 ASSERT_EQ(ERROR_SUCCESS
, provider
.Register());
241 // Start the consumer_.
242 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
243 ASSERT_EQ(0, TestConsumer::events_
.size());
245 EtwMofEvent
<1> event(kTestEventType
, 1, TRACE_LEVEL_ERROR
);
246 EXPECT_EQ(ERROR_SUCCESS
, provider
.Log(&event
.header
));
247 EXPECT_EQ(WAIT_OBJECT_0
, ::WaitForSingleObject(TestConsumer::sank_event_
,
249 ASSERT_HRESULT_SUCCEEDED(controller
.Stop(NULL
));
250 ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
251 ASSERT_NE(0u, TestConsumer::events_
.size());
256 // We run events through a file session to assert that
257 // the content comes through.
258 class EtwTraceConsumerDataTest
: public EtwTraceConsumerBaseTest
{
260 EtwTraceConsumerDataTest() {
263 virtual void SetUp() {
264 EtwTraceConsumerBaseTest::SetUp();
266 EtwTraceProperties prop
;
267 EtwTraceController::Stop(session_name_
.c_str(), &prop
);
269 // Create a temp dir for this test.
270 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
271 // Construct a temp file name in our dir.
272 temp_file_
= temp_dir_
.path().Append(L
"test.etl");
275 virtual void TearDown() {
276 EXPECT_TRUE(base::DeleteFile(temp_file_
, false));
278 EtwTraceConsumerBaseTest::TearDown();
281 HRESULT
LogEventToTempSession(PEVENT_TRACE_HEADER header
) {
282 EtwTraceController controller
;
284 // Set up a file session.
285 HRESULT hr
= controller
.StartFileSession(session_name_
.c_str(),
286 temp_file_
.value().c_str());
290 // Enable our provider.
291 EXPECT_HRESULT_SUCCEEDED(controller
.EnableProvider(
292 test_provider_
, TRACE_LEVEL_VERBOSE
, 0xFFFFFFFF));
294 EtwTraceProvider
provider(test_provider_
);
295 // Then register our provider, means we get a session handle immediately.
296 EXPECT_EQ(ERROR_SUCCESS
, provider
.Register());
297 // Trace the event, it goes to the temp file.
298 EXPECT_EQ(ERROR_SUCCESS
, provider
.Log(header
));
299 EXPECT_HRESULT_SUCCEEDED(controller
.DisableProvider(test_provider_
));
300 EXPECT_HRESULT_SUCCEEDED(provider
.Unregister());
301 EXPECT_HRESULT_SUCCEEDED(controller
.Flush(NULL
));
302 EXPECT_HRESULT_SUCCEEDED(controller
.Stop(NULL
));
307 HRESULT
ConsumeEventFromTempSession() {
308 // Now consume the event(s).
309 TestConsumer consumer_
;
310 HRESULT hr
= consumer_
.OpenFileSession(temp_file_
.value().c_str());
312 hr
= consumer_
.Consume();
314 // And nab the result.
315 events_
.swap(TestConsumer::events_
);
319 HRESULT
RoundTripEvent(PEVENT_TRACE_HEADER header
, PEVENT_TRACE
* trace
) {
320 base::DeleteFile(temp_file_
, false);
322 HRESULT hr
= LogEventToTempSession(header
);
324 hr
= ConsumeEventFromTempSession();
329 // We should now have the event in the queue.
333 *trace
= &events_
.back();
338 ScopedTempDir temp_dir_
;
345 TEST_F(EtwTraceConsumerDataTest
, RoundTrip
) {
346 EtwMofEvent
<1> event(kTestEventType
, 1, TRACE_LEVEL_ERROR
);
348 static const char kData
[] = "This is but test data";
349 event
.fields
[0].DataPtr
= reinterpret_cast<ULONG64
>(kData
);
350 event
.fields
[0].Length
= sizeof(kData
);
352 PEVENT_TRACE trace
= NULL
;
353 HRESULT hr
= RoundTripEvent(&event
.header
, &trace
);
354 if (hr
== E_ACCESSDENIED
) {
355 VLOG(1) << "You must be an administrator to run this test on Vista";
358 ASSERT_HRESULT_SUCCEEDED(hr
) << "RoundTripEvent failed";
359 ASSERT_TRUE(trace
!= NULL
);
360 ASSERT_EQ(sizeof(kData
), trace
->MofLength
);
361 ASSERT_STREQ(kData
, reinterpret_cast<const char*>(trace
->MofData
));