1 // Copyright 2019 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 
5 #include "components/optimization_guide/store_update_data.h"
6 
7 #include <string>
8 #include <vector>
9 
10 #include "base/macros.h"
11 #include "base/time/time.h"
12 #include "base/version.h"
13 #include "components/optimization_guide/optimization_guide_features.h"
14 #include "components/optimization_guide/proto/hint_cache.pb.h"
15 #include "components/optimization_guide/proto/hints.pb.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 
18 namespace optimization_guide {
19 
20 namespace {
21 
TEST(StoreUpdateDataTest,BuildComponentStoreUpdateData)22 TEST(StoreUpdateDataTest, BuildComponentStoreUpdateData) {
23   // Verify creating a Component Hint update package.
24   base::Version v1("1.2.3.4");
25   proto::Hint hint1;
26   hint1.set_key("foo.org");
27   hint1.set_key_representation(proto::HOST);
28   proto::PageHint* page_hint1 = hint1.add_page_hints();
29   page_hint1->set_page_pattern("slowpage");
30   proto::Hint hint2;
31   hint2.set_key("bar.com");
32   hint2.set_key_representation(proto::HOST);
33   proto::PageHint* page_hint2 = hint2.add_page_hints();
34   page_hint2->set_page_pattern("slowpagealso");
35 
36   std::unique_ptr<StoreUpdateData> component_update =
37       StoreUpdateData::CreateComponentStoreUpdateData(v1);
38   component_update->MoveHintIntoUpdateData(std::move(hint1));
39   component_update->MoveHintIntoUpdateData(std::move(hint2));
40   EXPECT_TRUE(component_update->component_version().has_value());
41   EXPECT_FALSE(component_update->update_time().has_value());
42   EXPECT_EQ(v1, *component_update->component_version());
43   // Verify there are 3 store entries: 1 for the metadata entry plus
44   // the 2 added hint entries.
45   EXPECT_EQ(3ul, component_update->TakeUpdateEntries()->size());
46 }
47 
TEST(StoreUpdateDataTest,BuildFetchUpdateDataUsesDefaultCacheDuration)48 TEST(StoreUpdateDataTest, BuildFetchUpdateDataUsesDefaultCacheDuration) {
49   // Verify creating a Fetched Hint update package.
50   base::Time update_time = base::Time::Now();
51   proto::Hint hint1;
52   hint1.set_key("foo.org");
53   hint1.set_key_representation(proto::HOST);
54   proto::PageHint* page_hint1 = hint1.add_page_hints();
55   page_hint1->set_page_pattern("slowpage");
56 
57   std::unique_ptr<StoreUpdateData> fetch_update =
58       StoreUpdateData::CreateFetchedStoreUpdateData(update_time);
59   fetch_update->MoveHintIntoUpdateData(std::move(hint1));
60   EXPECT_FALSE(fetch_update->component_version().has_value());
61   EXPECT_TRUE(fetch_update->update_time().has_value());
62   EXPECT_EQ(update_time, *fetch_update->update_time());
63   // Verify there are 2 store entries: 1 for the metadata entry plus
64   // the 1 added hint entries.
65   const auto update_entries = fetch_update->TakeUpdateEntries();
66   EXPECT_EQ(2ul, update_entries->size());
67   // Verify expiry time taken from hint rather than the default expiry time of
68   // the store update data.
69   for (const auto& entry : *update_entries) {
70     proto::StoreEntry store_entry = entry.second;
71     if (store_entry.entry_type() == proto::FETCHED_HINT) {
72       base::Time expected_expiry_time =
73           base::Time::Now() + features::StoredFetchedHintsFreshnessDuration();
74       EXPECT_EQ(expected_expiry_time.ToDeltaSinceWindowsEpoch().InSeconds(),
75                 store_entry.expiry_time_secs());
76       break;
77     }
78   }
79 }
80 
TEST(StoreUpdateDataTest,BuildFetchUpdateDataUsesCacheDurationFromHintIfAvailable)81 TEST(StoreUpdateDataTest,
82      BuildFetchUpdateDataUsesCacheDurationFromHintIfAvailable) {
83   // Verify creating a Fetched Hint update package.
84   int max_cache_duration_secs = 60;
85   base::Time update_time = base::Time::Now();
86   proto::Hint hint1;
87   hint1.set_key("foo.org");
88   hint1.set_key_representation(proto::HOST);
89   hint1.mutable_max_cache_duration()->set_seconds(max_cache_duration_secs);
90   proto::PageHint* page_hint1 = hint1.add_page_hints();
91   page_hint1->set_page_pattern("slowpage");
92 
93   std::unique_ptr<StoreUpdateData> fetch_update =
94       StoreUpdateData::CreateFetchedStoreUpdateData(update_time);
95   fetch_update->MoveHintIntoUpdateData(std::move(hint1));
96   EXPECT_FALSE(fetch_update->component_version().has_value());
97   EXPECT_TRUE(fetch_update->update_time().has_value());
98   EXPECT_EQ(update_time, *fetch_update->update_time());
99   // Verify there are 2 store entries: 1 for the metadata entry plus
100   // the 1 added hint entries.
101   const auto update_entries = fetch_update->TakeUpdateEntries();
102   EXPECT_EQ(2ul, update_entries->size());
103   // Verify expiry time taken from hint rather than the default expiry time of
104   // the store update data.
105   for (const auto& entry : *update_entries) {
106     proto::StoreEntry store_entry = entry.second;
107     if (store_entry.entry_type() == proto::FETCHED_HINT) {
108       base::Time expected_expiry_time =
109           base::Time::Now() +
110           base::TimeDelta::FromSeconds(max_cache_duration_secs);
111       EXPECT_EQ(expected_expiry_time.ToDeltaSinceWindowsEpoch().InSeconds(),
112                 store_entry.expiry_time_secs());
113       break;
114     }
115   }
116 }
117 
TEST(StoreUpdateDataTest,BuildPredictionModelUpdateData)118 TEST(StoreUpdateDataTest, BuildPredictionModelUpdateData) {
119   // Verify creating a Prediction Model update data.
120   proto::PredictionModel prediction_model;
121 
122   proto::ModelInfo* model_info = prediction_model.mutable_model_info();
123   model_info->set_version(1);
124   model_info->add_supported_model_features(
125       proto::CLIENT_MODEL_FEATURE_EFFECTIVE_CONNECTION_TYPE);
126   model_info->set_optimization_target(
127       proto::OPTIMIZATION_TARGET_PAINFUL_PAGE_LOAD);
128   model_info->add_supported_model_types(
129       proto::ModelType::MODEL_TYPE_DECISION_TREE);
130 
131   std::unique_ptr<StoreUpdateData> prediction_model_update =
132       StoreUpdateData::CreatePredictionModelStoreUpdateData();
133   prediction_model_update->CopyPredictionModelIntoUpdateData(prediction_model);
134   EXPECT_FALSE(prediction_model_update->component_version().has_value());
135   EXPECT_FALSE(prediction_model_update->update_time().has_value());
136   // Verify there is 1 store entry.
137   EXPECT_EQ(1ul, prediction_model_update->TakeUpdateEntries()->size());
138 }
139 
TEST(StoreUpdateDataTest,BuildHostModelFeaturesUpdateData)140 TEST(StoreUpdateDataTest, BuildHostModelFeaturesUpdateData) {
141   // Verify creating a Prediction Model update data.
142   base::Time host_model_features_update_time = base::Time::Now();
143 
144   proto::HostModelFeatures host_model_features;
145   host_model_features.set_host("foo.com");
146   proto::ModelFeature* model_feature = host_model_features.add_model_features();
147   model_feature->set_feature_name("host_feat1");
148   model_feature->set_double_value(2.0);
149 
150   std::unique_ptr<StoreUpdateData> host_model_features_update =
151       StoreUpdateData::CreateHostModelFeaturesStoreUpdateData(
152           host_model_features_update_time,
153           host_model_features_update_time +
154               optimization_guide::features::
155                   StoredHostModelFeaturesFreshnessDuration());
156   host_model_features_update->CopyHostModelFeaturesIntoUpdateData(
157       std::move(host_model_features));
158   EXPECT_FALSE(host_model_features_update->component_version().has_value());
159   EXPECT_TRUE(host_model_features_update->update_time().has_value());
160   EXPECT_EQ(host_model_features_update_time,
161             *host_model_features_update->update_time());
162   // Verify there are 2 store entries, 1 for the metadata entry and 1 for the
163   // added host model features entry.
164   EXPECT_EQ(2ul, host_model_features_update->TakeUpdateEntries()->size());
165 }
166 
167 }  // namespace
168 
169 }  // namespace optimization_guide
170