1 // Copyright 2017 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "components/metrics/system_session_analyzer/system_session_analyzer_win.h"
6
7 #include <algorithm>
8 #include <utility>
9 #include <vector>
10
11 #include "base/logging.h"
12 #include "base/time/time.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15
16 namespace metrics {
17
18 namespace {
19
20 const uint16_t kIdSessionStart = 6005U;
21 const uint16_t kIdSessionEnd = 6006U;
22 const uint16_t kIdSessionEndUnclean = 6008U;
23
24 } // namespace
25
26 // Ensure the fetcher retrieves events.
27 // Due to https://crbug.com/1053451 which is caused by a Windows "bug" tracked
28 // by https://crbug.com/1053451 this cannot be made reliable. Running
29 // browser_tests can and does generate so much event logging (DCOM events) that
30 // none of the looked for events remain.
TEST(SystemSessionAnalyzerTest,DISABLED_FetchEvents)31 TEST(SystemSessionAnalyzerTest, DISABLED_FetchEvents) {
32 SystemSessionAnalyzer analyzer(0);
33 std::vector<SystemSessionAnalyzer::EventInfo> events;
34 ASSERT_TRUE(analyzer.FetchEvents(1U, &events));
35 EXPECT_EQ(1U, events.size());
36 }
37
38 // Ensure the fetcher's retrieved events conform to our expectations.
39 // Note: this test fails if the host system doesn't have at least 1 prior
40 // session.
TEST(SystemSessionAnalyzerTest,ValidateEvents)41 TEST(SystemSessionAnalyzerTest, ValidateEvents) {
42 SystemSessionAnalyzer analyzer(1U);
43 auto is_session_unclean = analyzer.IsSessionUnclean(base::Time::Now());
44 // If the system event log rate is high enough then there may not be enough
45 // events to make a clean/unclean determination. Check for this situation and
46 // don't treat it as a failure. See https://crbug.com/968440 and
47 // https://crbug.com/1053451 for details.
48 if (is_session_unclean == SystemSessionAnalyzer::INSUFFICIENT_DATA) {
49 // This warning can be ignored, but it does mean that our clean/unclean
50 // check did not give an answer.
51 LOG(WARNING) << "Insufficient events found in ValidateEvents.";
52 } else {
53 EXPECT_EQ(SystemSessionAnalyzer::CLEAN, is_session_unclean)
54 << "Extended error code is: "
55 << static_cast<int>(analyzer.GetExtendedFailureStatus());
56 }
57 }
58
59 // Stubs FetchEvents.
60 class StubSystemSessionAnalyzer : public SystemSessionAnalyzer {
61 public:
StubSystemSessionAnalyzer(uint32_t max_session_cnt)62 StubSystemSessionAnalyzer(uint32_t max_session_cnt)
63 : SystemSessionAnalyzer(max_session_cnt) {}
64
FetchEvents(size_t requested_events,std::vector<EventInfo> * event_infos)65 bool FetchEvents(size_t requested_events,
66 std::vector<EventInfo>* event_infos) override {
67 DCHECK(event_infos);
68 size_t num_to_copy = std::min(requested_events, events_.size());
69 if (num_to_copy) {
70 event_infos->clear();
71 event_infos->insert(event_infos->begin(), events_.begin(),
72 events_.begin() + num_to_copy);
73 events_.erase(events_.begin(), events_.begin() + num_to_copy);
74 }
75
76 return true;
77 }
78
AddEvent(const EventInfo & info)79 void AddEvent(const EventInfo& info) { events_.push_back(info); }
80
81 private:
82 std::vector<EventInfo> events_;
83 };
84
TEST(SystemSessionAnalyzerTest,StandardCase)85 TEST(SystemSessionAnalyzerTest, StandardCase) {
86 StubSystemSessionAnalyzer analyzer(2U);
87
88 base::Time time = base::Time::Now();
89 analyzer.AddEvent({kIdSessionStart, time});
90 analyzer.AddEvent({kIdSessionEndUnclean, time - base::Seconds(10)});
91 analyzer.AddEvent({kIdSessionStart, time - base::Seconds(20)});
92 analyzer.AddEvent({kIdSessionEnd, time - base::Seconds(22)});
93 analyzer.AddEvent({kIdSessionStart, time - base::Seconds(28)});
94
95 EXPECT_EQ(SystemSessionAnalyzer::OUTSIDE_RANGE,
96 analyzer.IsSessionUnclean(time - base::Seconds(30)));
97 EXPECT_EQ(SystemSessionAnalyzer::CLEAN,
98 analyzer.IsSessionUnclean(time - base::Seconds(25)));
99 EXPECT_EQ(SystemSessionAnalyzer::UNCLEAN,
100 analyzer.IsSessionUnclean(time - base::Seconds(20)));
101 EXPECT_EQ(SystemSessionAnalyzer::UNCLEAN,
102 analyzer.IsSessionUnclean(time - base::Seconds(15)));
103 EXPECT_EQ(SystemSessionAnalyzer::UNCLEAN,
104 analyzer.IsSessionUnclean(time - base::Seconds(10)));
105 EXPECT_EQ(SystemSessionAnalyzer::CLEAN,
106 analyzer.IsSessionUnclean(time - base::Seconds(5)));
107 EXPECT_EQ(SystemSessionAnalyzer::CLEAN,
108 analyzer.IsSessionUnclean(time + base::Seconds(5)));
109 }
110
TEST(SystemSessionAnalyzerTest,NoEvent)111 TEST(SystemSessionAnalyzerTest, NoEvent) {
112 StubSystemSessionAnalyzer analyzer(0U);
113 EXPECT_EQ(SystemSessionAnalyzer::INSUFFICIENT_DATA,
114 analyzer.IsSessionUnclean(base::Time::Now()));
115 }
116
TEST(SystemSessionAnalyzerTest,TimeInversion)117 TEST(SystemSessionAnalyzerTest, TimeInversion) {
118 StubSystemSessionAnalyzer analyzer(1U);
119
120 base::Time time = base::Time::Now();
121 analyzer.AddEvent({kIdSessionStart, time});
122 analyzer.AddEvent({kIdSessionEnd, time + base::Seconds(1)});
123 analyzer.AddEvent({kIdSessionStart, time - base::Seconds(1)});
124
125 EXPECT_EQ(SystemSessionAnalyzer::INITIALIZE_FAILED,
126 analyzer.IsSessionUnclean(base::Time::Now()));
127 }
128
TEST(SystemSessionAnalyzerTest,IdInversion)129 TEST(SystemSessionAnalyzerTest, IdInversion) {
130 StubSystemSessionAnalyzer analyzer(1U);
131
132 base::Time time = base::Time::Now();
133 analyzer.AddEvent({kIdSessionStart, time});
134 analyzer.AddEvent({kIdSessionStart, time - base::Seconds(1)});
135 analyzer.AddEvent({kIdSessionEnd, time - base::Seconds(2)});
136
137 EXPECT_EQ(SystemSessionAnalyzer::INITIALIZE_FAILED,
138 analyzer.IsSessionUnclean(base::Time::Now()));
139 }
140
141 } // namespace metrics
142