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