unsent_log_store_unittest.cc 25 KB

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