Commit 13f56c06 authored by Bruce Dawson's avatar Bruce Dawson Committed by Commit Bot

Adding extended error codes to SystemSessionAnalyzer

SystemSessionAnalyzerTest.ValidateEvents fails flakily (failing most of
the time) and it is impossible to tell which failure point is being hit.
This change adds recording of extended error codes so that the failure
will be visible so that we can make progress on this old bug.

Some multi-part logical-or statements were broken up to ensure that the
precise failure is found. GetEventInfo was moved to be a member function
so that it has access to the error-setting function.

Test command line is:
components_unittests --gtest_filter=SystemSessionAnalyzerTest.ValidateEvents

Bug: 968440
Change-Id: Ie7b76d6e6607725819244ef22b3a2b1f8ab34d38
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2136061Reviewed-by: default avatarJesse McKenna <jessemckenna@google.com>
Reviewed-by: default avatarIlya Sherman <isherman@chromium.org>
Commit-Queue: Bruce Dawson <brucedawson@chromium.org>
Cr-Commit-Position: refs/heads/master@{#756900}
parent a776f4cb
...@@ -50,9 +50,28 @@ base::Time ULLFileTimeToTime(ULONGLONG time_ulonglong) { ...@@ -50,9 +50,28 @@ base::Time ULLFileTimeToTime(ULONGLONG time_ulonglong) {
return base::Time::FromFileTime(ft); return base::Time::FromFileTime(ft);
} }
bool GetEventInfo(EVT_HANDLE context, } // namespace
EVT_HANDLE event,
SystemSessionAnalyzer::EventInfo* info) { SystemSessionAnalyzer::SystemSessionAnalyzer(uint32_t max_session_cnt)
: max_session_cnt_(max_session_cnt), sessions_queried_(0) {}
SystemSessionAnalyzer::~SystemSessionAnalyzer() {}
SystemSessionAnalyzer::ExtendedStatus
SystemSessionAnalyzer::GetExtendedFailureStatus() const {
return extended_status_;
}
void SystemSessionAnalyzer::SetExtendedFailureStatus(
ExtendedStatus new_status) {
if (extended_status_ == ExtendedStatus::NO_FAILURE)
extended_status_ = new_status;
}
bool SystemSessionAnalyzer::GetEventInfo(
EVT_HANDLE context,
EVT_HANDLE event,
SystemSessionAnalyzer::EventInfo* info) {
DCHECK(context); DCHECK(context);
DCHECK(event); DCHECK(event);
DCHECK(info); DCHECK(info);
...@@ -67,14 +86,22 @@ bool GetEventInfo(EVT_HANDLE context, ...@@ -67,14 +86,22 @@ bool GetEventInfo(EVT_HANDLE context,
DWORD retrieved_attribute_cnt = 0U; DWORD retrieved_attribute_cnt = 0U;
if (!::EvtRender(context, event, EvtRenderEventValues, buffer_size, if (!::EvtRender(context, event, EvtRenderEventValues, buffer_size,
buffer.data(), &buffer_used, &retrieved_attribute_cnt)) { buffer.data(), &buffer_used, &retrieved_attribute_cnt)) {
SetExtendedFailureStatus(ExtendedStatus::RENDER_EVENT_FAILURE);
DLOG(ERROR) << "Failed to render the event."; DLOG(ERROR) << "Failed to render the event.";
return false; return false;
} }
// Validate the count and types of the retrieved attributes. // Validate the count and types of the retrieved attributes.
if ((retrieved_attribute_cnt != kAttributeCnt) || if (retrieved_attribute_cnt != kAttributeCnt) {
(buffer[0].Type != EvtVarTypeUInt16) || SetExtendedFailureStatus(ExtendedStatus::ATTRIBUTE_CNT_MISMATCH);
(buffer[1].Type != EvtVarTypeFileTime)) { return false;
}
if (buffer[0].Type != EvtVarTypeUInt16) {
SetExtendedFailureStatus(ExtendedStatus::EXPECTED_INT16_TYPE);
return false;
}
if (buffer[1].Type != EvtVarTypeFileTime) {
SetExtendedFailureStatus(ExtendedStatus::EXPECTED_FILETIME_TYPE);
return false; return false;
} }
...@@ -84,13 +111,6 @@ bool GetEventInfo(EVT_HANDLE context, ...@@ -84,13 +111,6 @@ bool GetEventInfo(EVT_HANDLE context,
return true; return true;
} }
} // namespace
SystemSessionAnalyzer::SystemSessionAnalyzer(uint32_t max_session_cnt)
: max_session_cnt_(max_session_cnt), sessions_queried_(0) {}
SystemSessionAnalyzer::~SystemSessionAnalyzer() {}
SystemSessionAnalyzer::Status SystemSessionAnalyzer::IsSessionUnclean( SystemSessionAnalyzer::Status SystemSessionAnalyzer::IsSessionUnclean(
base::Time timestamp) { base::Time timestamp) {
if (!EnsureInitialized()) if (!EnsureInitialized())
...@@ -146,6 +166,7 @@ bool SystemSessionAnalyzer::FetchEvents(size_t requested_events, ...@@ -146,6 +166,7 @@ bool SystemSessionAnalyzer::FetchEvents(size_t requested_events,
events[i].reset(events_raw[i]); events[i].reset(events_raw[i]);
if (!success) { if (!success) {
SetExtendedFailureStatus(ExtendedStatus::RETRIEVE_EVENTS_FAILURE);
DLOG(ERROR) << "Failed to retrieve events."; DLOG(ERROR) << "Failed to retrieve events.";
return false; return false;
} }
...@@ -182,6 +203,7 @@ bool SystemSessionAnalyzer::EnsureHandlesOpened() { ...@@ -182,6 +203,7 @@ bool SystemSessionAnalyzer::EnsureHandlesOpened() {
::EvtQuery(nullptr, kChannelName, kSessionEventsQuery, ::EvtQuery(nullptr, kChannelName, kSessionEventsQuery,
EvtQueryChannelPath | EvtQueryReverseDirection)); EvtQueryChannelPath | EvtQueryReverseDirection));
if (!query_handle_.get()) { if (!query_handle_.get()) {
SetExtendedFailureStatus(ExtendedStatus::EVTQUERY_FAILED);
DLOG(ERROR) << "Event query failed."; DLOG(ERROR) << "Event query failed.";
return false; return false;
} }
...@@ -190,8 +212,10 @@ bool SystemSessionAnalyzer::EnsureHandlesOpened() { ...@@ -190,8 +212,10 @@ bool SystemSessionAnalyzer::EnsureHandlesOpened() {
if (!render_context_.get()) { if (!render_context_.get()) {
// Create the render context for extracting information from the events. // Create the render context for extracting information from the events.
render_context_ = CreateRenderContext(); render_context_ = CreateRenderContext();
if (!render_context_.get()) if (!render_context_.get()) {
SetExtendedFailureStatus(ExtendedStatus::CREATE_RENDER_CONTEXT_FAILURE);
return false; return false;
}
} }
return true; return true;
...@@ -203,12 +227,20 @@ bool SystemSessionAnalyzer::Initialize() { ...@@ -203,12 +227,20 @@ bool SystemSessionAnalyzer::Initialize() {
// Fetch the first (current) session start event and the first session, // Fetch the first (current) session start event and the first session,
// comprising an end and a start event for a total of 3 events. // comprising an end and a start event for a total of 3 events.
std::vector<EventInfo> events; std::vector<EventInfo> events;
if (!FetchEvents(3U, &events)) if (!FetchEvents(3U, &events)) {
SetExtendedFailureStatus(ExtendedStatus::FETCH_EVENTS_FAILURE);
return false; return false;
}
// Validate that the initial event is what we expect. // Validate that the initial event is what we expect.
if (events.size() != 3 || events[0].event_id != kIdSessionStart) if (events.size() != 3) {
SetExtendedFailureStatus(ExtendedStatus::EVENT_COUNT_MISMATCH);
return false; return false;
}
if (events[0].event_id != kIdSessionStart) {
SetExtendedFailureStatus(ExtendedStatus::SESSION_START_MISMATCH);
return false;
}
// Initialize the coverage start to allow detecting event time inversion. // Initialize the coverage start to allow detecting event time inversion.
coverage_start_ = events[0].event_time; coverage_start_ = events[0].event_time;
...@@ -225,17 +257,25 @@ bool SystemSessionAnalyzer::ProcessSession(const EventInfo& end, ...@@ -225,17 +257,25 @@ bool SystemSessionAnalyzer::ProcessSession(const EventInfo& end,
const EventInfo& start) { const EventInfo& start) {
// Validate the ordering of events (newest to oldest). The expectation is a // Validate the ordering of events (newest to oldest). The expectation is a
// (start / [unclean]shutdown) pair of events for each session. // (start / [unclean]shutdown) pair of events for each session.
if (coverage_start_ < end.event_time) if (coverage_start_ < end.event_time) {
SetExtendedFailureStatus(ExtendedStatus::COVERAGE_START_ORDER_FAILURE);
return false; return false;
if (end.event_time < start.event_time) }
if (end.event_time < start.event_time) {
SetExtendedFailureStatus(ExtendedStatus::EVENT_ORDER_FAILURE);
return false; return false;
}
// Process a (start / shutdown) event pair, validating the types of events // Process a (start / shutdown) event pair, validating the types of events
// and recording unclean sessions. // and recording unclean sessions.
if (start.event_id != kIdSessionStart) if (start.event_id != kIdSessionStart) {
SetExtendedFailureStatus(ExtendedStatus::UNEXPECTED_START_EVENT_TYPE);
return false; // Unexpected event type. return false; // Unexpected event type.
if (end.event_id != kIdSessionEnd && end.event_id != kIdSessionEndUnclean) }
if (end.event_id != kIdSessionEnd && end.event_id != kIdSessionEndUnclean) {
SetExtendedFailureStatus(ExtendedStatus::UNEXPECTED_END_EVENT_TYPE);
return false; // Unexpected event type. return false; // Unexpected event type.
}
if (end.event_id == kIdSessionEndUnclean) { if (end.event_id == kIdSessionEndUnclean) {
unclean_sessions_.insert( unclean_sessions_.insert(
......
...@@ -32,6 +32,31 @@ class SystemSessionAnalyzer { ...@@ -32,6 +32,31 @@ class SystemSessionAnalyzer {
PROCESS_SESSION_FAILED = 5, PROCESS_SESSION_FAILED = 5,
}; };
// Track internal details of what went wrong.
enum class ExtendedStatus {
NO_FAILURE = 0,
RENDER_EVENT_FAILURE = 1,
ATTRIBUTE_CNT_MISMATCH = 2,
EXPECTED_INT16_TYPE = 3,
EXPECTED_FILETIME_TYPE = 4,
RETRIEVE_EVENTS_FAILURE = 5,
GET_EVENT_INFO_FAILURE = 6,
EVTQUERY_FAILED = 7,
CREATE_RENDER_CONTEXT_FAILURE = 8,
FETCH_EVENTS_FAILURE = 9,
EVENT_COUNT_MISMATCH = 10,
SESSION_START_MISMATCH = 11,
COVERAGE_START_ORDER_FAILURE = 12,
EVENT_ORDER_FAILURE = 13,
UNEXPECTED_START_EVENT_TYPE = 14,
UNEXPECTED_END_EVENT_TYPE = 15,
};
ExtendedStatus GetExtendedFailureStatus() const;
// Set an extended failure status code for easier diagnosing of test failures.
// The first extended status code is retained.
void SetExtendedFailureStatus(ExtendedStatus);
// Minimal information about a log event. // Minimal information about a log event.
struct EventInfo { struct EventInfo {
uint16_t event_id; uint16_t event_id;
...@@ -76,6 +101,9 @@ class SystemSessionAnalyzer { ...@@ -76,6 +101,9 @@ class SystemSessionAnalyzer {
// as appropriate. // as appropriate.
bool ProcessSession(const EventInfo& end, const EventInfo& start); bool ProcessSession(const EventInfo& end, const EventInfo& start);
bool GetEventInfo(EVT_HANDLE context,
EVT_HANDLE event,
SystemSessionAnalyzer::EventInfo* info);
EvtHandle CreateRenderContext(); EvtHandle CreateRenderContext();
// The maximal number of sessions to query events for. // The maximal number of sessions to query events for.
...@@ -96,6 +124,9 @@ class SystemSessionAnalyzer { ...@@ -96,6 +124,9 @@ class SystemSessionAnalyzer {
// Timestamp of the oldest event. // Timestamp of the oldest event.
base::Time coverage_start_; base::Time coverage_start_;
// Track details of what failures occurred.
ExtendedStatus extended_status_ = ExtendedStatus::NO_FAILURE;
DISALLOW_COPY_AND_ASSIGN(SystemSessionAnalyzer); DISALLOW_COPY_AND_ASSIGN(SystemSessionAnalyzer);
}; };
......
...@@ -36,7 +36,9 @@ TEST(SystemSessionAnalyzerTest, FetchEvents) { ...@@ -36,7 +36,9 @@ TEST(SystemSessionAnalyzerTest, FetchEvents) {
TEST(SystemSessionAnalyzerTest, ValidateEvents) { TEST(SystemSessionAnalyzerTest, ValidateEvents) {
SystemSessionAnalyzer analyzer(1U); SystemSessionAnalyzer analyzer(1U);
EXPECT_EQ(SystemSessionAnalyzer::CLEAN, EXPECT_EQ(SystemSessionAnalyzer::CLEAN,
analyzer.IsSessionUnclean(base::Time::Now())); analyzer.IsSessionUnclean(base::Time::Now()))
<< "Extended error code is: "
<< static_cast<int>(analyzer.GetExtendedFailureStatus());
} }
// Stubs FetchEvents. // Stubs FetchEvents.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment