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