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