1 // Copyright (c) 2009 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/event_trace_consumer_win.h"
8 #include "base/basictypes.h"
9 #include "base/event_trace_controller_win.h"
10 #include "base/event_trace_provider_win.h"
11 #include "base/file_path.h"
12 #include "base/file_util.h"
13 #include "base/logging.h"
14 #include "base/scoped_handle.h"
15 #include "testing/gtest/include/gtest/gtest.h"
17 #include <initguid.h> // NOLINT - has to be last
21 typedef std::list
<EVENT_TRACE
> EventQueue
;
23 class TestConsumer
: public EtwTraceConsumerBase
<TestConsumer
> {
26 sank_event_
.Set(::CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
36 EventQueue::const_iterator
it(events_
.begin()), end(events_
.end());
38 for (; it
!= end
; ++it
) {
39 delete [] it
->MofData
;
45 static void EnqueueEvent(EVENT_TRACE
* event
) {
46 events_
.push_back(*event
);
47 EVENT_TRACE
& back
= events_
.back();
49 if (NULL
!= event
->MofData
&& 0 != event
->MofLength
) {
50 back
.MofData
= new char[event
->MofLength
];
51 memcpy(back
.MofData
, event
->MofData
, event
->MofLength
);
55 static void ProcessEvent(EVENT_TRACE
* event
) {
57 ::SetEvent(sank_event_
.Get());
60 static ScopedHandle sank_event_
;
61 static EventQueue events_
;
64 DISALLOW_COPY_AND_ASSIGN(TestConsumer
);
67 ScopedHandle
TestConsumer::sank_event_
;
68 EventQueue
TestConsumer::events_
;
70 const wchar_t* const kTestSessionName
= L
"TestLogSession";
72 class EtwTraceConsumerBaseTest
: public testing::Test
{
74 virtual void SetUp() {
75 EtwTraceController::Stop(kTestSessionName
, NULL
);
81 TEST_F(EtwTraceConsumerBaseTest
, Initialize
) {
82 TestConsumer consumer_
;
85 TEST_F(EtwTraceConsumerBaseTest
, OpenRealtimeSucceedsWhenNoSession
) {
86 TestConsumer consumer_
;
88 ASSERT_HRESULT_SUCCEEDED(consumer_
.OpenRealtimeSession(kTestSessionName
));
91 TEST_F(EtwTraceConsumerBaseTest
, ConsumerImmediateFailureWhenNoSession
) {
92 TestConsumer consumer_
;
94 ASSERT_HRESULT_SUCCEEDED(consumer_
.OpenRealtimeSession(kTestSessionName
));
95 ASSERT_HRESULT_FAILED(consumer_
.Consume());
100 class EtwTraceConsumerRealtimeTest
: public testing::Test
{
102 virtual void SetUp() {
103 ASSERT_HRESULT_SUCCEEDED(consumer_
.OpenRealtimeSession(kTestSessionName
));
106 virtual void TearDown() {
110 DWORD
ConsumerThread() {
111 ::SetEvent(consumer_ready_
.Get());
113 HRESULT hr
= consumer_
.Consume();
117 static DWORD WINAPI
ConsumerThreadMainProc(void* arg
) {
118 return reinterpret_cast<EtwTraceConsumerRealtimeTest
*>(arg
)->
122 HRESULT
StartConsumerThread() {
123 consumer_ready_
.Set(::CreateEvent(NULL
, TRUE
, FALSE
, NULL
));
124 EXPECT_TRUE(consumer_ready_
!= NULL
);
125 consumer_thread_
.Set(::CreateThread(NULL
, 0, ConsumerThreadMainProc
,
127 if (NULL
== consumer_thread_
.Get())
128 return HRESULT_FROM_WIN32(::GetLastError());
131 HANDLE events
[] = { consumer_ready_
, consumer_thread_
};
132 DWORD result
= ::WaitForMultipleObjects(arraysize(events
), events
,
136 // The event was set, the consumer_ is ready.
138 case WAIT_OBJECT_0
+ 1: {
139 // The thread finished. This may race with the event, so check
140 // explicitly for the event here, before concluding there's trouble.
141 if (WAIT_OBJECT_0
== ::WaitForSingleObject(consumer_ready_
, 0))
144 if (::GetExitCodeThread(consumer_thread_
, &exit_code
))
147 return HRESULT_FROM_WIN32(::GetLastError());
158 // Waits for consumer_ thread to exit, and returns its exit code.
159 HRESULT
JoinConsumerThread() {
160 if (WAIT_OBJECT_0
!= ::WaitForSingleObject(consumer_thread_
, INFINITE
))
161 return HRESULT_FROM_WIN32(::GetLastError());
164 if (::GetExitCodeThread(consumer_thread_
, &exit_code
))
167 return HRESULT_FROM_WIN32(::GetLastError());
170 TestConsumer consumer_
;
171 ScopedHandle consumer_ready_
;
172 ScopedHandle consumer_thread_
;
176 TEST_F(EtwTraceConsumerRealtimeTest
, ConsumerReturnsWhenSessionClosed
) {
177 EtwTraceController controller
;
179 HRESULT hr
= controller
.StartRealtimeSession(kTestSessionName
, 100 * 1024);
180 if (hr
== E_ACCESSDENIED
) {
181 LOG(INFO
) << "You must be an administrator to run this test on Vista";
185 // Start the consumer_.
186 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
188 // Wait around for the consumer_ thread a bit.
189 ASSERT_EQ(WAIT_TIMEOUT
, ::WaitForSingleObject(consumer_thread_
, 50));
191 ASSERT_HRESULT_SUCCEEDED(controller
.Stop(NULL
));
193 // The consumer_ returns success on session stop.
194 ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
199 // {036B8F65-8DF3-46e4-ABFC-6985C43D59BA}
200 DEFINE_GUID(kTestProvider
,
201 0x36b8f65, 0x8df3, 0x46e4, 0xab, 0xfc, 0x69, 0x85, 0xc4, 0x3d, 0x59, 0xba);
203 // {57E47923-A549-476f-86CA-503D57F59E62}
204 DEFINE_GUID(kTestEventType
,
205 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
209 TEST_F(EtwTraceConsumerRealtimeTest
, ConsumeEvent
) {
210 EtwTraceController controller
;
211 HRESULT hr
= controller
.StartRealtimeSession(kTestSessionName
, 100 * 1024);
212 if (hr
== E_ACCESSDENIED
) {
213 LOG(INFO
) << "You must be an administrator to run this test on Vista";
217 ASSERT_HRESULT_SUCCEEDED(controller
.EnableProvider(kTestProvider
,
218 TRACE_LEVEL_VERBOSE
, 0xFFFFFFFF));
220 EtwTraceProvider
provider(kTestProvider
);
221 ASSERT_EQ(ERROR_SUCCESS
, provider
.Register());
223 // Start the consumer_.
224 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
226 ASSERT_EQ(0, TestConsumer::events_
.size());
228 EtwMofEvent
<1> event(kTestEventType
, 1, TRACE_LEVEL_ERROR
);
229 EXPECT_EQ(ERROR_SUCCESS
, provider
.Log(&event
.header
));
231 EXPECT_EQ(WAIT_OBJECT_0
, ::WaitForSingleObject(TestConsumer::sank_event_
,
233 ASSERT_HRESULT_SUCCEEDED(controller
.Stop(NULL
));
234 ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
235 ASSERT_NE(0, TestConsumer::events_
.size());
240 // We run events through a file session to assert that
241 // the content comes through.
242 class EtwTraceConsumerDataTest
: public testing::Test
{
244 EtwTraceConsumerDataTest() {
247 virtual void SetUp() {
248 EtwTraceController::Stop(kTestSessionName
, NULL
);
249 // Construct a temp file name.
250 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file_
));
253 virtual void TearDown() {
254 EXPECT_TRUE(file_util::Delete(temp_file_
, false));
255 EtwTraceController::Stop(kTestSessionName
, NULL
);
258 HRESULT
LogEventToTempSession(PEVENT_TRACE_HEADER header
) {
259 EtwTraceController controller
;
261 // Set up a file session.
262 HRESULT hr
= controller
.StartFileSession(kTestSessionName
,
263 temp_file_
.value().c_str());
267 // Enable our provider.
268 EXPECT_HRESULT_SUCCEEDED(controller
.EnableProvider(kTestProvider
,
269 TRACE_LEVEL_VERBOSE
, 0xFFFFFFFF));
271 EtwTraceProvider
provider(kTestProvider
);
272 // Then register our provider, means we get a session handle immediately.
273 EXPECT_EQ(ERROR_SUCCESS
, provider
.Register());
274 // Trace the event, it goes to the temp file.
275 EXPECT_EQ(ERROR_SUCCESS
, provider
.Log(header
));
276 EXPECT_HRESULT_SUCCEEDED(controller
.DisableProvider(kTestProvider
));
277 EXPECT_HRESULT_SUCCEEDED(provider
.Unregister());
278 EXPECT_HRESULT_SUCCEEDED(controller
.Flush(NULL
));
279 EXPECT_HRESULT_SUCCEEDED(controller
.Stop(NULL
));
284 HRESULT
ConsumeEventFromTempSession() {
285 // Now consume the event(s).
286 TestConsumer consumer_
;
287 HRESULT hr
= consumer_
.OpenFileSession(temp_file_
.value().c_str());
289 hr
= consumer_
.Consume();
291 // And nab the result.
292 events_
.swap(TestConsumer::events_
);
296 HRESULT
RoundTripEvent(PEVENT_TRACE_HEADER header
, PEVENT_TRACE
* trace
) {
297 file_util::Delete(temp_file_
, false);
299 HRESULT hr
= LogEventToTempSession(header
);
301 hr
= ConsumeEventFromTempSession();
306 // We should now have the event in the queue.
310 *trace
= &events_
.back();
321 TEST_F(EtwTraceConsumerDataTest
, RoundTrip
) {
322 EtwMofEvent
<1> event(kTestEventType
, 1, TRACE_LEVEL_ERROR
);
324 static const char kData
[] = "This is but test data";
325 event
.fields
[0].DataPtr
= reinterpret_cast<ULONG64
>(kData
);
326 event
.fields
[0].Length
= sizeof(kData
);
328 PEVENT_TRACE trace
= NULL
;
329 HRESULT hr
= RoundTripEvent(&event
.header
, &trace
);
330 if (hr
== E_ACCESSDENIED
) {
331 LOG(INFO
) << "You must be an administrator to run this test on Vista";
334 ASSERT_TRUE(NULL
!= trace
);
335 ASSERT_EQ(sizeof(kData
), trace
->MofLength
);
336 ASSERT_STREQ(kData
, reinterpret_cast<const char*>(trace
->MofData
));