• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/reporting_service.h"
6 
7 #include <stdint.h>
8 
9 #include <deque>
10 #include <memory>
11 #include <string>
12 #include <string_view>
13 
14 #include "base/functional/bind.h"
15 #include "base/hash/sha1.h"
16 #include "base/strings/string_util.h"
17 #include "base/task/single_thread_task_runner.h"
18 #include "base/test/test_simple_task_runner.h"
19 #include "components/metrics/log_store.h"
20 #include "components/metrics/metrics_log.h"
21 #include "components/metrics/test/test_metrics_service_client.h"
22 #include "components/prefs/testing_pref_service.h"
23 #include "testing/gtest/include/gtest/gtest.h"
24 #include "third_party/zlib/google/compression_utils.h"
25 
26 namespace metrics {
27 
28 namespace {
29 
30 // Represent a flushed log and its metadata to be used for testing.
31 struct TestLog {
TestLogmetrics::__anon58e50bff0111::TestLog32   explicit TestLog(const std::string& log) : log(log), user_id(std::nullopt) {}
TestLogmetrics::__anon58e50bff0111::TestLog33   TestLog(const std::string& log, uint64_t user_id)
34       : log(log), user_id(user_id) {}
TestLogmetrics::__anon58e50bff0111::TestLog35   TestLog(const std::string& log, uint64_t user_id, LogMetadata log_metadata)
36       : log(log), user_id(user_id), log_metadata(log_metadata) {}
37   TestLog(const TestLog& other) = default;
38   ~TestLog() = default;
39 
40   const std::string log;
41   const std::optional<uint64_t> user_id;
42   const LogMetadata log_metadata;
43 };
44 
45 const char kTestUploadUrl[] = "test_url";
46 const char kTestMimeType[] = "test_mime_type";
47 
48 class TestLogStore : public LogStore {
49  public:
50   TestLogStore() = default;
51   ~TestLogStore() override = default;
52 
AddLog(const TestLog & log)53   void AddLog(const TestLog& log) { logs_.push_back(log); }
54 
55   // LogStore:
has_unsent_logs() const56   bool has_unsent_logs() const override { return !logs_.empty(); }
has_staged_log() const57   bool has_staged_log() const override { return !staged_log_hash_.empty(); }
staged_log() const58   const std::string& staged_log() const override { return logs_.front().log; }
staged_log_hash() const59   const std::string& staged_log_hash() const override {
60     return staged_log_hash_;
61   }
staged_log_user_id() const62   std::optional<uint64_t> staged_log_user_id() const override {
63     return logs_.front().user_id;
64   }
staged_log_metadata() const65   const LogMetadata staged_log_metadata() const override {
66     return logs_.front().log_metadata;
67   }
staged_log_signature() const68   const std::string& staged_log_signature() const override {
69     return base::EmptyString();
70   }
StageNextLog()71   void StageNextLog() override {
72     if (has_unsent_logs()) {
73       staged_log_hash_ = base::SHA1HashString(logs_.front().log);
74     }
75   }
DiscardStagedLog(std::string_view reason)76   void DiscardStagedLog(std::string_view reason) override {
77     if (!has_staged_log())
78       return;
79     logs_.pop_front();
80     staged_log_hash_.clear();
81   }
MarkStagedLogAsSent()82   void MarkStagedLogAsSent() override {}
TrimAndPersistUnsentLogs(bool overwrite_in_memory_store)83   void TrimAndPersistUnsentLogs(bool overwrite_in_memory_store) override {}
LoadPersistedUnsentLogs()84   void LoadPersistedUnsentLogs() override {}
85 
86  private:
87   std::string staged_log_hash_;
88   std::deque<TestLog> logs_;
89 };
90 
91 class TestReportingService : public ReportingService {
92  public:
TestReportingService(MetricsServiceClient * client,PrefService * local_state)93   TestReportingService(MetricsServiceClient* client, PrefService* local_state)
94       : ReportingService(client,
95                          local_state,
96                          100,
97                          /*logs_event_manager=*/nullptr) {
98     Initialize();
99   }
100 
101   TestReportingService(const TestReportingService&) = delete;
102   TestReportingService& operator=(const TestReportingService&) = delete;
103 
104   ~TestReportingService() override = default;
105 
AddLog(const TestLog & log)106   void AddLog(const TestLog& log) { log_store_.AddLog(log); }
HasUnsentLogs()107   bool HasUnsentLogs() { return log_store_.has_unsent_logs(); }
108 
109  private:
110   // ReportingService:
log_store()111   LogStore* log_store() override { return &log_store_; }
GetUploadUrl() const112   GURL GetUploadUrl() const override { return GURL(kTestUploadUrl); }
GetInsecureUploadUrl() const113   GURL GetInsecureUploadUrl() const override { return GURL(kTestUploadUrl); }
upload_mime_type() const114   std::string_view upload_mime_type() const override { return kTestMimeType; }
service_type() const115   MetricsLogUploader::MetricServiceType service_type() const override {
116     return MetricsLogUploader::MetricServiceType::UMA;
117   }
118 
119   TestLogStore log_store_;
120 };
121 
122 class ReportingServiceTest : public testing::Test {
123  public:
ReportingServiceTest()124   ReportingServiceTest()
125       : task_runner_(new base::TestSimpleTaskRunner),
126         task_runner_current_default_handle_(task_runner_) {
127     ReportingService::RegisterPrefs(testing_local_state_.registry());
128   }
129 
130   ReportingServiceTest(const ReportingServiceTest&) = delete;
131   ReportingServiceTest& operator=(const ReportingServiceTest&) = delete;
132 
133   ~ReportingServiceTest() override = default;
134 
GetLocalState()135   PrefService* GetLocalState() { return &testing_local_state_; }
136 
137  protected:
138   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
139   base::SingleThreadTaskRunner::CurrentDefaultHandle
140       task_runner_current_default_handle_;
141   TestMetricsServiceClient client_;
142 
143  private:
144   TestingPrefServiceSimple testing_local_state_;
145 };
146 
147 }  // namespace
148 
TEST_F(ReportingServiceTest,BasicTest)149 TEST_F(ReportingServiceTest, BasicTest) {
150   TestReportingService service(&client_, GetLocalState());
151   service.AddLog(TestLog("log1"));
152   service.AddLog(TestLog("log2"));
153 
154   service.EnableReporting();
155   task_runner_->RunPendingTasks();
156   EXPECT_TRUE(client_.uploader()->is_uploading());
157   EXPECT_EQ(1, client_.uploader()->reporting_info().attempt_count());
158   EXPECT_FALSE(client_.uploader()->reporting_info().has_last_response_code());
159 
160   client_.uploader()->CompleteUpload(404);
161   task_runner_->RunPendingTasks();
162   EXPECT_TRUE(client_.uploader()->is_uploading());
163   EXPECT_EQ(2, client_.uploader()->reporting_info().attempt_count());
164   EXPECT_EQ(404, client_.uploader()->reporting_info().last_response_code());
165 
166   client_.uploader()->CompleteUpload(200);
167   task_runner_->RunPendingTasks();
168   EXPECT_TRUE(client_.uploader()->is_uploading());
169   EXPECT_EQ(1, client_.uploader()->reporting_info().attempt_count());
170   EXPECT_EQ(200, client_.uploader()->reporting_info().last_response_code());
171 
172   client_.uploader()->CompleteUpload(200);
173   EXPECT_EQ(0U, task_runner_->NumPendingTasks());
174   EXPECT_FALSE(client_.uploader()->is_uploading());
175 }
176 
TEST_F(ReportingServiceTest,UserIdLogsUploadedIfUserConsented)177 TEST_F(ReportingServiceTest, UserIdLogsUploadedIfUserConsented) {
178   uint64_t user_id = 12345;
179 
180   TestReportingService service(&client_, GetLocalState());
181   service.AddLog(TestLog("log1", user_id));
182   service.AddLog(TestLog("log2", user_id));
183   service.EnableReporting();
184   client_.AllowMetricUploadForUserId(user_id);
185 
186   task_runner_->RunPendingTasks();
187   EXPECT_TRUE(client_.uploader()->is_uploading());
188   EXPECT_EQ(1, client_.uploader()->reporting_info().attempt_count());
189   EXPECT_FALSE(client_.uploader()->reporting_info().has_last_response_code());
190   client_.uploader()->CompleteUpload(200);
191 
192   // Upload 2nd log and last response code logged.
193   task_runner_->RunPendingTasks();
194   EXPECT_EQ(200, client_.uploader()->reporting_info().last_response_code());
195   EXPECT_TRUE(client_.uploader()->is_uploading());
196 
197   client_.uploader()->CompleteUpload(200);
198   EXPECT_EQ(0U, task_runner_->NumPendingTasks());
199   EXPECT_FALSE(client_.uploader()->is_uploading());
200 }
201 
TEST_F(ReportingServiceTest,UserIdLogsNotUploadedIfUserNotConsented)202 TEST_F(ReportingServiceTest, UserIdLogsNotUploadedIfUserNotConsented) {
203   TestReportingService service(&client_, GetLocalState());
204   service.AddLog(TestLog("log1", 12345));
205   service.AddLog(TestLog("log2", 12345));
206   service.EnableReporting();
207 
208   // Log with user id should never be in uploading state if user upload
209   // disabled. |client_.uploader()| should be nullptr since it is lazily
210   // created when a log is to be uploaded for the first time.
211   EXPECT_EQ(client_.uploader(), nullptr);
212 }
213 
TEST_F(ReportingServiceTest,ForceDiscard)214 TEST_F(ReportingServiceTest, ForceDiscard) {
215   TestReportingService service(&client_, GetLocalState());
216   service.AddLog(TestLog("log1"));
217 
218   service.EnableReporting();
219 
220   // Simulate the server returning a 500 error, which indicates that the server
221   // is unhealthy.
222   task_runner_->RunPendingTasks();
223   EXPECT_TRUE(client_.uploader()->is_uploading());
224   client_.uploader()->CompleteUpload(500);
225   task_runner_->RunPendingTasks();
226   // Verify that the log is not discarded so that it can be re-sent later.
227   EXPECT_TRUE(service.HasUnsentLogs());
228   EXPECT_TRUE(client_.uploader()->is_uploading());
229 
230   // Simulate the server returning a 500 error again, but this time, with
231   // |force_discard| set to true.
232   client_.uploader()->CompleteUpload(500, /*force_discard=*/true);
233   task_runner_->RunPendingTasks();
234   // Verify that the log was discarded, and that |service| is not uploading
235   // anymore since there are no more logs.
236   EXPECT_FALSE(service.HasUnsentLogs());
237   EXPECT_EQ(0U, task_runner_->NumPendingTasks());
238   EXPECT_FALSE(client_.uploader()->is_uploading());
239 }
240 
241 }  // namespace metrics
242