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 <map>
6 #include <memory>
7 #include <string>
8 #include <vector>
9
10 #include "chrome/browser/chromeos/power/auto_screen_brightness/model_config_loader_impl.h"
11
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/files/scoped_temp_dir.h"
15 #include "base/task/thread_pool/thread_pool_instance.h"
16 #include "base/test/scoped_feature_list.h"
17 #include "base/test/task_environment.h"
18 #include "base/test/test_mock_time_task_runner.h"
19 #include "base/threading/sequenced_task_runner_handle.h"
20 #include "chromeos/constants/chromeos_features.h"
21 #include "content/public/test/browser_task_environment.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 namespace chromeos {
25 namespace power {
26 namespace auto_screen_brightness {
27
28 namespace {
29
30 class TestObserver : public ModelConfigLoader::Observer {
31 public:
TestObserver()32 TestObserver() {}
33 ~TestObserver() override = default;
34
35 // ModelConfigLoader::Observer overrides:
OnModelConfigLoaded(base::Optional<ModelConfig> model_config)36 void OnModelConfigLoaded(base::Optional<ModelConfig> model_config) override {
37 model_config_loader_initialized_ = true;
38 model_config_ = model_config;
39 }
40
model_config_loader_initialized() const41 bool model_config_loader_initialized() const {
42 return model_config_loader_initialized_;
43 }
model_config()44 base::Optional<ModelConfig> model_config() { return model_config_; }
45
46 private:
47 bool model_config_loader_initialized_ = false;
48 base::Optional<ModelConfig> model_config_;
49
50 DISALLOW_COPY_AND_ASSIGN(TestObserver);
51 };
52
53 } // namespace
54
55 class ModelConfigLoaderImplTest : public testing::Test {
56 public:
ModelConfigLoaderImplTest()57 ModelConfigLoaderImplTest()
58 : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
59 CHECK(temp_dir_.CreateUniqueTempDir());
60 temp_params_path_ = temp_dir_.GetPath().Append("model_params.json");
61 }
62
~ModelConfigLoaderImplTest()63 ~ModelConfigLoaderImplTest() override {
64 base::ThreadPoolInstance::Get()->FlushForTesting();
65 }
66
Init(const std::string & model_params,const std::map<std::string,std::string> & experiment_params={})67 void Init(const std::string& model_params,
68 const std::map<std::string, std::string>& experiment_params = {}) {
69 base::test::ScopedFeatureList scoped_feature_list;
70 if (!experiment_params.empty()) {
71 scoped_feature_list.InitAndEnableFeatureWithParameters(
72 features::kAutoScreenBrightness, experiment_params);
73 }
74
75 WriteParamsToFile(model_params);
76 model_config_loader_ = ModelConfigLoaderImpl::CreateForTesting(
77 temp_params_path_, base::SequencedTaskRunnerHandle::Get());
78
79 test_observer_ = std::make_unique<TestObserver>();
80 model_config_loader_->AddObserver(test_observer_.get());
81 task_environment_.RunUntilIdle();
82 }
83
84 protected:
WriteParamsToFile(const std::string & params)85 void WriteParamsToFile(const std::string& params) {
86 if (params.empty())
87 return;
88
89 CHECK(!temp_params_path_.empty());
90
91 const int bytes_written =
92 base::WriteFile(temp_params_path_, params.data(), params.size());
93 ASSERT_EQ(bytes_written, static_cast<int>(params.size()))
94 << "Wrote " << bytes_written << " byte(s) instead of " << params.size()
95 << " to " << temp_params_path_;
96 }
97
98 content::BrowserTaskEnvironment task_environment_;
99
100 base::ScopedTempDir temp_dir_;
101 base::FilePath temp_params_path_;
102
103 std::unique_ptr<ModelConfigLoaderImpl> model_config_loader_;
104 std::unique_ptr<TestObserver> test_observer_;
105
106 private:
107 DISALLOW_COPY_AND_ASSIGN(ModelConfigLoaderImplTest);
108 };
109
TEST_F(ModelConfigLoaderImplTest,ValidModelParamsLoaded)110 TEST_F(ModelConfigLoaderImplTest, ValidModelParamsLoaded) {
111 const std::string model_params = R"(
112 {
113 "auto_brightness_als_horizon_seconds": 2,
114 "enabled": true,
115 "global_curve": {
116 "log_lux": [
117 1.0,
118 2.0,
119 3.0
120 ],
121 "brightness": [
122 10.0,
123 20.0,
124 30.0
125 ]
126 },
127 "metrics_key": "abc",
128 "model_als_horizon_seconds": 5
129 }
130 )";
131
132 Init(model_params);
133 EXPECT_TRUE(test_observer_->model_config_loader_initialized());
134
135 std::vector<double> expected_log_lux = {1.0, 2.0, 3.0};
136 std::vector<double> expected_brightness = {10.0, 20.0, 30.0};
137
138 ModelConfig expected_model_config;
139 expected_model_config.auto_brightness_als_horizon_seconds = 2.0;
140 expected_model_config.enabled = true;
141 expected_model_config.log_lux = expected_log_lux;
142 expected_model_config.brightness = expected_brightness;
143 expected_model_config.metrics_key = "abc";
144 expected_model_config.model_als_horizon_seconds = 5;
145 EXPECT_TRUE(test_observer_->model_config());
146 EXPECT_EQ(*test_observer_->model_config(), expected_model_config);
147 }
148
TEST_F(ModelConfigLoaderImplTest,MissingEnabledMeansFalse)149 TEST_F(ModelConfigLoaderImplTest, MissingEnabledMeansFalse) {
150 const std::string model_params = R"(
151 {
152 "auto_brightness_als_horizon_seconds": 2,
153 "global_curve": {
154 "log_lux": [
155 1.0,
156 2.0,
157 3.0
158 ],
159 "brightness": [
160 10.0,
161 20.0,
162 30.0
163 ]
164 },
165 "metrics_key": "abc",
166 "model_als_horizon_seconds": 5
167 }
168 )";
169
170 Init(model_params);
171 EXPECT_TRUE(test_observer_->model_config_loader_initialized());
172
173 std::vector<double> expected_log_lux = {1.0, 2.0, 3.0};
174 std::vector<double> expected_brightness = {10.0, 20.0, 30.0};
175
176 ModelConfig expected_model_config;
177 expected_model_config.auto_brightness_als_horizon_seconds = 2.0;
178 expected_model_config.enabled = false;
179 expected_model_config.log_lux = expected_log_lux;
180 expected_model_config.brightness = expected_brightness;
181 expected_model_config.metrics_key = "abc";
182 expected_model_config.model_als_horizon_seconds = 5;
183 EXPECT_TRUE(test_observer_->model_config());
184 EXPECT_EQ(*test_observer_->model_config(), expected_model_config);
185 }
186
TEST_F(ModelConfigLoaderImplTest,ValidModelParamsLoadedThenOverriden)187 TEST_F(ModelConfigLoaderImplTest, ValidModelParamsLoadedThenOverriden) {
188 const std::string model_params = R"(
189 {
190 "auto_brightness_als_horizon_seconds": 2,
191 "enabled": true,
192 "global_curve": {
193 "log_lux": [
194 1.0,
195 2.0,
196 3.0
197 ],
198 "brightness": [
199 10.0,
200 20.0,
201 30.0
202 ]
203 },
204 "metrics_key": "abc",
205 "model_als_horizon_seconds": 5
206 }
207 )";
208
209 const std::string global_curve_spec("2:20,4:40,6:60");
210
211 const std::map<std::string, std::string> experiment_params = {
212 {"auto_brightness_als_horizon_seconds", "10"},
213 {"enabled", "false"},
214 {"model_als_horizon_seconds", "20"},
215 {"global_curve", global_curve_spec},
216 };
217
218 Init(model_params, experiment_params);
219 EXPECT_TRUE(test_observer_->model_config_loader_initialized());
220
221 std::vector<double> expected_log_lux = {2.0, 4.0, 6.0};
222 std::vector<double> expected_brightness = {20.0, 40.0, 60.0};
223
224 ModelConfig expected_model_config;
225 expected_model_config.auto_brightness_als_horizon_seconds = 10.0;
226 expected_model_config.enabled = false;
227 expected_model_config.log_lux = expected_log_lux;
228 expected_model_config.brightness = expected_brightness;
229 expected_model_config.metrics_key = "abc";
230 expected_model_config.model_als_horizon_seconds = 20.0;
231 EXPECT_TRUE(test_observer_->model_config());
232 EXPECT_EQ(*test_observer_->model_config(), expected_model_config);
233 }
234
TEST_F(ModelConfigLoaderImplTest,InvalidModelParamsLoaded)235 TEST_F(ModelConfigLoaderImplTest, InvalidModelParamsLoaded) {
236 // "auto_brightness_als_horizon_seconds" is missing.
237 const std::string model_params = R"(
238 {
239 "global_curve": {
240 "log_lux": [
241 1.0,
242 2.0,
243 3.0
244 ],
245 "brightness": [
246 10.0,
247 20.0,
248 30.0
249 ]
250 },
251 "metrics_key": "abc",
252 "model_als_horizon_seconds": 5
253 }
254 )";
255
256 Init(model_params);
257 EXPECT_TRUE(test_observer_->model_config_loader_initialized());
258 EXPECT_FALSE(test_observer_->model_config());
259 }
260
TEST_F(ModelConfigLoaderImplTest,InvalidModelParamsLoadedThenOverriden)261 TEST_F(ModelConfigLoaderImplTest, InvalidModelParamsLoadedThenOverriden) {
262 // Same as InvalidModelParamsLoaded, but missing
263 // "auto_brightness_als_horizon_seconds" is specified in the experiment flags.
264 const std::string model_params = R"(
265 {
266 "global_curve": {
267 "log_lux": [
268 1.0,
269 2.0,
270 3.0
271 ],
272 "brightness": [
273 10.0,
274 20.0,
275 30.0
276 ]
277 },
278 "metrics_key": "abc",
279 "model_als_horizon_seconds": 5
280 }
281 )";
282
283 const std::map<std::string, std::string> experiment_params = {
284 {"auto_brightness_als_horizon_seconds", "10"},
285 {"model_als_horizon_seconds", "20"},
286 };
287
288 Init(model_params, experiment_params);
289 EXPECT_TRUE(test_observer_->model_config_loader_initialized());
290
291 std::vector<double> expected_log_lux = {1.0, 2.0, 3.0};
292 std::vector<double> expected_brightness = {10.0, 20.0, 30.0};
293
294 ModelConfig expected_model_config;
295 expected_model_config.auto_brightness_als_horizon_seconds = 10.0;
296 expected_model_config.enabled = false;
297 expected_model_config.log_lux = expected_log_lux;
298 expected_model_config.brightness = expected_brightness;
299 expected_model_config.metrics_key = "abc";
300 expected_model_config.model_als_horizon_seconds = 20.0;
301 EXPECT_TRUE(test_observer_->model_config());
302 EXPECT_EQ(*test_observer_->model_config(), expected_model_config);
303 }
304
TEST_F(ModelConfigLoaderImplTest,MissingModelParams)305 TEST_F(ModelConfigLoaderImplTest, MissingModelParams) {
306 // Model params not found from disk and experiment flags do not contain
307 // all fields we need.
308 const std::map<std::string, std::string> experiment_params = {
309 {"auto_brightness_als_horizon_seconds", "10"},
310 {"model_als_horizon_seconds", "20"},
311 };
312
313 Init("" /* model_params */, experiment_params);
314 EXPECT_TRUE(test_observer_->model_config_loader_initialized());
315 EXPECT_FALSE(test_observer_->model_config());
316 }
317
TEST_F(ModelConfigLoaderImplTest,InvalidJsonFormat)318 TEST_F(ModelConfigLoaderImplTest, InvalidJsonFormat) {
319 const std::string model_params = R"(
320 {
321 "global_curve": {
322 "log_lux": [
323 1.0,
324 2.0,
325 3.0
326 ],
327 "brightness": [
328 10.0,
329 20.0,
330 30.0
331 ]
332 },
333 "metrics_key": 10,
334 "model_als_horizon_seconds": 5
335 }
336 )";
337
338 const std::map<std::string, std::string> experiment_params = {
339 {"auto_brightness_als_horizon_seconds", "10"},
340 {"model_als_horizon_seconds", "20"},
341 };
342
343 Init(model_params, experiment_params);
344 EXPECT_TRUE(test_observer_->model_config_loader_initialized());
345 EXPECT_FALSE(test_observer_->model_config());
346 }
347
348 } // namespace auto_screen_brightness
349 } // namespace power
350 } // namespace chromeos
351