1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <memory>
18 
19 #include <base/at_exit.h>
20 #include <base/files/file_util.h>
21 #include <base/files/scoped_temp_dir.h>
22 #include <base/logging.h>
23 #include <base/metrics/sparse_histogram.h>
24 #include <base/metrics/statistics_recorder.h>
25 #include <base/sys_info.h>
26 #include <gtest/gtest.h>
27 
28 #include "constants.h"
29 #include "persistent_integer.h"
30 #include "uploader/metrics_log.h"
31 #include "uploader/mock/mock_system_profile_setter.h"
32 #include "uploader/mock/sender_mock.h"
33 #include "uploader/proto/chrome_user_metrics_extension.pb.h"
34 #include "uploader/proto/histogram_event.pb.h"
35 #include "uploader/proto/system_profile.pb.h"
36 #include "uploader/system_profile_cache.h"
37 #include "uploader/upload_service.h"
38 
39 class UploadServiceTest : public testing::Test {
40  protected:
SetUp()41   virtual void SetUp() {
42     CHECK(dir_.CreateUniqueTempDir());
43     // Make sure the statistics recorder is inactive (contains no metrics) then
44     // initialize it.
45     ASSERT_FALSE(base::StatisticsRecorder::IsActive());
46     base::StatisticsRecorder::Initialize();
47 
48     private_dir_ = dir_.path().Append("private");
49     shared_dir_ = dir_.path().Append("shared");
50 
51     EXPECT_TRUE(base::CreateDirectory(private_dir_));
52     EXPECT_TRUE(base::CreateDirectory(shared_dir_));
53 
54     ASSERT_EQ(0, base::WriteFile(shared_dir_.Append(metrics::kConsentFileName),
55                                  "", 0));
56 
57     upload_service_.reset(new UploadService(
58         "", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
59     counters_ = upload_service_->counters_;
60 
61     upload_service_->sender_.reset(new SenderMock);
62     upload_service_->InitForTest(new MockSystemProfileSetter);
63     upload_service_->GatherHistograms();
64     upload_service_->Reset();
65   }
66 
SendSparseHistogram(const std::string & name,int sample)67   void SendSparseHistogram(const std::string& name, int sample) {
68     base::HistogramBase* histogram = base::SparseHistogram::FactoryGet(
69         name, base::Histogram::kUmaTargetedHistogramFlag);
70     histogram->Add(sample);
71   }
72 
SendHistogram(const std::string & name,int sample,int min,int max,int nbuckets)73   void SendHistogram(
74       const std::string& name, int sample, int min, int max, int nbuckets) {
75     base::HistogramBase* histogram = base::Histogram::FactoryGet(
76         name, min, max, nbuckets, base::Histogram::kUmaTargetedHistogramFlag);
77     histogram->Add(sample);
78   }
79 
SetTestingProperty(const std::string & name,const std::string & value)80   void SetTestingProperty(const std::string& name, const std::string& value) {
81     base::FilePath filepath =
82         dir_.path().Append("etc/os-release.d").Append(name);
83     ASSERT_TRUE(base::CreateDirectory(filepath.DirName()));
84     ASSERT_EQ(value.size(),
85               base::WriteFile(filepath, value.data(), value.size()));
86   }
87 
GetCurrentStability()88   const metrics::SystemProfileProto_Stability GetCurrentStability() {
89     EXPECT_TRUE(upload_service_->current_log_.get());
90 
91     return upload_service_->current_log_->uma_proto()
92         ->system_profile()
93         .stability();
94   }
95 
96   base::ScopedTempDir dir_;
97   std::unique_ptr<UploadService> upload_service_;
98 
99   std::unique_ptr<base::AtExitManager> exit_manager_;
100   std::shared_ptr<CrashCounters> counters_;
101   base::FilePath private_dir_;
102   base::FilePath shared_dir_;
103 };
104 
TEST_F(UploadServiceTest,FailedSendAreRetried)105 TEST_F(UploadServiceTest, FailedSendAreRetried) {
106   SenderMock* sender = new SenderMock();
107   upload_service_->sender_.reset(sender);
108 
109   sender->set_should_succeed(false);
110 
111   SendSparseHistogram("hello", 1);
112   upload_service_->UploadEvent();
113   EXPECT_EQ(1, sender->send_call_count());
114   std::string sent_string = sender->last_message();
115 
116   upload_service_->UploadEvent();
117   EXPECT_EQ(2, sender->send_call_count());
118   EXPECT_EQ(sent_string, sender->last_message());
119 }
120 
TEST_F(UploadServiceTest,DiscardLogsAfterTooManyFailedUpload)121 TEST_F(UploadServiceTest, DiscardLogsAfterTooManyFailedUpload) {
122   SenderMock* sender = new SenderMock();
123   upload_service_->sender_.reset(sender);
124 
125   sender->set_should_succeed(false);
126 
127   SendSparseHistogram("hello", 1);
128 
129   for (int i = 0; i < UploadService::kMaxFailedUpload; i++) {
130     upload_service_->UploadEvent();
131   }
132 
133   EXPECT_TRUE(upload_service_->HasStagedLog());
134   upload_service_->UploadEvent();
135   EXPECT_FALSE(upload_service_->HasStagedLog());
136 
137   // Log a new sample. The failed upload counter should be reset.
138   SendSparseHistogram("hello", 1);
139   for (int i = 0; i < UploadService::kMaxFailedUpload; i++) {
140     upload_service_->UploadEvent();
141   }
142   // The log is not discarded after multiple failed uploads.
143   EXPECT_TRUE(upload_service_->HasStagedLog());
144 }
145 
TEST_F(UploadServiceTest,EmptyLogsAreNotSent)146 TEST_F(UploadServiceTest, EmptyLogsAreNotSent) {
147   SenderMock* sender = new SenderMock();
148   upload_service_->sender_.reset(sender);
149   upload_service_->UploadEvent();
150   EXPECT_FALSE(upload_service_->current_log_);
151   EXPECT_EQ(0, sender->send_call_count());
152 }
153 
TEST_F(UploadServiceTest,LogEmptyByDefault)154 TEST_F(UploadServiceTest, LogEmptyByDefault) {
155   // current_log_ should be initialized later as it needs AtExitManager to exist
156   // in order to gather system information from SysInfo.
157   EXPECT_FALSE(upload_service_->current_log_);
158 }
159 
TEST_F(UploadServiceTest,CanSendMultipleTimes)160 TEST_F(UploadServiceTest, CanSendMultipleTimes) {
161   SenderMock* sender = new SenderMock();
162   upload_service_->sender_.reset(sender);
163 
164   SendSparseHistogram("hello", 1);
165 
166   upload_service_->UploadEvent();
167 
168   std::string first_message = sender->last_message();
169   SendSparseHistogram("hello", 2);
170 
171   upload_service_->UploadEvent();
172 
173   EXPECT_NE(first_message, sender->last_message());
174 }
175 
TEST_F(UploadServiceTest,LogEmptyAfterUpload)176 TEST_F(UploadServiceTest, LogEmptyAfterUpload) {
177   SendSparseHistogram("hello", 2);
178 
179   upload_service_->UploadEvent();
180   EXPECT_FALSE(upload_service_->current_log_);
181 }
182 
TEST_F(UploadServiceTest,LogContainsAggregatedValues)183 TEST_F(UploadServiceTest, LogContainsAggregatedValues) {
184   SendHistogram("foo", 11, 0, 42, 10);
185   SendHistogram("foo", 12, 0, 42, 10);
186 
187   upload_service_->GatherHistograms();
188   metrics::ChromeUserMetricsExtension* proto =
189       upload_service_->current_log_->uma_proto();
190   EXPECT_EQ(1, proto->histogram_event().size());
191 }
192 
TEST_F(UploadServiceTest,LogContainsCrashCounts)193 TEST_F(UploadServiceTest, LogContainsCrashCounts) {
194   // By default, there is no current log.
195   upload_service_->GatherHistograms();
196   EXPECT_FALSE(upload_service_->current_log_);
197 
198   // If the user crash counter is incremented, we add the count to the current
199   // log.
200   counters_->IncrementUserCrashCount();
201   upload_service_->GatherHistograms();
202   EXPECT_EQ(1, GetCurrentStability().other_user_crash_count());
203 
204   // If the kernel crash counter is incremented, we add the count to the current
205   // log.
206   counters_->IncrementKernelCrashCount();
207   upload_service_->GatherHistograms();
208   EXPECT_EQ(1, GetCurrentStability().kernel_crash_count());
209 
210   // If the kernel crash counter is incremented, we add the count to the current
211   // log.
212   counters_->IncrementUncleanShutdownCount();
213   counters_->IncrementUncleanShutdownCount();
214   upload_service_->GatherHistograms();
215   EXPECT_EQ(2, GetCurrentStability().unclean_system_shutdown_count());
216 
217   // If no counter is incremented, the reported numbers don't change.
218   upload_service_->GatherHistograms();
219   EXPECT_EQ(1, GetCurrentStability().other_user_crash_count());
220   EXPECT_EQ(1, GetCurrentStability().kernel_crash_count());
221   EXPECT_EQ(2, GetCurrentStability().unclean_system_shutdown_count());
222 }
223 
TEST_F(UploadServiceTest,ExtractChannelFromString)224 TEST_F(UploadServiceTest, ExtractChannelFromString) {
225   EXPECT_EQ(SystemProfileCache::ProtoChannelFromString("developer-build"),
226             metrics::SystemProfileProto::CHANNEL_UNKNOWN);
227 
228   EXPECT_EQ(metrics::SystemProfileProto::CHANNEL_DEV,
229             SystemProfileCache::ProtoChannelFromString("dev-channel"));
230 
231   EXPECT_EQ(metrics::SystemProfileProto::CHANNEL_STABLE,
232             SystemProfileCache::ProtoChannelFromString("stable-channel"));
233 
234   EXPECT_EQ(metrics::SystemProfileProto::CHANNEL_UNKNOWN,
235             SystemProfileCache::ProtoChannelFromString("this is a test"));
236 }
237 
TEST_F(UploadServiceTest,ValuesInConfigFileAreSent)238 TEST_F(UploadServiceTest, ValuesInConfigFileAreSent) {
239   SenderMock* sender = new SenderMock();
240   upload_service_->sender_.reset(sender);
241 
242   SetTestingProperty(metrics::kProductId, "hello");
243   SetTestingProperty(metrics::kProductVersion, "1.2.3.4");
244 
245   SendSparseHistogram("hello", 1);
246 
247   // Reset to create the new log with the profile setter.
248   upload_service_->system_profile_setter_.reset(
249       new SystemProfileCache(true, dir_.path()));
250   upload_service_->Reset();
251   upload_service_->UploadEvent();
252 
253   EXPECT_EQ(1, sender->send_call_count());
254   EXPECT_TRUE(sender->is_good_proto());
255   EXPECT_EQ(1, sender->last_message_proto().histogram_event().size());
256 
257   EXPECT_NE(0, sender->last_message_proto().client_id());
258   EXPECT_NE(0, sender->last_message_proto().system_profile().build_timestamp());
259   EXPECT_NE(0, sender->last_message_proto().session_id());
260 }
261 
TEST_F(UploadServiceTest,PersistentGUID)262 TEST_F(UploadServiceTest, PersistentGUID) {
263   std::string tmp_file = dir_.path().Append("tmpfile").value();
264 
265   std::string first_guid = SystemProfileCache::GetPersistentGUID(tmp_file);
266   std::string second_guid = SystemProfileCache::GetPersistentGUID(tmp_file);
267 
268   // The GUID are cached.
269   EXPECT_EQ(first_guid, second_guid);
270 
271   base::DeleteFile(base::FilePath(tmp_file), false);
272 
273   first_guid = SystemProfileCache::GetPersistentGUID(tmp_file);
274   base::DeleteFile(base::FilePath(tmp_file), false);
275   second_guid = SystemProfileCache::GetPersistentGUID(tmp_file);
276 
277   // Random GUIDs are generated (not all the same).
278   EXPECT_NE(first_guid, second_guid);
279 }
280 
TEST_F(UploadServiceTest,SessionIdIncrementedAtInitialization)281 TEST_F(UploadServiceTest, SessionIdIncrementedAtInitialization) {
282   SetTestingProperty(metrics::kProductId, "hello");
283   SystemProfileCache cache(true, dir_.path());
284   cache.Initialize();
285   int session_id = cache.profile_.session_id;
286   cache.initialized_ = false;
287   cache.Initialize();
288   EXPECT_EQ(cache.profile_.session_id, session_id + 1);
289 }
290 
291 // The product id must be set for metrics to be uploaded.
292 // If it is not set, the system profile cache should fail to initialize.
TEST_F(UploadServiceTest,ProductIdMandatory)293 TEST_F(UploadServiceTest, ProductIdMandatory) {
294   SystemProfileCache cache(true, dir_.path());
295   ASSERT_FALSE(cache.Initialize());
296   SetTestingProperty(metrics::kProductId, "");
297   ASSERT_FALSE(cache.Initialize());
298   SetTestingProperty(metrics::kProductId, "hello");
299   ASSERT_TRUE(cache.Initialize());
300 }
301 
TEST_F(UploadServiceTest,CurrentLogSavedAndResumed)302 TEST_F(UploadServiceTest, CurrentLogSavedAndResumed) {
303   SendHistogram("hello", 10, 0, 100, 10);
304   upload_service_->PersistToDisk();
305   EXPECT_EQ(
306       1, upload_service_->current_log_->uma_proto()->histogram_event().size());
307   upload_service_.reset(new UploadService(
308       "", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
309   upload_service_->InitForTest(nullptr);
310 
311   SendHistogram("hello", 10, 0, 100, 10);
312   upload_service_->GatherHistograms();
313   EXPECT_EQ(2, upload_service_->GetOrCreateCurrentLog()
314                    ->uma_proto()
315                    ->histogram_event()
316                    .size());
317 }
318 
TEST_F(UploadServiceTest,PersistEmptyLog)319 TEST_F(UploadServiceTest, PersistEmptyLog) {
320   upload_service_->PersistToDisk();
321   EXPECT_FALSE(base::PathExists(upload_service_->saved_log_path_));
322 }
323 
TEST_F(UploadServiceTest,CorruptedSavedLog)324 TEST_F(UploadServiceTest, CorruptedSavedLog) {
325   // Write a bogus saved log.
326   EXPECT_EQ(5, base::WriteFile(upload_service_->saved_log_path_, "hello", 5));
327 
328   upload_service_.reset(new UploadService(
329       "", base::TimeDelta(), base::TimeDelta(), private_dir_, shared_dir_));
330 
331   upload_service_->InitForTest(nullptr);
332   // If the log is unreadable, we drop it and continue execution.
333   ASSERT_NE(nullptr, upload_service_->GetOrCreateCurrentLog());
334   ASSERT_FALSE(base::PathExists(upload_service_->saved_log_path_));
335 }
336