This source file includes following definitions.
- ClearQueue
- EnqueueEvent
- ProcessEvent
- SetUp
- TearDown
- TEST_F
- TEST_F
- TEST_F
- SetUp
- TearDown
- ConsumerThread
- ConsumerThreadMainProc
- StartConsumerThread
- JoinConsumerThread
- TEST_F
- TEST_F
- SetUp
- TearDown
- LogEventToTempSession
- ConsumeEventFromTempSession
- RoundTripEvent
- TEST_F
#include "base/win/event_trace_consumer.h"
#include <list>
#include <objbase.h>
#include "base/basictypes.h"
#include "base/file_util.h"
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/logging.h"
#include "base/process/process.h"
#include "base/strings/stringprintf.h"
#include "base/win/event_trace_controller.h"
#include "base/win/event_trace_provider.h"
#include "base/win/scoped_handle.h"
#include "testing/gtest/include/gtest/gtest.h"
#include <initguid.h>
namespace base {
namespace win {
namespace {
typedef std::list<EVENT_TRACE> EventQueue;
class TestConsumer: public EtwTraceConsumerBase<TestConsumer> {
public:
TestConsumer() {
sank_event_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
ClearQueue();
}
~TestConsumer() {
ClearQueue();
sank_event_.Close();
}
void ClearQueue() {
for (EventQueue::const_iterator it(events_.begin()), end(events_.end());
it != end; ++it) {
delete[] it->MofData;
}
events_.clear();
}
static void EnqueueEvent(EVENT_TRACE* event) {
events_.push_back(*event);
EVENT_TRACE& back = events_.back();
if (event->MofData != NULL && event->MofLength != 0) {
back.MofData = new char[event->MofLength];
memcpy(back.MofData, event->MofData, event->MofLength);
}
}
static void ProcessEvent(EVENT_TRACE* event) {
EnqueueEvent(event);
::SetEvent(sank_event_.Get());
}
static ScopedHandle sank_event_;
static EventQueue events_;
private:
DISALLOW_COPY_AND_ASSIGN(TestConsumer);
};
ScopedHandle TestConsumer::sank_event_;
EventQueue TestConsumer::events_;
class EtwTraceConsumerBaseTest: public testing::Test {
public:
EtwTraceConsumerBaseTest()
: session_name_(StringPrintf(L"TestSession-%d",
Process::Current().pid())) {
}
virtual void SetUp() {
EtwTraceProperties ignore;
EtwTraceController::Stop(session_name_.c_str(), &ignore);
ASSERT_HRESULT_SUCCEEDED(::CoCreateGuid(&test_provider_));
}
virtual void TearDown() {
EtwTraceProperties ignore;
EtwTraceController::Stop(session_name_.c_str(), &ignore);
}
protected:
GUID test_provider_;
std::wstring session_name_;
};
}
TEST_F(EtwTraceConsumerBaseTest, Initialize) {
TestConsumer consumer_;
}
TEST_F(EtwTraceConsumerBaseTest, OpenRealtimeSucceedsWhenNoSession) {
TestConsumer consumer_;
ASSERT_HRESULT_SUCCEEDED(
consumer_.OpenRealtimeSession(session_name_.c_str()));
}
TEST_F(EtwTraceConsumerBaseTest, ConsumerImmediateFailureWhenNoSession) {
TestConsumer consumer_;
ASSERT_HRESULT_SUCCEEDED(
consumer_.OpenRealtimeSession(session_name_.c_str()));
ASSERT_HRESULT_FAILED(consumer_.Consume());
}
namespace {
class EtwTraceConsumerRealtimeTest: public EtwTraceConsumerBaseTest {
public:
virtual void SetUp() {
EtwTraceConsumerBaseTest::SetUp();
ASSERT_HRESULT_SUCCEEDED(
consumer_.OpenRealtimeSession(session_name_.c_str()));
}
virtual void TearDown() {
consumer_.Close();
EtwTraceConsumerBaseTest::TearDown();
}
DWORD ConsumerThread() {
::SetEvent(consumer_ready_.Get());
return consumer_.Consume();
}
static DWORD WINAPI ConsumerThreadMainProc(void* arg) {
return reinterpret_cast<EtwTraceConsumerRealtimeTest*>(arg)->
ConsumerThread();
}
HRESULT StartConsumerThread() {
consumer_ready_.Set(::CreateEvent(NULL, TRUE, FALSE, NULL));
EXPECT_TRUE(consumer_ready_ != NULL);
consumer_thread_.Set(::CreateThread(NULL, 0, ConsumerThreadMainProc, this,
0, NULL));
if (consumer_thread_.Get() == NULL)
return HRESULT_FROM_WIN32(::GetLastError());
HANDLE events[] = { consumer_ready_, consumer_thread_ };
DWORD result = ::WaitForMultipleObjects(arraysize(events), events,
FALSE, INFINITE);
switch (result) {
case WAIT_OBJECT_0:
return S_OK;
case WAIT_OBJECT_0 + 1: {
if (::WaitForSingleObject(consumer_ready_, 0) == WAIT_OBJECT_0)
return S_OK;
DWORD exit_code = 0;
if (::GetExitCodeThread(consumer_thread_, &exit_code))
return exit_code;
return HRESULT_FROM_WIN32(::GetLastError());
}
default:
return E_UNEXPECTED;
}
}
HRESULT JoinConsumerThread() {
if (::WaitForSingleObject(consumer_thread_, INFINITE) != WAIT_OBJECT_0)
return HRESULT_FROM_WIN32(::GetLastError());
DWORD exit_code = 0;
if (::GetExitCodeThread(consumer_thread_, &exit_code))
return exit_code;
return HRESULT_FROM_WIN32(::GetLastError());
}
TestConsumer consumer_;
ScopedHandle consumer_ready_;
ScopedHandle consumer_thread_;
};
}
TEST_F(EtwTraceConsumerRealtimeTest, ConsumerReturnsWhenSessionClosed) {
EtwTraceController controller;
if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) ==
E_ACCESSDENIED) {
VLOG(1) << "You must be an administrator to run this test on Vista";
return;
}
ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
ASSERT_EQ(WAIT_TIMEOUT, ::WaitForSingleObject(consumer_thread_, 50));
ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
}
namespace {
DEFINE_GUID(
kTestEventType,
0x57e47923, 0xa549, 0x476f, 0x86, 0xca, 0x50, 0x3d, 0x57, 0xf5, 0x9e, 0x62);
}
TEST_F(EtwTraceConsumerRealtimeTest, ConsumeEvent) {
EtwTraceController controller;
if (controller.StartRealtimeSession(session_name_.c_str(), 100 * 1024) ==
E_ACCESSDENIED) {
VLOG(1) << "You must be an administrator to run this test on Vista";
return;
}
ASSERT_HRESULT_SUCCEEDED(controller.EnableProvider(
test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
EtwTraceProvider provider(test_provider_);
ASSERT_EQ(ERROR_SUCCESS, provider.Register());
ASSERT_HRESULT_SUCCEEDED(StartConsumerThread());
ASSERT_EQ(0, TestConsumer::events_.size());
EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
EXPECT_EQ(ERROR_SUCCESS, provider.Log(&event.header));
EXPECT_EQ(WAIT_OBJECT_0, ::WaitForSingleObject(TestConsumer::sank_event_,
INFINITE));
ASSERT_HRESULT_SUCCEEDED(controller.Stop(NULL));
ASSERT_HRESULT_SUCCEEDED(JoinConsumerThread());
ASSERT_NE(0u, TestConsumer::events_.size());
}
namespace {
class EtwTraceConsumerDataTest: public EtwTraceConsumerBaseTest {
public:
EtwTraceConsumerDataTest() {
}
virtual void SetUp() {
EtwTraceConsumerBaseTest::SetUp();
EtwTraceProperties prop;
EtwTraceController::Stop(session_name_.c_str(), &prop);
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
temp_file_ = temp_dir_.path().Append(L"test.etl");
}
virtual void TearDown() {
EXPECT_TRUE(base::DeleteFile(temp_file_, false));
EtwTraceConsumerBaseTest::TearDown();
}
HRESULT LogEventToTempSession(PEVENT_TRACE_HEADER header) {
EtwTraceController controller;
HRESULT hr = controller.StartFileSession(session_name_.c_str(),
temp_file_.value().c_str());
if (FAILED(hr))
return hr;
EXPECT_HRESULT_SUCCEEDED(controller.EnableProvider(
test_provider_, TRACE_LEVEL_VERBOSE, 0xFFFFFFFF));
EtwTraceProvider provider(test_provider_);
EXPECT_EQ(ERROR_SUCCESS, provider.Register());
EXPECT_EQ(ERROR_SUCCESS, provider.Log(header));
EXPECT_HRESULT_SUCCEEDED(controller.DisableProvider(test_provider_));
EXPECT_HRESULT_SUCCEEDED(provider.Unregister());
EXPECT_HRESULT_SUCCEEDED(controller.Flush(NULL));
EXPECT_HRESULT_SUCCEEDED(controller.Stop(NULL));
return S_OK;
}
HRESULT ConsumeEventFromTempSession() {
TestConsumer consumer_;
HRESULT hr = consumer_.OpenFileSession(temp_file_.value().c_str());
if (SUCCEEDED(hr))
hr = consumer_.Consume();
consumer_.Close();
events_.swap(TestConsumer::events_);
return hr;
}
HRESULT RoundTripEvent(PEVENT_TRACE_HEADER header, PEVENT_TRACE* trace) {
base::DeleteFile(temp_file_, false);
HRESULT hr = LogEventToTempSession(header);
if (SUCCEEDED(hr))
hr = ConsumeEventFromTempSession();
if (FAILED(hr))
return hr;
if (events_.empty())
return E_FAIL;
*trace = &events_.back();
return S_OK;
}
EventQueue events_;
ScopedTempDir temp_dir_;
FilePath temp_file_;
};
}
TEST_F(EtwTraceConsumerDataTest, RoundTrip) {
EtwMofEvent<1> event(kTestEventType, 1, TRACE_LEVEL_ERROR);
static const char kData[] = "This is but test data";
event.fields[0].DataPtr = reinterpret_cast<ULONG64>(kData);
event.fields[0].Length = sizeof(kData);
PEVENT_TRACE trace = NULL;
HRESULT hr = RoundTripEvent(&event.header, &trace);
if (hr == E_ACCESSDENIED) {
VLOG(1) << "You must be an administrator to run this test on Vista";
return;
}
ASSERT_HRESULT_SUCCEEDED(hr) << "RoundTripEvent failed";
ASSERT_TRUE(trace != NULL);
ASSERT_EQ(sizeof(kData), trace->MofLength);
ASSERT_STREQ(kData, reinterpret_cast<const char*>(trace->MofData));
}
}
}