• 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/unsent_log_store.h"
6 
7 #include <stddef.h>
8 #include <limits>
9 
10 #include "base/base64.h"
11 #include "base/hash/sha1.h"
12 #include "base/rand_util.h"
13 #include "base/values.h"
14 #include "components/metrics/unsent_log_store_metrics_impl.h"
15 #include "components/prefs/pref_registry_simple.h"
16 #include "components/prefs/scoped_user_pref_update.h"
17 #include "components/prefs/testing_pref_service.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/zlib/google/compression_utils.h"
20 
21 namespace metrics {
22 
23 namespace {
24 
25 const char kTestPrefName[] = "TestPref";
26 const char kTestMetaDataPrefName[] = "TestMetaDataPref";
27 
28 const size_t kLogCountLimit = 3;
29 const size_t kLogByteLimit = 1000;
30 
31 // Compresses |log_data| and returns the result.
Compress(const std::string & log_data)32 std::string Compress(const std::string& log_data) {
33   std::string compressed_log_data;
34   EXPECT_TRUE(compression::GzipCompress(log_data, &compressed_log_data));
35   return compressed_log_data;
36 }
37 
38 // Generates and returns log data such that its size after compression is at
39 // least |min_compressed_size|.
GenerateLogWithMinCompressedSize(size_t min_compressed_size)40 std::string GenerateLogWithMinCompressedSize(size_t min_compressed_size) {
41   // Since the size check is done against a compressed log, generate enough
42   // data that compresses to larger than |log_size|.
43   std::string rand_bytes = base::RandBytesAsString(min_compressed_size);
44   while (Compress(rand_bytes).size() < min_compressed_size)
45     rand_bytes.append(base::RandBytesAsString(min_compressed_size));
46   std::string base64_data_for_logging;
47   base::Base64Encode(rand_bytes, &base64_data_for_logging);
48   SCOPED_TRACE(testing::Message()
49                << "Using random data " << base64_data_for_logging);
50   return rand_bytes;
51 }
52 
53 class UnsentLogStoreTest : public testing::Test {
54  public:
UnsentLogStoreTest()55   UnsentLogStoreTest() {
56     prefs_.registry()->RegisterListPref(kTestPrefName);
57     prefs_.registry()->RegisterDictionaryPref(kTestMetaDataPrefName);
58   }
59 
60   UnsentLogStoreTest(const UnsentLogStoreTest&) = delete;
61   UnsentLogStoreTest& operator=(const UnsentLogStoreTest&) = delete;
62 
63  protected:
64   TestingPrefServiceSimple prefs_;
65 };
66 
67 class TestUnsentLogStoreMetrics : public UnsentLogStoreMetrics {
68  public:
69   TestUnsentLogStoreMetrics() = default;
70 
RecordLastUnsentLogMetadataMetrics(int unsent_samples_count,int sent_samples_count,int persisted_size_in_kb)71   void RecordLastUnsentLogMetadataMetrics(int unsent_samples_count,
72                                           int sent_samples_count,
73                                           int persisted_size_in_kb) override {
74     unsent_samples_count_ = unsent_samples_count;
75     sent_samples_count_ = sent_samples_count;
76     persisted_size_in_kb_ = persisted_size_in_kb;
77   }
78 
unsent_samples_count() const79   int unsent_samples_count() const { return unsent_samples_count_; }
sent_samples_count() const80   int sent_samples_count() const { return sent_samples_count_; }
persisted_size_in_kb() const81   int persisted_size_in_kb() const { return persisted_size_in_kb_; }
82 
83  private:
84   int unsent_samples_count_ = 0;
85   int sent_samples_count_ = 0;
86   int persisted_size_in_kb_ = 0;
87 };
88 
89 class TestUnsentLogStore : public UnsentLogStore {
90  public:
TestUnsentLogStore(PrefService * service,size_t min_log_bytes)91   TestUnsentLogStore(PrefService* service, size_t min_log_bytes)
92       : UnsentLogStore(std::make_unique<UnsentLogStoreMetricsImpl>(),
93                        service,
94                        kTestPrefName,
95                        /*metadata_pref_name=*/nullptr,
96                        UnsentLogStore::UnsentLogStoreLimits{
97                            .min_log_count = kLogCountLimit,
98                            .min_queue_size_bytes = min_log_bytes,
99                        },
100                        /*signing_key=*/std::string(),
101                        /*logs_event_manager=*/nullptr) {}
TestUnsentLogStore(PrefService * service,size_t min_log_bytes,const std::string & signing_key)102   TestUnsentLogStore(PrefService* service,
103                      size_t min_log_bytes,
104                      const std::string& signing_key)
105       : UnsentLogStore(std::make_unique<UnsentLogStoreMetricsImpl>(),
106                        service,
107                        kTestPrefName,
108                        /*metadata_pref_name=*/nullptr,
109                        UnsentLogStore::UnsentLogStoreLimits{
110                            .min_log_count = kLogCountLimit,
111                            .min_queue_size_bytes = min_log_bytes,
112                        },
113                        signing_key,
114                        /*logs_event_manager=*/nullptr) {}
TestUnsentLogStore(std::unique_ptr<UnsentLogStoreMetrics> metrics,PrefService * service,size_t max_log_size)115   TestUnsentLogStore(std::unique_ptr<UnsentLogStoreMetrics> metrics,
116                      PrefService* service,
117                      size_t max_log_size)
118       : UnsentLogStore(std::move(metrics),
119                        service,
120                        kTestPrefName,
121                        kTestMetaDataPrefName,
122                        UnsentLogStore::UnsentLogStoreLimits{
123                            .min_log_count = kLogCountLimit,
124                            .min_queue_size_bytes = 1,
125                            .max_log_size_bytes = max_log_size,
126                        },
127                        /*signing_key=*/std::string(),
128                        /*logs_event_manager=*/nullptr) {}
129 
130   TestUnsentLogStore(const TestUnsentLogStore&) = delete;
131   TestUnsentLogStore& operator=(const TestUnsentLogStore&) = delete;
132 
133   // Stages and removes the next log, while testing it's value.
ExpectNextLog(const std::string & expected_log)134   void ExpectNextLog(const std::string& expected_log) {
135     StageNextLog();
136     EXPECT_EQ(staged_log(), Compress(expected_log));
137     DiscardStagedLog();
138   }
139 };
140 
141 }  // namespace
142 
143 // Store and retrieve empty list_value.
TEST_F(UnsentLogStoreTest,EmptyLogList)144 TEST_F(UnsentLogStoreTest, EmptyLogList) {
145   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
146 
147   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
148   EXPECT_EQ(0U, prefs_.GetList(kTestPrefName).size());
149 
150   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
151   result_unsent_log_store.LoadPersistedUnsentLogs();
152   EXPECT_EQ(0U, result_unsent_log_store.size());
153 }
154 
155 // Store and retrieve a single log value.
TEST_F(UnsentLogStoreTest,SingleElementLogList)156 TEST_F(UnsentLogStoreTest, SingleElementLogList) {
157   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
158 
159   LogMetadata log_metadata;
160   unsent_log_store.StoreLog("Hello world!", log_metadata,
161                             MetricsLogsEventManager::CreateReason::kUnknown);
162   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
163 
164   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
165   result_unsent_log_store.LoadPersistedUnsentLogs();
166   EXPECT_EQ(1U, result_unsent_log_store.size());
167 
168   // Verify that the result log matches the initial log.
169   unsent_log_store.StageNextLog();
170   result_unsent_log_store.StageNextLog();
171   EXPECT_EQ(unsent_log_store.staged_log(),
172             result_unsent_log_store.staged_log());
173   EXPECT_EQ(unsent_log_store.staged_log_hash(),
174             result_unsent_log_store.staged_log_hash());
175   EXPECT_EQ(unsent_log_store.staged_log_signature(),
176             result_unsent_log_store.staged_log_signature());
177   EXPECT_EQ(unsent_log_store.staged_log_timestamp(),
178             result_unsent_log_store.staged_log_timestamp());
179 }
180 
181 // Store a set of logs over the length limit, but smaller than the min number of
182 // bytes. This should leave the logs unchanged.
TEST_F(UnsentLogStoreTest,LongButTinyLogList)183 TEST_F(UnsentLogStoreTest, LongButTinyLogList) {
184   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
185   LogMetadata log_metadata;
186 
187   size_t log_count = kLogCountLimit * 5;
188   for (size_t i = 0; i < log_count; ++i)
189     unsent_log_store.StoreLog("x", log_metadata,
190                               MetricsLogsEventManager::CreateReason::kUnknown);
191 
192   EXPECT_EQ(log_count, unsent_log_store.size());
193   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
194   EXPECT_EQ(log_count, unsent_log_store.size());
195 
196   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
197   result_unsent_log_store.LoadPersistedUnsentLogs();
198   EXPECT_EQ(unsent_log_store.size(), result_unsent_log_store.size());
199 
200   result_unsent_log_store.ExpectNextLog("x");
201 }
202 
203 // Store a set of logs over the length limit, but that doesn't reach the minimum
204 // number of bytes until after passing the length limit.
TEST_F(UnsentLogStoreTest,LongButSmallLogList)205 TEST_F(UnsentLogStoreTest, LongButSmallLogList) {
206   size_t log_count = kLogCountLimit * 5;
207   size_t log_size = 50;
208   LogMetadata log_metadata;
209 
210   std::string first_kept = "First to keep";
211   first_kept.resize(log_size, ' ');
212 
213   std::string blank_log = std::string(log_size, ' ');
214 
215   std::string last_kept = "Last to keep";
216   last_kept.resize(log_size, ' ');
217 
218   // Set the byte limit enough to keep everything but the first two logs.
219   const size_t min_log_bytes = Compress(first_kept).length() +
220                                Compress(last_kept).length() +
221                                (log_count - 4) * Compress(blank_log).length();
222   TestUnsentLogStore unsent_log_store(&prefs_, min_log_bytes);
223 
224   unsent_log_store.StoreLog("one", log_metadata,
225                             MetricsLogsEventManager::CreateReason::kUnknown);
226   unsent_log_store.StoreLog("two", log_metadata,
227                             MetricsLogsEventManager::CreateReason::kUnknown);
228   unsent_log_store.StoreLog(first_kept, log_metadata,
229                             MetricsLogsEventManager::CreateReason::kUnknown);
230   for (size_t i = unsent_log_store.size(); i < log_count - 1; ++i) {
231     unsent_log_store.StoreLog(blank_log, log_metadata,
232                               MetricsLogsEventManager::CreateReason::kUnknown);
233   }
234   unsent_log_store.StoreLog(last_kept, log_metadata,
235                             MetricsLogsEventManager::CreateReason::kUnknown);
236 
237   size_t original_size = unsent_log_store.size();
238   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
239   // New size has been reduced.
240   EXPECT_EQ(original_size - 2, unsent_log_store.size());
241 
242   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
243   result_unsent_log_store.LoadPersistedUnsentLogs();
244   // Prefs should be the same size.
245   EXPECT_EQ(unsent_log_store.size(), result_unsent_log_store.size());
246 
247   result_unsent_log_store.ExpectNextLog(last_kept);
248   while (result_unsent_log_store.size() > 1) {
249     result_unsent_log_store.ExpectNextLog(blank_log);
250   }
251   result_unsent_log_store.ExpectNextLog(first_kept);
252 }
253 
254 // Store a set of logs within the length limit, but well over the minimum
255 // number of bytes. This should leave the logs unchanged.
TEST_F(UnsentLogStoreTest,ShortButLargeLogList)256 TEST_F(UnsentLogStoreTest, ShortButLargeLogList) {
257   // Make the total byte count about twice the minimum.
258   size_t log_count = kLogCountLimit;
259   size_t log_size = (kLogByteLimit / log_count) * 2;
260   std::string log_data = GenerateLogWithMinCompressedSize(log_size);
261 
262   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
263   LogMetadata log_metadata;
264   for (size_t i = 0; i < log_count; ++i) {
265     unsent_log_store.StoreLog(log_data, log_metadata,
266                               MetricsLogsEventManager::CreateReason::kUnknown);
267   }
268   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
269 
270   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
271   result_unsent_log_store.LoadPersistedUnsentLogs();
272   // Both have expected number of logs (original amount).
273   EXPECT_EQ(kLogCountLimit, unsent_log_store.size());
274   EXPECT_EQ(kLogCountLimit, result_unsent_log_store.size());
275 }
276 
277 // Store a set of logs over the length limit, and over the minimum number of
278 // bytes. This will trim the set of logs.
TEST_F(UnsentLogStoreTest,LongAndLargeLogList)279 TEST_F(UnsentLogStoreTest, LongAndLargeLogList) {
280   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
281 
282   // Include twice the max number of logs.
283   size_t log_count = kLogCountLimit * 2;
284   // Make the total byte count about four times the minimum.
285   size_t log_size = (kLogByteLimit / log_count) * 4;
286 
287   std::string target_log = "First to keep";
288   target_log += GenerateLogWithMinCompressedSize(log_size);
289 
290   std::string log_data = GenerateLogWithMinCompressedSize(log_size);
291   LogMetadata log_metadata;
292   for (size_t i = 0; i < log_count; ++i) {
293     if (i == log_count - kLogCountLimit)
294       unsent_log_store.StoreLog(
295           target_log, log_metadata,
296           MetricsLogsEventManager::CreateReason::kUnknown);
297     else
298       unsent_log_store.StoreLog(
299           log_data, log_metadata,
300           MetricsLogsEventManager::CreateReason::kUnknown);
301   }
302 
303   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
304 
305   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
306   result_unsent_log_store.LoadPersistedUnsentLogs();
307   // Both original log and persisted are reduced to limit.
308   EXPECT_EQ(kLogCountLimit, unsent_log_store.size());
309   EXPECT_EQ(kLogCountLimit, result_unsent_log_store.size());
310 
311   while (result_unsent_log_store.size() > 1) {
312     result_unsent_log_store.ExpectNextLog(log_data);
313   }
314   result_unsent_log_store.ExpectNextLog(target_log);
315 }
316 
317 // Store a set of logs over the length limit, and over the minimum number of
318 // bytes. The first log will be a staged log that should be trimmed away. This
319 // should make the log store not have a staged log anymore.
TEST_F(UnsentLogStoreTest,TrimStagedLog)320 TEST_F(UnsentLogStoreTest, TrimStagedLog) {
321   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
322 
323   // Make each log byte count the limit.
324   size_t log_size = kLogByteLimit;
325 
326   // Create a target log that will be the staged log that we want to trim away.
327   std::string target_log = "First that should be trimmed";
328   target_log += GenerateLogWithMinCompressedSize(log_size);
329   LogMetadata log_metadata;
330   unsent_log_store.StoreLog(target_log, log_metadata,
331                             MetricsLogsEventManager::CreateReason::kUnknown);
332   unsent_log_store.StageNextLog();
333   EXPECT_TRUE(unsent_log_store.has_staged_log());
334 
335   // Add |kLogCountLimit| additional logs.
336   std::string log_data = GenerateLogWithMinCompressedSize(log_size);
337   for (size_t i = 0; i < kLogCountLimit; ++i) {
338     unsent_log_store.StoreLog(log_data, log_metadata,
339                               MetricsLogsEventManager::CreateReason::kUnknown);
340   }
341 
342   EXPECT_EQ(kLogCountLimit + 1, unsent_log_store.size());
343   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
344 
345   // Verify that the first log (the staged one) was trimmed away, and that the
346   // log store does not consider to have any staged log anymore. The other logs
347   // are not trimmed because the most recent logs are prioritized and we trim
348   // until we have |kLogCountLimit| logs.
349   EXPECT_EQ(kLogCountLimit, unsent_log_store.size());
350   EXPECT_FALSE(unsent_log_store.has_staged_log());
351   // Verify that all of the logs in the log store are not the |target_log|.
352   while (unsent_log_store.size() > 0) {
353     unsent_log_store.ExpectNextLog(log_data);
354   }
355 }
356 
357 // Verifies that when calling TrimAndPersistUnsentLogs() with
358 // |overwrite_in_memory_store| set to false, the in memory log store is
359 // unaffected.
TEST_F(UnsentLogStoreTest,TrimAndPersistUnsentLogs_DoNotOverwriteInMemoryStore)360 TEST_F(UnsentLogStoreTest,
361        TrimAndPersistUnsentLogs_DoNotOverwriteInMemoryStore) {
362   TestUnsentLogStore unsent_log_store(
363       std::make_unique<UnsentLogStoreMetricsImpl>(), &prefs_, kLogByteLimit);
364 
365   LogMetadata log_metadata;
366   std::string log_data = GenerateLogWithMinCompressedSize(kLogByteLimit + 1);
367   unsent_log_store.StoreLog(log_data, log_metadata,
368                             MetricsLogsEventManager::CreateReason::kUnknown);
369   unsent_log_store.TrimAndPersistUnsentLogs(
370       /*overwrite_in_memory_store=*/false);
371 
372   // Verify that the log store still contains the log.
373   EXPECT_EQ(1U, unsent_log_store.size());
374   unsent_log_store.ExpectNextLog(log_data);
375 
376   // Verify that the log was trimmed when persisted to memory.
377   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
378   result_unsent_log_store.LoadPersistedUnsentLogs();
379   EXPECT_EQ(0U, result_unsent_log_store.size());
380 }
381 
382 // Verifies that TrimAndPersistUnsentLogs() maintains the log order.
TEST_F(UnsentLogStoreTest,TrimAndPersistUnsentLogs_MaintainsLogOrder)383 TEST_F(UnsentLogStoreTest, TrimAndPersistUnsentLogs_MaintainsLogOrder) {
384   TestUnsentLogStore unsent_log_store(
385       std::make_unique<UnsentLogStoreMetricsImpl>(), &prefs_, kLogByteLimit);
386 
387   LogMetadata log_metadata;
388   unsent_log_store.StoreLog("1", log_metadata,
389                             MetricsLogsEventManager::CreateReason::kUnknown);
390   unsent_log_store.StoreLog(GenerateLogWithMinCompressedSize(kLogByteLimit + 1),
391                             log_metadata,
392                             MetricsLogsEventManager::CreateReason::kUnknown);
393   unsent_log_store.StoreLog("2", log_metadata,
394                             MetricsLogsEventManager::CreateReason::kUnknown);
395   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
396 
397   // Verify that only the second log was trimmed (since it was over the max log
398   // size), and that the log order was maintained. I.e., "2" should be the most
399   // recent log, followed by "1".
400   EXPECT_EQ(2U, unsent_log_store.size());
401   unsent_log_store.ExpectNextLog("2");
402   unsent_log_store.ExpectNextLog("1");
403 
404   // Similarly, verify that the order was also maintained in persistent memory.
405   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
406   result_unsent_log_store.LoadPersistedUnsentLogs();
407   EXPECT_EQ(2U, result_unsent_log_store.size());
408   result_unsent_log_store.ExpectNextLog("2");
409   result_unsent_log_store.ExpectNextLog("1");
410 }
411 
412 // Verifies that calling TrimAndPersistUnsentLogs() clears the pref list before
413 // writing the trimmed logs list.
TEST_F(UnsentLogStoreTest,TrimAndPersistUnsentLogs_OverwritesPrefs)414 TEST_F(UnsentLogStoreTest, TrimAndPersistUnsentLogs_OverwritesPrefs) {
415   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
416 
417   LogMetadata log_metadata;
418   unsent_log_store.StoreLog("Hello world!", log_metadata,
419                             MetricsLogsEventManager::CreateReason::kUnknown);
420   // Call TrimAndPersistUnsentLogs(). The log should not be trimmed.
421   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
422 
423   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
424   result_unsent_log_store.LoadPersistedUnsentLogs();
425   EXPECT_EQ(1U, result_unsent_log_store.size());
426 
427   // Verify that the result log matches the initial log.
428   result_unsent_log_store.ExpectNextLog("Hello world!");
429 
430   // Call TrimAndPersistUnsentLogs() and load the persisted logs once again.
431   // There should still only be one log.
432   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
433 
434   TestUnsentLogStore result_unsent_log_store2(&prefs_, kLogByteLimit);
435   result_unsent_log_store2.LoadPersistedUnsentLogs();
436   EXPECT_EQ(1U, result_unsent_log_store2.size());
437 
438   // Verify that the result log matches the initial log.
439   result_unsent_log_store2.ExpectNextLog("Hello world!");
440 }
441 
442 // Check that the store/stage/discard functions work as expected.
TEST_F(UnsentLogStoreTest,Staging)443 TEST_F(UnsentLogStoreTest, Staging) {
444   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
445   LogMetadata log_metadata;
446   std::string tmp;
447 
448   EXPECT_FALSE(unsent_log_store.has_staged_log());
449   unsent_log_store.StoreLog("one", log_metadata,
450                             MetricsLogsEventManager::CreateReason::kUnknown);
451   EXPECT_FALSE(unsent_log_store.has_staged_log());
452   unsent_log_store.StoreLog("two", log_metadata,
453                             MetricsLogsEventManager::CreateReason::kUnknown);
454   unsent_log_store.StageNextLog();
455   EXPECT_TRUE(unsent_log_store.has_staged_log());
456   EXPECT_EQ(unsent_log_store.staged_log(), Compress("two"));
457   unsent_log_store.StoreLog("three", log_metadata,
458                             MetricsLogsEventManager::CreateReason::kUnknown);
459   EXPECT_EQ(unsent_log_store.staged_log(), Compress("two"));
460   EXPECT_EQ(unsent_log_store.size(), 3U);
461   unsent_log_store.DiscardStagedLog();
462   EXPECT_FALSE(unsent_log_store.has_staged_log());
463   EXPECT_EQ(unsent_log_store.size(), 2U);
464   unsent_log_store.StageNextLog();
465   EXPECT_EQ(unsent_log_store.staged_log(), Compress("three"));
466   unsent_log_store.DiscardStagedLog();
467   unsent_log_store.StageNextLog();
468   EXPECT_EQ(unsent_log_store.staged_log(), Compress("one"));
469   unsent_log_store.DiscardStagedLog();
470   EXPECT_FALSE(unsent_log_store.has_staged_log());
471   EXPECT_EQ(unsent_log_store.size(), 0U);
472 }
473 
TEST_F(UnsentLogStoreTest,DiscardOrder)474 TEST_F(UnsentLogStoreTest, DiscardOrder) {
475   // Ensure that the correct log is discarded if new logs are pushed while
476   // a log is staged.
477   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
478   LogMetadata log_metadata;
479 
480   unsent_log_store.StoreLog("one", log_metadata,
481                             MetricsLogsEventManager::CreateReason::kUnknown);
482   unsent_log_store.StageNextLog();
483   unsent_log_store.StoreLog("two", log_metadata,
484                             MetricsLogsEventManager::CreateReason::kUnknown);
485   unsent_log_store.DiscardStagedLog();
486   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
487 
488   TestUnsentLogStore result_unsent_log_store(&prefs_, kLogByteLimit);
489   result_unsent_log_store.LoadPersistedUnsentLogs();
490   EXPECT_EQ(1U, result_unsent_log_store.size());
491   result_unsent_log_store.ExpectNextLog("two");
492 }
493 
TEST_F(UnsentLogStoreTest,Hashes)494 TEST_F(UnsentLogStoreTest, Hashes) {
495   const char kFooText[] = "foo";
496   const std::string foo_hash = base::SHA1HashString(kFooText);
497   LogMetadata log_metadata;
498 
499   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
500   unsent_log_store.StoreLog(kFooText, log_metadata,
501                             MetricsLogsEventManager::CreateReason::kUnknown);
502   unsent_log_store.StageNextLog();
503 
504   EXPECT_EQ(Compress(kFooText), unsent_log_store.staged_log());
505   EXPECT_EQ(foo_hash, unsent_log_store.staged_log_hash());
506 }
507 
TEST_F(UnsentLogStoreTest,Signatures)508 TEST_F(UnsentLogStoreTest, Signatures) {
509   const char kFooText[] = "foo";
510   LogMetadata log_metadata;
511 
512   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
513   unsent_log_store.StoreLog(kFooText, log_metadata,
514                             MetricsLogsEventManager::CreateReason::kUnknown);
515   unsent_log_store.StageNextLog();
516 
517   EXPECT_EQ(Compress(kFooText), unsent_log_store.staged_log());
518 
519   // The expected signature as a base 64 encoded string. The value was obtained
520   // by running the test with an empty expected_signature_base64 and taking the
521   // actual value from the test failure message. Can be verifying by the
522   // following python code:
523   // import hmac, hashlib, base64
524   // key = ''
525   // print(base64.b64encode(
526   //   hmac.new(key, msg='foo', digestmod=hashlib.sha256).digest()).decode())
527   std::string expected_signature_base64 =
528       "DA2Y9+PZ1F5y6Id7wbEEMn77nAexjy/+ztdtgTB/H/8=";
529 
530   std::string actual_signature_base64;
531   base::Base64Encode(unsent_log_store.staged_log_signature(),
532                      &actual_signature_base64);
533   EXPECT_EQ(expected_signature_base64, actual_signature_base64);
534 
535   // Test a different key results in a different signature.
536   std::string key = "secret key, don't tell anyone";
537   TestUnsentLogStore unsent_log_store_different_key(&prefs_, kLogByteLimit,
538                                                     key);
539 
540   unsent_log_store_different_key.StoreLog(
541       kFooText, log_metadata, MetricsLogsEventManager::CreateReason::kUnknown);
542   unsent_log_store_different_key.StageNextLog();
543 
544   EXPECT_EQ(Compress(kFooText), unsent_log_store_different_key.staged_log());
545 
546   // Base 64 encoded signature obtained in similar fashion to previous
547   // signature. To use previous python code change:
548   // key = "secret key, don't tell anyone"
549   expected_signature_base64 = "DV7z8wdDrjLkQrCzrXR3UjWsR3/YVM97tIhMnhUvfXM=";
550   base::Base64Encode(unsent_log_store_different_key.staged_log_signature(),
551                      &actual_signature_base64);
552 
553   EXPECT_EQ(expected_signature_base64, actual_signature_base64);
554 }
555 
TEST_F(UnsentLogStoreTest,StoreLogWithUserId)556 TEST_F(UnsentLogStoreTest, StoreLogWithUserId) {
557   const char foo_text[] = "foo";
558   const uint64_t user_id = 12345L;
559 
560   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
561   LogMetadata log_metadata(absl::nullopt, user_id, absl::nullopt);
562   unsent_log_store.StoreLog(foo_text, log_metadata,
563                             MetricsLogsEventManager::CreateReason::kUnknown);
564   unsent_log_store.StageNextLog();
565 
566   EXPECT_EQ(Compress(foo_text), unsent_log_store.staged_log());
567   EXPECT_EQ(unsent_log_store.staged_log_user_id().value(), user_id);
568 
569   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
570 
571   // Reads persisted logs from new log store.
572   TestUnsentLogStore read_unsent_log_store(&prefs_, kLogByteLimit);
573   read_unsent_log_store.LoadPersistedUnsentLogs();
574   EXPECT_EQ(1U, read_unsent_log_store.size());
575 
576   // Ensure that the user_id was parsed correctly.
577   read_unsent_log_store.StageNextLog();
578   EXPECT_EQ(user_id, read_unsent_log_store.staged_log_user_id().value());
579 }
580 
TEST_F(UnsentLogStoreTest,StoreLogWithLargeUserId)581 TEST_F(UnsentLogStoreTest, StoreLogWithLargeUserId) {
582   const char foo_text[] = "foo";
583   const uint64_t large_user_id = std::numeric_limits<uint64_t>::max();
584 
585   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
586   LogMetadata log_metadata(absl::nullopt, large_user_id, absl::nullopt);
587   unsent_log_store.StoreLog(foo_text, log_metadata,
588                             MetricsLogsEventManager::CreateReason::kUnknown);
589   unsent_log_store.StageNextLog();
590 
591   EXPECT_EQ(Compress(foo_text), unsent_log_store.staged_log());
592   EXPECT_EQ(unsent_log_store.staged_log_user_id().value(), large_user_id);
593 
594   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
595 
596   // Reads persisted logs from new log store.
597   TestUnsentLogStore read_unsent_log_store(&prefs_, kLogByteLimit);
598   read_unsent_log_store.LoadPersistedUnsentLogs();
599   EXPECT_EQ(1U, read_unsent_log_store.size());
600 
601   // Ensure that the user_id was parsed correctly.
602   read_unsent_log_store.StageNextLog();
603   EXPECT_EQ(large_user_id, read_unsent_log_store.staged_log_user_id().value());
604 }
605 
TEST_F(UnsentLogStoreTest,StoreLogWithOnlyAppKMLogSource)606 TEST_F(UnsentLogStoreTest, StoreLogWithOnlyAppKMLogSource) {
607   const char foo_text[] = "foo";
608   const UkmLogSourceType log_source_type = UkmLogSourceType::APPKM_ONLY;
609 
610   TestUnsentLogStore unsent_log_store(&prefs_, kLogByteLimit);
611   LogMetadata log_metadata(absl::nullopt, absl::nullopt, log_source_type);
612   unsent_log_store.StoreLog(foo_text, log_metadata,
613                             MetricsLogsEventManager::CreateReason::kUnknown);
614   unsent_log_store.StageNextLog();
615 
616   EXPECT_EQ(Compress(foo_text), unsent_log_store.staged_log());
617   EXPECT_EQ(unsent_log_store.staged_log_metadata().log_source_type.value(),
618             log_source_type);
619 
620   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
621 
622   // Reads persisted logs from new log store.
623   TestUnsentLogStore read_unsent_log_store(&prefs_, kLogByteLimit);
624   read_unsent_log_store.LoadPersistedUnsentLogs();
625   EXPECT_EQ(1U, read_unsent_log_store.size());
626 
627   // Ensure that the log source type was updated correctly in log metadata.
628   read_unsent_log_store.StageNextLog();
629   EXPECT_EQ(
630       log_source_type,
631       read_unsent_log_store.staged_log_metadata().log_source_type.value());
632 }
633 
TEST_F(UnsentLogStoreTest,UnsentLogMetadataMetrics)634 TEST_F(UnsentLogStoreTest, UnsentLogMetadataMetrics) {
635   std::unique_ptr<TestUnsentLogStoreMetrics> metrics =
636       std::make_unique<TestUnsentLogStoreMetrics>();
637   TestUnsentLogStoreMetrics* m = metrics.get();
638   TestUnsentLogStore unsent_log_store(std::move(metrics), &prefs_,
639                                       kLogByteLimit * 10);
640 
641   // Prepare 4 logs.
642   const char kFooText[] = "foo";
643   const base::HistogramBase::Count kFooSampleCount = 3;
644 
645   // The |foobar_log| whose compressed size is over 1kb will be staged first, so
646   // the persisted_size_in_kb shall be reduced by 1kb afterwards.
647   std::string foobar_log = GenerateLogWithMinCompressedSize(1024);
648   const base::HistogramBase::Count kFooBarSampleCount = 5;
649 
650   // The |oversize_log| shall not be persisted.
651   std::string oversize_log =
652       GenerateLogWithMinCompressedSize(kLogByteLimit * 10 + 1);
653   const base::HistogramBase::Count kOversizeLogSampleCount = 50;
654 
655   // The log without the SampleCount will not be counted to metrics.
656   const char kNoSampleLog[] = "no sample log";
657 
658   LogMetadata log_metadata_with_oversize_sample(kOversizeLogSampleCount,
659                                                 absl::nullopt, absl::nullopt);
660   unsent_log_store.StoreLog(oversize_log, log_metadata_with_oversize_sample,
661                             MetricsLogsEventManager::CreateReason::kUnknown);
662 
663   LogMetadata log_metadata_with_no_sample;
664   unsent_log_store.StoreLog(kNoSampleLog, log_metadata_with_no_sample,
665                             MetricsLogsEventManager::CreateReason::kUnknown);
666 
667   LogMetadata log_metadata_foo_sample(kFooSampleCount, absl::nullopt,
668                                       absl::nullopt);
669   unsent_log_store.StoreLog(kFooText, log_metadata_foo_sample,
670                             MetricsLogsEventManager::CreateReason::kUnknown);
671 
672   // The foobar_log will be staged first.
673   LogMetadata log_metadata_foo_bar_sample(kFooBarSampleCount, absl::nullopt,
674                                           absl::nullopt);
675   unsent_log_store.StoreLog(foobar_log, log_metadata_foo_bar_sample,
676                             MetricsLogsEventManager::CreateReason::kUnknown);
677 
678   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
679 
680   unsent_log_store.RecordMetaDataMetrics();
681   // The |oversize_log| was ignored, the kNoSampleLog won't be counted to
682   // metrics,
683   EXPECT_EQ(kFooSampleCount + kFooBarSampleCount, m->unsent_samples_count());
684   EXPECT_EQ(0, m->sent_samples_count());
685   EXPECT_EQ(2, m->persisted_size_in_kb());
686 
687   // Pretend to send log.
688   unsent_log_store.StageNextLog();
689   unsent_log_store.MarkStagedLogAsSent();
690   unsent_log_store.DiscardStagedLog();
691   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
692   unsent_log_store.RecordMetaDataMetrics();
693 
694   // The |foobar_log| shall be sent.
695   EXPECT_EQ(kFooSampleCount, m->unsent_samples_count());
696   EXPECT_EQ(kFooBarSampleCount, m->sent_samples_count());
697   EXPECT_EQ(1, m->persisted_size_in_kb());
698 
699   // Pretend |kFooText| upload failure.
700   unsent_log_store.StageNextLog();
701   unsent_log_store.DiscardStagedLog();
702   unsent_log_store.TrimAndPersistUnsentLogs(/*overwrite_in_memory_store=*/true);
703   unsent_log_store.RecordMetaDataMetrics();
704 
705   // Verify the failed upload wasn't added to the sent samples count.
706   EXPECT_EQ(0, m->unsent_samples_count());
707   EXPECT_EQ(kFooBarSampleCount, m->sent_samples_count());
708   EXPECT_EQ(1, m->persisted_size_in_kb());
709 }
710 
711 }  // namespace metrics
712