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
39class UploadServiceTest : public testing::Test {
40 protected:
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
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
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
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
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
105TEST_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
121TEST_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
146TEST_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
154TEST_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
160TEST_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
176TEST_F(UploadServiceTest, LogEmptyAfterUpload) {
177  SendSparseHistogram("hello", 2);
178
179  upload_service_->UploadEvent();
180  EXPECT_FALSE(upload_service_->current_log_);
181}
182
183TEST_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
193TEST_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
224TEST_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
238TEST_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
262TEST_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
281TEST_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.
293TEST_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
302TEST_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
319TEST_F(UploadServiceTest, PersistEmptyLog) {
320  upload_service_->PersistToDisk();
321  EXPECT_FALSE(base::PathExists(upload_service_->saved_log_path_));
322}
323
324TEST_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