1 // Copyright (c) 2010 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" 7 8 #include <list> 9 10 #include "base/basictypes.h" 11 #include "base/file_path.h" 12 #include "base/file_util.h" 13 #include "base/logging.h" 14 #include "base/win/event_trace_controller.h" 15 #include "base/win/event_trace_provider.h" 16 #include "base/win/scoped_handle.h" 17 #include "testing/gtest/include/gtest/gtest.h" 18 19 #include <initguid.h> // NOLINT - has to be last 20 21 namespace { 22 23 using base::win::EtwMofEvent; 24 using base::win::EtwTraceController; 25 using base::win::EtwTraceConsumerBase; 26 using base::win::EtwTraceProperties; 27 using base::win::EtwTraceProvider; 28 29 typedef std::list<EVENT_TRACE> EventQueue; 30 31 class TestConsumer: public EtwTraceConsumerBase<TestConsumer> { 32 public: 33 TestConsumer() { 34 sank_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL)); 35 ClearQueue(); 36 } 37 38 ~TestConsumer() { 39 ClearQueue(); 40 sank_event_.Close(); 41 } 42 43 void ClearQueue() { 44 EventQueue::const_iterator it(events_.begin()), end(events_.end()); 45 46 for (; it != end; ++it) { 47 delete [] it->MofData; 48 } 49 50 events_.clear(); 51 } 52 53 static void EnqueueEvent(EVENT_TRACE* event) { 54 events_.push_back(*event); 55 EVENT_TRACE& back = events_.back(); 56 57 if (NULL != event->MofData && 0 != event->MofLength) { 58 back.MofData = new char[event->MofLength]; 59 memcpy(back.MofData, event->MofData, event->MofLength); 60 } 61 } 62 63 static void ProcessEvent(EVENT_TRACE* event) { 64 EnqueueEvent(event); 65 ::SetEvent(sank_event_.Get()); 66 } 67 68 static base::win::ScopedHandle sank_event_; 69 static EventQueue events_; 70 71 private: 72 DISALLOW_COPY_AND_ASSIGN(TestConsumer); 73 }; 74 75 base::win::ScopedHandle TestConsumer::sank_event_; 76 EventQueue TestConsumer::events_; 77 78 const wchar_t* const kTestSessionName = L"TestLogSession"; 79 80 class EtwTraceConsumerBaseTest: public testing::Test { 81 public: 82 virtual void SetUp() { 83 EtwTraceProperties ignore; 84 EtwTraceController::Stop(kTestSessionName, &ignore); 85 } 86 }; 87 88 } // namespace 89 90 TEST_F(EtwTraceConsumerBaseTest, Initialize) { 91 TestConsumer consumer_; 92 } 93 94 TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) { 95 TestConsumer consumer_; 96 97 ASSERT_HRESULT_SUCCEEDED(consumer_.OpenRealtimeSession(kTestSessionName)); 98 } 99 100 TEST_F(EtwTraceConsumerBaseTest, ConsumerImmediateFailureWhenNoSession) { 101 TestConsumer consumer_; 102 103 ASSERT_HRESULT_SUCCEEDED(consumer_.OpenRealtimeSession(kTestSessionName)); 104 ASSERT_HRESULT_FAILED(consumer_.Consume()); 105 } 106 107 namespace { 108 109 class EtwTraceConsumerRealtimeTest: public testing::Test { 110 public: 111 virtual void SetUp() { 112 ASSERT_HRESULT_SUCCEEDED(consumer_.OpenRealtimeSession(kTestSessionName)); 113 } 114 115 virtual void TearDown() { 116 consumer_.Close(); 117 } 118 119 DWORD ConsumerThread() { 120 ::SetEvent(consumer_ready_.Get()); 121 122 HRESULT hr = consumer_.Consume(); 123 return hr; 124 } 125 126 static DWORD WINAPI ConsumerThreadMainProc(void* arg) { 127 return reinterpret_cast<EtwTraceConsumerRealtimeTest*>(arg)-> 128 ConsumerThread(); 129 } 130 131 HRESULT StartConsumerThread() { 132 consumer_ready_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL)); 133 EXPECT_TRUE(consumer_ready_ != NULL); 134 consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc, 135 this, 0, NULL)); 136 if (NULL == consumer_thread_.Get()) 137 return HRESULT_FROM_WIN32(::GetLastError()); 138 139 HRESULT hr = S_OK; 140 HANDLE events[] = { consumer_ready_, consumer_thread_ }; 141 DWORD result = ::WaitForMultipleObjects(arraysize(events), events, 142 FALSE, INFINITE); 143 switch (result) { 144 case WAIT_OBJECT_0: 145 // The event was set, the consumer_ is ready. 146 return S_OK; 147 case WAIT_OBJECT_0 + 1: { 148 // The thread finished. This may race with the event, so check 149 // explicitly for the event here, before concluding there's trouble. 150 if (WAIT_OBJECT_0 == ::WaitForSingleObject(consumer_ready_, 0)) 151 return S_OK; 152 DWORD exit_code = 0; 153 if (::GetExitCodeThread(consumer_thread_, &exit_code)) 154 return exit_code; 155 else 156 return HRESULT_FROM_WIN32(::GetLastError()); 157 break; 158 } 159 default: 160 return E_UNEXPECTED; 161 break; 162 } 163 164 return hr; 165 } 166 167 // Waits for consumer_ thread to exit, and returns its exit code. 168 HRESULT JoinConsumerThread() { 169 if (WAIT_OBJECT_0 != ::WaitForSingleObject(consumer_thread_, INFINITE)) 170 return HRESULT_FROM_WIN32(::GetLastError()); 171 172 DWORD exit_code = 0; 173 if (::GetExitCodeThread(consumer_thread_, &exit_code)) 174 return exit_code; 175 176 return HRESULT_FROM_WIN32(::GetLastError()); 177 } 178 179 TestConsumer consumer_; 180 base::win::ScopedHandle consumer_ready_; 181 base::win::ScopedHandle consumer_thread_; 182 }; 183 } // namespace 184 185 TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) { 186 EtwTraceController controller; 187 188 HRESULT hr = controller.StartRealtimeSession(kTestSessionName, 100 * 1024); 189 if (hr == E_ACCESSDENIED) { 190 VLOG(1) << "You must be an administrator to run this test on Vista"; 191 return; 192 } 193 194 // Start the consumer_. 195 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread()); 196 197 // Wait around for the consumer_ thread a bit. 198 ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_, 50)); 199 200 ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL)); 201 202 // The consumer_ returns success on session stop. 203 ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread()); 204 } 205 206 namespace { 207 208 // {036B8F65-8DF3-46e4-ABFC-6985C43D59BA} 209 DEFINE_GUID(kTestProvider, 210 0x36b8f65, 0x8df3, 0x46e4, 0xab, 0xfc, 0x69, 0x85, 0xc4, 0x3d, 0x59, 0xba); 211 212 // {57E47923-A549-476f-86CA-503D57F59E62} 213 DEFINE_GUID(kTestEventType, 214 0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62); 215 216 } // namespace 217 218 TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) { 219 EtwTraceController controller; 220 HRESULT hr = controller.StartRealtimeSession(kTestSessionName, 100 * 1024); 221 if (hr == E_ACCESSDENIED) { 222 VLOG(1) << "You must be an administrator to run this test on Vista"; 223 return; 224 } 225 226 ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(kTestProvider, 227 TRACE_LEVEL_VERBOSE, 0xFFFFFFFF)); 228 229 EtwTraceProvider provider(kTestProvider); 230 ASSERT_EQ(ERROR_SUCCESS, provider.Register()); 231 232 // Start the consumer_. 233 ASSERT_HRESULT_SUCCEEDED(StartConsumerThread()); 234 235 ASSERT_EQ(0, TestConsumer::events_.size()); 236 237 EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR); 238 EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header)); 239 240 EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(TestConsumer::sank_event_, 241 INFINITE)); 242 ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL)); 243 ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread()); 244 ASSERT_NE(0u, TestConsumer::events_.size()); 245 } 246 247 namespace { 248 249 // We run events through a file session to assert that 250 // the content comes through. 251 class EtwTraceConsumerDataTest: public testing::Test { 252 public: 253 EtwTraceConsumerDataTest() { 254 } 255 256 virtual void SetUp() { 257 EtwTraceProperties prop; 258 EtwTraceController::Stop(kTestSessionName, &prop); 259 // Construct a temp file name. 260 ASSERT_TRUE(file_util::CreateTemporaryFile(&temp_file_)); 261 } 262 263 virtual void TearDown() { 264 EXPECT_TRUE(file_util::Delete(temp_file_, false)); 265 EtwTraceProperties ignore; 266 EtwTraceController::Stop(kTestSessionName, &ignore); 267 } 268 269 HRESULT LogEventToTempSession(PEVENT_TRACE_HEADER header) { 270 EtwTraceController controller; 271 272 // Set up a file session. 273 HRESULT hr = controller.StartFileSession(kTestSessionName, 274 temp_file_.value().c_str()); 275 if (FAILED(hr)) 276 return hr; 277 278 // Enable our provider. 279 EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(kTestProvider, 280 TRACE_LEVEL_VERBOSE, 0xFFFFFFFF)); 281 282 EtwTraceProvider provider(kTestProvider); 283 // Then register our provider, means we get a session handle immediately. 284 EXPECT_EQ(ERROR_SUCCESS, provider.Register()); 285 // Trace the event, it goes to the temp file. 286 EXPECT_EQ(ERROR_SUCCESS, provider.Log(header)); 287 EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(kTestProvider)); 288 EXPECT_HRESULT_SUCCEEDED(provider.Unregister()); 289 EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL)); 290 EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL)); 291 292 return S_OK; 293 } 294 295 HRESULT ConsumeEventFromTempSession() { 296 // Now consume the event(s). 297 TestConsumer consumer_; 298 HRESULT hr = consumer_.OpenFileSession(temp_file_.value().c_str()); 299 if (SUCCEEDED(hr)) 300 hr = consumer_.Consume(); 301 consumer_.Close(); 302 // And nab the result. 303 events_.swap(TestConsumer::events_); 304 return hr; 305 } 306 307 HRESULT RoundTripEvent(PEVENT_TRACE_HEADER header, PEVENT_TRACE* trace) { 308 file_util::Delete(temp_file_, false); 309 310 HRESULT hr = LogEventToTempSession(header); 311 if (SUCCEEDED(hr)) 312 hr = ConsumeEventFromTempSession(); 313 314 if (FAILED(hr)) 315 return hr; 316 317 // We should now have the event in the queue. 318 if (events_.empty()) 319 return E_FAIL; 320 321 *trace = &events_.back(); 322 return S_OK; 323 } 324 325 EventQueue events_; 326 FilePath temp_file_; 327 }; 328 329 } // namespace 330 331 332 TEST_F(EtwTraceConsumerDataTest, RoundTrip) { 333 EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR); 334 335 static const char kData[] = "This is but test data"; 336 event.fields[0].DataPtr = reinterpret_cast<ULONG64>(kData); 337 event.fields[0].Length = sizeof(kData); 338 339 PEVENT_TRACE trace = NULL; 340 HRESULT hr = RoundTripEvent(&event.header, &trace); 341 if (hr == E_ACCESSDENIED) { 342 VLOG(1) << "You must be an administrator to run this test on Vista"; 343 return; 344 } 345 ASSERT_TRUE(NULL != trace); 346 ASSERT_EQ(sizeof(kData), trace->MofLength); 347 ASSERT_STREQ(kData, reinterpret_cast<const char*>(trace->MofData)); 348 } 349