blob: b47040b6c1785a1dd17b02f9c092571f25c99fa9 [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
2// Copyright (C) 2011 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
adlr@google.com3defe6a2009-12-04 20:57:17 +000016
Alex Deymoaab50e32014-11-10 19:55:35 -080017#include "update_engine/omaha_response_handler_action.h"
18
Aaron Woodc73fdc12017-12-06 11:09:15 -080019#include <memory>
adlr@google.com3defe6a2009-12-04 20:57:17 +000020#include <string>
Amin Hassanid3f4bea2018-04-30 14:52:40 -070021#include <utility>
Darin Petkov73058b42010-10-06 16:32:19 -070022
Alex Deymo110e0302015-10-19 20:35:21 -070023#include <base/files/file_util.h>
Sen Jiang297e5832016-03-17 14:45:51 -070024#include <base/files/scoped_temp_dir.h>
Aaron Wood23bd3392017-10-06 14:48:25 -070025#include <brillo/message_loops/fake_message_loop.h>
adlr@google.com3defe6a2009-12-04 20:57:17 +000026#include <gtest/gtest.h>
Darin Petkov73058b42010-10-06 16:32:19 -070027
Alex Deymo39910dc2015-11-09 17:04:30 -080028#include "update_engine/common/constants.h"
29#include "update_engine/common/platform_constants.h"
30#include "update_engine/common/test_utils.h"
31#include "update_engine/common/utils.h"
Gilad Arnold5bb4c902014-04-10 12:32:13 -070032#include "update_engine/fake_system_state.h"
Gilad Arnold74b5f552014-10-07 08:17:16 -070033#include "update_engine/mock_payload_state.h"
Alex Deymo39910dc2015-11-09 17:04:30 -080034#include "update_engine/payload_consumer/payload_constants.h"
Aaron Wood23bd3392017-10-06 14:48:25 -070035#include "update_engine/update_manager/mock_policy.h"
adlr@google.com3defe6a2009-12-04 20:57:17 +000036
Alex Deymo10875d92014-11-10 21:52:57 -080037using chromeos_update_engine::test_utils::System;
38using chromeos_update_engine::test_utils::WriteFileString;
Aaron Wood23bd3392017-10-06 14:48:25 -070039using chromeos_update_manager::EvalStatus;
40using chromeos_update_manager::FakeUpdateManager;
41using chromeos_update_manager::MockPolicy;
adlr@google.com3defe6a2009-12-04 20:57:17 +000042using std::string;
Aaron Woodc73fdc12017-12-06 11:09:15 -080043using testing::_;
Aaron Wood23bd3392017-10-06 14:48:25 -070044using testing::DoAll;
Darin Petkov73058b42010-10-06 16:32:19 -070045using testing::Return;
Aaron Wood23bd3392017-10-06 14:48:25 -070046using testing::SetArgPointee;
adlr@google.com3defe6a2009-12-04 20:57:17 +000047
48namespace chromeos_update_engine {
49
adlr@google.com3defe6a2009-12-04 20:57:17 +000050class OmahaResponseHandlerActionProcessorDelegate
51 : public ActionProcessorDelegate {
52 public:
53 OmahaResponseHandlerActionProcessorDelegate()
Aaron Woodc73fdc12017-12-06 11:09:15 -080054 : code_(ErrorCode::kError), code_set_(false) {}
adlr@google.com3defe6a2009-12-04 20:57:17 +000055 void ActionCompleted(ActionProcessor* processor,
56 AbstractAction* action,
David Zeuthena99981f2013-04-29 13:42:47 -070057 ErrorCode code) {
adlr@google.com3defe6a2009-12-04 20:57:17 +000058 if (action->Type() == OmahaResponseHandlerAction::StaticType()) {
Amin Hassanid3f4bea2018-04-30 14:52:40 -070059 auto response_handler_action =
60 static_cast<OmahaResponseHandlerAction*>(action);
Darin Petkovc1a8b422010-07-19 11:34:49 -070061 code_ = code;
62 code_set_ = true;
Amin Hassanid3f4bea2018-04-30 14:52:40 -070063 response_handler_action_install_plan_.reset(
64 new InstallPlan(response_handler_action->install_plan_));
65 } else if (action->Type() ==
66 ObjectCollectorAction<InstallPlan>::StaticType()) {
67 auto collector_action =
68 static_cast<ObjectCollectorAction<InstallPlan>*>(action);
69 collector_action_install_plan_.reset(
70 new InstallPlan(collector_action->object()));
adlr@google.com3defe6a2009-12-04 20:57:17 +000071 }
72 }
David Zeuthena99981f2013-04-29 13:42:47 -070073 ErrorCode code_;
Darin Petkovc1a8b422010-07-19 11:34:49 -070074 bool code_set_;
Amin Hassanid3f4bea2018-04-30 14:52:40 -070075 std::unique_ptr<InstallPlan> collector_action_install_plan_;
76 std::unique_ptr<InstallPlan> response_handler_action_install_plan_;
77};
78
adlr@google.com3defe6a2009-12-04 20:57:17 +000079class OmahaResponseHandlerActionTest : public ::testing::Test {
80 protected:
81 void SetUp() override {
82 FakeBootControl* fake_boot_control = fake_system_state_.fake_boot_control();
Amin Hassani7cc8bb02019-01-14 16:29:47 -080083 fake_boot_control->SetPartitionDevice(kPartitionNameKernel, 0, "/dev/sdz2");
84 fake_boot_control->SetPartitionDevice(kPartitionNameRoot, 0, "/dev/sdz3");
85 fake_boot_control->SetPartitionDevice(kPartitionNameKernel, 1, "/dev/sdz4");
86 fake_boot_control->SetPartitionDevice(kPartitionNameRoot, 1, "/dev/sdz5");
adlr@google.com3defe6a2009-12-04 20:57:17 +000087 }
88
89 // Return true iff the OmahaResponseHandlerAction succeeded.
90 // If out is non-null, it's set w/ the response from the action.
91 bool DoTest(const OmahaResponse& in,
92 const string& deadline_file,
93 InstallPlan* out);
94
Amin Hassanid3f4bea2018-04-30 14:52:40 -070095 // Delegate passed to the ActionProcessor.
96 OmahaResponseHandlerActionProcessorDelegate delegate_;
97
adlr@google.com3defe6a2009-12-04 20:57:17 +000098 // Captures the action's result code, for tests that need to directly verify
99 // it in non-success cases.
100 ErrorCode action_result_code_;
101
102 FakeSystemState fake_system_state_;
103 // "Hash+"
104 const brillo::Blob expected_hash_ = {0x48, 0x61, 0x73, 0x68, 0x2b};
adlr@google.com3defe6a2009-12-04 20:57:17 +0000105};
106
107namespace {
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700108const char* const kLongName =
adlr@google.com3defe6a2009-12-04 20:57:17 +0000109 "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
110 "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
111 "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
112 "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
113 "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
114 "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
115 "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
116 "-the_update_a.b.c.d_DELTA_.tgz";
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700117const char* const kBadVersion = "don't update me";
Sen Jiang2703ef42017-03-16 13:36:21 -0700118const char* const kPayloadHashHex = "486173682b";
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700119} // namespace
adlr@google.com3defe6a2009-12-04 20:57:17 +0000120
Aaron Woodc73fdc12017-12-06 11:09:15 -0800121bool OmahaResponseHandlerActionTest::DoTest(const OmahaResponse& in,
122 const string& test_deadline_file,
123 InstallPlan* out) {
Aaron Wood23bd3392017-10-06 14:48:25 -0700124 brillo::FakeMessageLoop loop(nullptr);
125 loop.SetAsCurrent();
adlr@google.com3defe6a2009-12-04 20:57:17 +0000126 ActionProcessor processor;
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700127 processor.set_delegate(&delegate_);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000128
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700129 auto feeder_action = std::make_unique<ObjectFeederAction<OmahaResponse>>();
130 feeder_action->set_obj(in);
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700131 if (in.update_exists && in.version != kBadVersion) {
Sen Jiang0affc2c2017-02-10 15:55:05 -0800132 string expected_hash;
133 for (const auto& package : in.packages)
134 expected_hash += package.hash + ":";
Alex Deymo763e7db2015-08-27 21:08:08 -0700135 EXPECT_CALL(*(fake_system_state_.mock_prefs()),
Sen Jiang0affc2c2017-02-10 15:55:05 -0800136 SetString(kPrefsUpdateCheckResponseHash, expected_hash))
Darin Petkov73058b42010-10-06 16:32:19 -0700137 .WillOnce(Return(true));
Alex Deymo85616652015-10-15 18:48:31 -0700138
Xiaochu Liu88d90382018-08-29 16:09:11 -0700139 int slot =
140 fake_system_state_.request_params()->is_install()
141 ? fake_system_state_.fake_boot_control()->GetCurrentSlot()
142 : 1 - fake_system_state_.fake_boot_control()->GetCurrentSlot();
Alex Deymo85616652015-10-15 18:48:31 -0700143 string key = kPrefsChannelOnSlotPrefix + std::to_string(slot);
144 EXPECT_CALL(*(fake_system_state_.mock_prefs()), SetString(key, testing::_))
145 .WillOnce(Return(true));
Darin Petkov73058b42010-10-06 16:32:19 -0700146 }
Jay Srinivasan53173b92013-05-17 17:13:01 -0700147
Sen Jiang0affc2c2017-02-10 15:55:05 -0800148 string current_url = in.packages.size() ? in.packages[0].payload_urls[0] : "";
Alex Deymo763e7db2015-08-27 21:08:08 -0700149 EXPECT_CALL(*(fake_system_state_.mock_payload_state()), GetCurrentUrl())
Jay Srinivasan53173b92013-05-17 17:13:01 -0700150 .WillRepeatedly(Return(current_url));
151
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700152 auto response_handler_action =
153 std::make_unique<OmahaResponseHandlerAction>(&fake_system_state_);
154 if (!test_deadline_file.empty())
155 response_handler_action->deadline_file_ = test_deadline_file;
156
157 auto collector_action =
158 std::make_unique<ObjectCollectorAction<InstallPlan>>();
159
160 BondActions(feeder_action.get(), response_handler_action.get());
161 BondActions(response_handler_action.get(), collector_action.get());
162 processor.EnqueueAction(std::move(feeder_action));
163 processor.EnqueueAction(std::move(response_handler_action));
164 processor.EnqueueAction(std::move(collector_action));
adlr@google.com3defe6a2009-12-04 20:57:17 +0000165 processor.StartProcessing();
166 EXPECT_TRUE(!processor.IsRunning())
Alex Vakulenko072359c2014-07-18 11:41:07 -0700167 << "Update test to handle non-async actions";
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700168
169 if (out && delegate_.collector_action_install_plan_)
170 *out = *delegate_.collector_action_install_plan_;
171
172 EXPECT_TRUE(delegate_.code_set_);
173 action_result_code_ = delegate_.code_;
174 return delegate_.code_ == ErrorCode::kSuccess;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000175}
176
177TEST_F(OmahaResponseHandlerActionTest, SimpleTest) {
Sen Jiang0779a152018-07-02 17:34:56 -0700178 test_utils::ScopedTempFile test_deadline_file(
179 "omaha_response_handler_action_unittest-XXXXXX");
adlr@google.com3defe6a2009-12-04 20:57:17 +0000180 {
Darin Petkov6a5b3222010-07-13 14:55:28 -0700181 OmahaResponse in;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000182 in.update_exists = true;
Chris Sosa3b748432013-06-20 16:42:59 -0700183 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800184 in.packages.push_back(
185 {.payload_urls = {"http://foo/the_update_a.b.c.d.tgz"},
186 .size = 12,
187 .hash = kPayloadHashHex});
adlr@google.com3defe6a2009-12-04 20:57:17 +0000188 in.more_info_url = "http://more/info";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000189 in.prompt = false;
Darin Petkov6c118642010-10-21 12:06:30 -0700190 in.deadline = "20101020";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000191 InstallPlan install_plan;
Sen Jiang0779a152018-07-02 17:34:56 -0700192 EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
Sen Jiang0affc2c2017-02-10 15:55:05 -0800193 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
194 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
Alex Deymo80f70ff2016-02-10 16:08:11 -0800195 EXPECT_EQ(1U, install_plan.target_slot);
Darin Petkov6c118642010-10-21 12:06:30 -0700196 string deadline;
Sen Jiang0779a152018-07-02 17:34:56 -0700197 EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline));
Darin Petkov6c118642010-10-21 12:06:30 -0700198 EXPECT_EQ("20101020", deadline);
199 struct stat deadline_stat;
Sen Jiang0779a152018-07-02 17:34:56 -0700200 EXPECT_EQ(0, stat(test_deadline_file.path().c_str(), &deadline_stat));
Alex Deymo80f70ff2016-02-10 16:08:11 -0800201 EXPECT_EQ(
202 static_cast<mode_t>(S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH),
203 deadline_stat.st_mode);
Chris Sosafb1020e2013-07-29 17:27:33 -0700204 EXPECT_EQ(in.version, install_plan.version);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000205 }
206 {
Darin Petkov6a5b3222010-07-13 14:55:28 -0700207 OmahaResponse in;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000208 in.update_exists = true;
Chris Sosa3b748432013-06-20 16:42:59 -0700209 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800210 in.packages.push_back(
211 {.payload_urls = {"http://foo/the_update_a.b.c.d.tgz"},
212 .size = 12,
213 .hash = kPayloadHashHex});
adlr@google.com3defe6a2009-12-04 20:57:17 +0000214 in.more_info_url = "http://more/info";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000215 in.prompt = true;
216 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700217 // Set the other slot as current.
218 fake_system_state_.fake_boot_control()->SetCurrentSlot(1);
Sen Jiang0779a152018-07-02 17:34:56 -0700219 EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
Sen Jiang0affc2c2017-02-10 15:55:05 -0800220 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
221 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
Alex Deymo80f70ff2016-02-10 16:08:11 -0800222 EXPECT_EQ(0U, install_plan.target_slot);
Darin Petkov6c118642010-10-21 12:06:30 -0700223 string deadline;
Sen Jiang0779a152018-07-02 17:34:56 -0700224 EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline) &&
Gilad Arnold4dbd47e2013-07-22 05:39:26 -0700225 deadline.empty());
Chris Sosafb1020e2013-07-29 17:27:33 -0700226 EXPECT_EQ(in.version, install_plan.version);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000227 }
228 {
Darin Petkov6a5b3222010-07-13 14:55:28 -0700229 OmahaResponse in;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000230 in.update_exists = true;
Chris Sosa3b748432013-06-20 16:42:59 -0700231 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800232 in.packages.push_back(
233 {.payload_urls = {kLongName}, .size = 12, .hash = kPayloadHashHex});
adlr@google.com3defe6a2009-12-04 20:57:17 +0000234 in.more_info_url = "http://more/info";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000235 in.prompt = true;
Darin Petkov6c118642010-10-21 12:06:30 -0700236 in.deadline = "some-deadline";
adlr@google.com3defe6a2009-12-04 20:57:17 +0000237 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700238 fake_system_state_.fake_boot_control()->SetCurrentSlot(0);
Marton Hunyadye58bddb2018-04-10 20:27:26 +0200239 // Because rollback happened, the deadline shouldn't be written into the
240 // file.
241 EXPECT_CALL(*(fake_system_state_.mock_payload_state()),
242 GetRollbackHappened())
243 .WillOnce(Return(true));
Sen Jiang456853f2018-08-13 15:41:43 -0700244 EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
Marton Hunyadye58bddb2018-04-10 20:27:26 +0200245 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
246 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
247 EXPECT_EQ(1U, install_plan.target_slot);
248 string deadline;
Sen Jiang456853f2018-08-13 15:41:43 -0700249 EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline));
Marton Hunyadye58bddb2018-04-10 20:27:26 +0200250 EXPECT_TRUE(deadline.empty());
251 EXPECT_EQ(in.version, install_plan.version);
252 }
253 {
254 OmahaResponse in;
255 in.update_exists = true;
256 in.version = "a.b.c.d";
257 in.packages.push_back(
258 {.payload_urls = {kLongName}, .size = 12, .hash = kPayloadHashHex});
259 in.more_info_url = "http://more/info";
260 in.prompt = true;
261 in.deadline = "some-deadline";
262 InstallPlan install_plan;
263 fake_system_state_.fake_boot_control()->SetCurrentSlot(0);
264 EXPECT_CALL(*(fake_system_state_.mock_payload_state()),
265 GetRollbackHappened())
266 .WillOnce(Return(false));
Sen Jiang0779a152018-07-02 17:34:56 -0700267 EXPECT_TRUE(DoTest(in, test_deadline_file.path(), &install_plan));
Sen Jiang0affc2c2017-02-10 15:55:05 -0800268 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
269 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
Alex Deymo80f70ff2016-02-10 16:08:11 -0800270 EXPECT_EQ(1U, install_plan.target_slot);
Darin Petkov6c118642010-10-21 12:06:30 -0700271 string deadline;
Sen Jiang0779a152018-07-02 17:34:56 -0700272 EXPECT_TRUE(utils::ReadFile(test_deadline_file.path(), &deadline));
Darin Petkov6c118642010-10-21 12:06:30 -0700273 EXPECT_EQ("some-deadline", deadline);
Chris Sosafb1020e2013-07-29 17:27:33 -0700274 EXPECT_EQ(in.version, install_plan.version);
adlr@google.com3defe6a2009-12-04 20:57:17 +0000275 }
276}
277
278TEST_F(OmahaResponseHandlerActionTest, NoUpdatesTest) {
Darin Petkov6a5b3222010-07-13 14:55:28 -0700279 OmahaResponse in;
adlr@google.com3defe6a2009-12-04 20:57:17 +0000280 in.update_exists = false;
281 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700282 EXPECT_FALSE(DoTest(in, "", &install_plan));
Alex Deymoe5e5fe92015-10-05 09:28:19 -0700283 EXPECT_TRUE(install_plan.partitions.empty());
adlr@google.com3defe6a2009-12-04 20:57:17 +0000284}
285
Xiaochu Liu88d90382018-08-29 16:09:11 -0700286TEST_F(OmahaResponseHandlerActionTest, InstallTest) {
287 OmahaResponse in;
288 in.update_exists = true;
289 in.version = "a.b.c.d";
290 in.packages.push_back(
291 {.payload_urls = {kLongName}, .size = 1, .hash = kPayloadHashHex});
292 in.packages.push_back(
293 {.payload_urls = {kLongName}, .size = 2, .hash = kPayloadHashHex});
294 in.more_info_url = "http://more/info";
295
296 OmahaRequestParams params(&fake_system_state_);
297 params.set_is_install(true);
298
299 fake_system_state_.set_request_params(&params);
300 InstallPlan install_plan;
301 EXPECT_TRUE(DoTest(in, "", &install_plan));
302 EXPECT_EQ(install_plan.source_slot, UINT_MAX);
303}
304
Sen Jiang0affc2c2017-02-10 15:55:05 -0800305TEST_F(OmahaResponseHandlerActionTest, MultiPackageTest) {
306 OmahaResponse in;
307 in.update_exists = true;
308 in.version = "a.b.c.d";
309 in.packages.push_back({.payload_urls = {"http://package/1"},
310 .size = 1,
311 .hash = kPayloadHashHex});
312 in.packages.push_back({.payload_urls = {"http://package/2"},
313 .size = 2,
314 .hash = kPayloadHashHex});
315 in.more_info_url = "http://more/info";
316 InstallPlan install_plan;
317 EXPECT_TRUE(DoTest(in, "", &install_plan));
318 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
319 EXPECT_EQ(2u, install_plan.payloads.size());
320 EXPECT_EQ(in.packages[0].size, install_plan.payloads[0].size);
321 EXPECT_EQ(in.packages[1].size, install_plan.payloads[1].size);
322 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
323 EXPECT_EQ(expected_hash_, install_plan.payloads[1].hash);
324 EXPECT_EQ(in.version, install_plan.version);
325}
326
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800327TEST_F(OmahaResponseHandlerActionTest, HashChecksForHttpTest) {
328 OmahaResponse in;
329 in.update_exists = true;
Chris Sosa3b748432013-06-20 16:42:59 -0700330 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800331 in.packages.push_back(
332 {.payload_urls = {"http://test.should/need/hash.checks.signed"},
333 .size = 12,
334 .hash = kPayloadHashHex});
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800335 in.more_info_url = "http://more/info";
David Pursell02c18642014-11-06 11:26:11 -0800336 // Hash checks are always skipped for non-official update URLs.
Alex Deymo763e7db2015-08-27 21:08:08 -0700337 EXPECT_CALL(*(fake_system_state_.mock_request_params()),
David Pursell02c18642014-11-06 11:26:11 -0800338 IsUpdateUrlOfficial())
339 .WillRepeatedly(Return(true));
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800340 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700341 EXPECT_TRUE(DoTest(in, "", &install_plan));
Sen Jiang0affc2c2017-02-10 15:55:05 -0800342 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
343 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800344 EXPECT_TRUE(install_plan.hash_checks_mandatory);
Chris Sosafb1020e2013-07-29 17:27:33 -0700345 EXPECT_EQ(in.version, install_plan.version);
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800346}
347
David Pursell02c18642014-11-06 11:26:11 -0800348TEST_F(OmahaResponseHandlerActionTest, HashChecksForUnofficialUpdateUrl) {
349 OmahaResponse in;
350 in.update_exists = true;
351 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800352 in.packages.push_back(
353 {.payload_urls = {"http://url.normally/needs/hash.checks.signed"},
354 .size = 12,
355 .hash = kPayloadHashHex});
David Pursell02c18642014-11-06 11:26:11 -0800356 in.more_info_url = "http://more/info";
Alex Deymo763e7db2015-08-27 21:08:08 -0700357 EXPECT_CALL(*(fake_system_state_.mock_request_params()),
David Pursell02c18642014-11-06 11:26:11 -0800358 IsUpdateUrlOfficial())
359 .WillRepeatedly(Return(false));
360 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700361 EXPECT_TRUE(DoTest(in, "", &install_plan));
Sen Jiang0affc2c2017-02-10 15:55:05 -0800362 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
363 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
David Pursell02c18642014-11-06 11:26:11 -0800364 EXPECT_FALSE(install_plan.hash_checks_mandatory);
365 EXPECT_EQ(in.version, install_plan.version);
366}
367
David Pursell907b4fa2015-01-27 10:27:38 -0800368TEST_F(OmahaResponseHandlerActionTest,
369 HashChecksForOfficialUrlUnofficialBuildTest) {
370 // Official URLs for unofficial builds (dev/test images) don't require hash.
371 OmahaResponse in;
372 in.update_exists = true;
373 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800374 in.packages.push_back(
375 {.payload_urls = {"http://url.normally/needs/hash.checks.signed"},
376 .size = 12,
377 .hash = kPayloadHashHex});
David Pursell907b4fa2015-01-27 10:27:38 -0800378 in.more_info_url = "http://more/info";
Alex Deymo763e7db2015-08-27 21:08:08 -0700379 EXPECT_CALL(*(fake_system_state_.mock_request_params()),
David Pursell907b4fa2015-01-27 10:27:38 -0800380 IsUpdateUrlOfficial())
381 .WillRepeatedly(Return(true));
Alex Deymo763e7db2015-08-27 21:08:08 -0700382 fake_system_state_.fake_hardware()->SetIsOfficialBuild(false);
David Pursell907b4fa2015-01-27 10:27:38 -0800383 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700384 EXPECT_TRUE(DoTest(in, "", &install_plan));
Sen Jiang0affc2c2017-02-10 15:55:05 -0800385 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
386 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
David Pursell907b4fa2015-01-27 10:27:38 -0800387 EXPECT_FALSE(install_plan.hash_checks_mandatory);
388 EXPECT_EQ(in.version, install_plan.version);
389}
390
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800391TEST_F(OmahaResponseHandlerActionTest, HashChecksForHttpsTest) {
392 OmahaResponse in;
393 in.update_exists = true;
Chris Sosa3b748432013-06-20 16:42:59 -0700394 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800395 in.packages.push_back(
396 {.payload_urls = {"https://test.should/need/hash.checks.signed"},
397 .size = 12,
398 .hash = kPayloadHashHex});
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800399 in.more_info_url = "http://more/info";
Alex Deymo763e7db2015-08-27 21:08:08 -0700400 EXPECT_CALL(*(fake_system_state_.mock_request_params()),
David Pursell02c18642014-11-06 11:26:11 -0800401 IsUpdateUrlOfficial())
402 .WillRepeatedly(Return(true));
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800403 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700404 EXPECT_TRUE(DoTest(in, "", &install_plan));
Sen Jiang0affc2c2017-02-10 15:55:05 -0800405 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
406 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
Sen Jiang81c705b2018-10-04 14:15:05 -0700407 EXPECT_TRUE(install_plan.hash_checks_mandatory);
Chris Sosafb1020e2013-07-29 17:27:33 -0700408 EXPECT_EQ(in.version, install_plan.version);
Jay Srinivasan738fdf32012-12-07 17:40:54 -0800409}
410
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800411TEST_F(OmahaResponseHandlerActionTest, HashChecksForBothHttpAndHttpsTest) {
412 OmahaResponse in;
413 in.update_exists = true;
Chris Sosa3b748432013-06-20 16:42:59 -0700414 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800415 in.packages.push_back(
416 {.payload_urls = {"http://test.should.still/need/hash.checks",
417 "https://test.should.still/need/hash.checks"},
418 .size = 12,
419 .hash = kPayloadHashHex});
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800420 in.more_info_url = "http://more/info";
Alex Deymo763e7db2015-08-27 21:08:08 -0700421 EXPECT_CALL(*(fake_system_state_.mock_request_params()),
David Pursell02c18642014-11-06 11:26:11 -0800422 IsUpdateUrlOfficial())
423 .WillRepeatedly(Return(true));
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800424 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700425 EXPECT_TRUE(DoTest(in, "", &install_plan));
Sen Jiang0affc2c2017-02-10 15:55:05 -0800426 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
427 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800428 EXPECT_TRUE(install_plan.hash_checks_mandatory);
Chris Sosafb1020e2013-07-29 17:27:33 -0700429 EXPECT_EQ(in.version, install_plan.version);
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800430}
431
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700432TEST_F(OmahaResponseHandlerActionTest, ChangeToMoreStableChannelTest) {
433 OmahaResponse in;
434 in.update_exists = true;
Chris Sosa3b748432013-06-20 16:42:59 -0700435 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800436 in.packages.push_back({.payload_urls = {"https://MoreStableChannelTest"},
437 .size = 1,
438 .hash = kPayloadHashHex});
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700439 in.more_info_url = "http://more/info";
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700440
Gilad Arnoldeff87cc2013-07-22 18:32:09 -0700441 // Create a uniquely named test directory.
Sen Jiang297e5832016-03-17 14:45:51 -0700442 base::ScopedTempDir tempdir;
443 ASSERT_TRUE(tempdir.CreateUniqueTempDir());
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700444
Alex Deymo763e7db2015-08-27 21:08:08 -0700445 OmahaRequestParams params(&fake_system_state_);
Alex Deymo85616652015-10-15 18:48:31 -0700446 fake_system_state_.fake_hardware()->SetIsOfficialBuild(false);
Hidehiko Abe2b9d2412017-12-13 18:56:18 +0900447 params.set_root(tempdir.GetPath().value());
Sen Jiang297e5832016-03-17 14:45:51 -0700448 params.set_current_channel("canary-channel");
449 // The ImageProperties in Android uses prefs to store MutableImageProperties.
450#ifdef __ANDROID__
Sen Jiang297e5832016-03-17 14:45:51 -0700451 EXPECT_CALL(*fake_system_state_.mock_prefs(), SetBoolean(_, true))
452 .WillOnce(Return(true));
453#endif // __ANDROID__
454 EXPECT_TRUE(params.SetTargetChannel("stable-channel", true, nullptr));
455 params.UpdateDownloadChannel();
Sen Jiang8500d3a2018-02-08 12:04:05 -0800456 EXPECT_TRUE(params.ShouldPowerwash());
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700457
Alex Deymo763e7db2015-08-27 21:08:08 -0700458 fake_system_state_.set_request_params(&params);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700459 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700460 EXPECT_TRUE(DoTest(in, "", &install_plan));
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700461 EXPECT_TRUE(install_plan.powerwash_required);
462}
463
464TEST_F(OmahaResponseHandlerActionTest, ChangeToLessStableChannelTest) {
465 OmahaResponse in;
466 in.update_exists = true;
Chris Sosa3b748432013-06-20 16:42:59 -0700467 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800468 in.packages.push_back({.payload_urls = {"https://LessStableChannelTest"},
469 .size = 15,
470 .hash = kPayloadHashHex});
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700471 in.more_info_url = "http://more/info";
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700472
Gilad Arnoldeff87cc2013-07-22 18:32:09 -0700473 // Create a uniquely named test directory.
Sen Jiang297e5832016-03-17 14:45:51 -0700474 base::ScopedTempDir tempdir;
475 ASSERT_TRUE(tempdir.CreateUniqueTempDir());
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700476
Alex Deymo763e7db2015-08-27 21:08:08 -0700477 OmahaRequestParams params(&fake_system_state_);
Alex Deymo85616652015-10-15 18:48:31 -0700478 fake_system_state_.fake_hardware()->SetIsOfficialBuild(false);
Hidehiko Abe2b9d2412017-12-13 18:56:18 +0900479 params.set_root(tempdir.GetPath().value());
Sen Jiang297e5832016-03-17 14:45:51 -0700480 params.set_current_channel("stable-channel");
481 // The ImageProperties in Android uses prefs to store MutableImageProperties.
482#ifdef __ANDROID__
Sen Jiang297e5832016-03-17 14:45:51 -0700483 EXPECT_CALL(*fake_system_state_.mock_prefs(), SetBoolean(_, false))
484 .WillOnce(Return(true));
485#endif // __ANDROID__
486 EXPECT_TRUE(params.SetTargetChannel("canary-channel", false, nullptr));
487 params.UpdateDownloadChannel();
Sen Jiang8500d3a2018-02-08 12:04:05 -0800488 EXPECT_FALSE(params.ShouldPowerwash());
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700489
Alex Deymo763e7db2015-08-27 21:08:08 -0700490 fake_system_state_.set_request_params(&params);
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700491 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700492 EXPECT_TRUE(DoTest(in, "", &install_plan));
Jay Srinivasanae4697c2013-03-18 17:08:08 -0700493 EXPECT_FALSE(install_plan.powerwash_required);
494}
Jay Srinivasan6f6ea002012-12-14 11:26:28 -0800495
David Zeuthen8f191b22013-08-06 12:27:50 -0700496TEST_F(OmahaResponseHandlerActionTest, P2PUrlIsUsedAndHashChecksMandatory) {
497 OmahaResponse in;
498 in.update_exists = true;
499 in.version = "a.b.c.d";
Sen Jiang0affc2c2017-02-10 15:55:05 -0800500 in.packages.push_back(
501 {.payload_urls = {"https://would.not/cause/hash/checks"},
502 .size = 12,
503 .hash = kPayloadHashHex});
David Zeuthen8f191b22013-08-06 12:27:50 -0700504 in.more_info_url = "http://more/info";
David Zeuthen8f191b22013-08-06 12:27:50 -0700505
Alex Deymo763e7db2015-08-27 21:08:08 -0700506 OmahaRequestParams params(&fake_system_state_);
David Pursell02c18642014-11-06 11:26:11 -0800507 // We're using a real OmahaRequestParams object here so we can't mock
508 // IsUpdateUrlOfficial(), but setting the update URL to the AutoUpdate test
509 // server will cause IsUpdateUrlOfficial() to return true.
Alex Deymoac41a822015-09-15 20:52:53 -0700510 params.set_update_url(constants::kOmahaDefaultAUTestURL);
Alex Deymo763e7db2015-08-27 21:08:08 -0700511 fake_system_state_.set_request_params(&params);
David Zeuthen8f191b22013-08-06 12:27:50 -0700512
Alex Deymo763e7db2015-08-27 21:08:08 -0700513 EXPECT_CALL(*fake_system_state_.mock_payload_state(),
David Zeuthenbb8bdc72013-09-03 13:43:48 -0700514 SetUsingP2PForDownloading(true));
515
David Zeuthen8f191b22013-08-06 12:27:50 -0700516 string p2p_url = "http://9.8.7.6/p2p";
Alex Deymo763e7db2015-08-27 21:08:08 -0700517 EXPECT_CALL(*fake_system_state_.mock_payload_state(), GetP2PUrl())
Gilad Arnold74b5f552014-10-07 08:17:16 -0700518 .WillRepeatedly(Return(p2p_url));
Alex Deymo763e7db2015-08-27 21:08:08 -0700519 EXPECT_CALL(*fake_system_state_.mock_payload_state(),
Aaron Woodc73fdc12017-12-06 11:09:15 -0800520 GetUsingP2PForDownloading())
521 .WillRepeatedly(Return(true));
David Zeuthen8f191b22013-08-06 12:27:50 -0700522
523 InstallPlan install_plan;
Alex Deymo763e7db2015-08-27 21:08:08 -0700524 EXPECT_TRUE(DoTest(in, "", &install_plan));
Sen Jiang0affc2c2017-02-10 15:55:05 -0800525 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
Sen Jiang2703ef42017-03-16 13:36:21 -0700526 EXPECT_EQ(p2p_url, install_plan.download_url);
David Zeuthen8f191b22013-08-06 12:27:50 -0700527 EXPECT_TRUE(install_plan.hash_checks_mandatory);
528}
529
Marton Hunyady199152d2018-05-07 19:08:48 +0200530TEST_F(OmahaResponseHandlerActionTest, RollbackTest) {
531 OmahaResponse in;
532 in.update_exists = true;
533 in.packages.push_back({.payload_urls = {"https://RollbackTest"},
534 .size = 1,
535 .hash = kPayloadHashHex});
536 in.is_rollback = true;
Zentaro Kavanagh0ff621c2018-07-13 13:06:56 -0700537 in.rollback_key_version.kernel = 1;
538 in.rollback_key_version.kernel = 2;
539 in.rollback_key_version.firmware_key = 3;
540 in.rollback_key_version.firmware = 4;
Marton Hunyady199152d2018-05-07 19:08:48 +0200541
542 fake_system_state_.fake_hardware()->SetMinKernelKeyVersion(0x00010002);
543 fake_system_state_.fake_hardware()->SetMinFirmwareKeyVersion(0x00030004);
544
545 OmahaRequestParams params(&fake_system_state_);
546 params.set_rollback_allowed(true);
547
548 fake_system_state_.set_request_params(&params);
549 InstallPlan install_plan;
550 EXPECT_TRUE(DoTest(in, "", &install_plan));
551 EXPECT_TRUE(install_plan.is_rollback);
552}
553
554TEST_F(OmahaResponseHandlerActionTest, RollbackKernelVersionErrorTest) {
555 OmahaResponse in;
556 in.update_exists = true;
557 in.packages.push_back({.payload_urls = {"https://RollbackTest"},
558 .size = 1,
559 .hash = kPayloadHashHex});
560 in.is_rollback = true;
Zentaro Kavanagh0ff621c2018-07-13 13:06:56 -0700561 in.rollback_key_version.kernel_key = 1;
562 in.rollback_key_version.kernel = 1; // This is lower than the minimum.
563 in.rollback_key_version.firmware_key = 3;
564 in.rollback_key_version.firmware = 4;
Marton Hunyady199152d2018-05-07 19:08:48 +0200565
566 fake_system_state_.fake_hardware()->SetMinKernelKeyVersion(0x00010002);
567 fake_system_state_.fake_hardware()->SetMinFirmwareKeyVersion(0x00030004);
568
569 OmahaRequestParams params(&fake_system_state_);
570 params.set_rollback_allowed(true);
571
572 fake_system_state_.set_request_params(&params);
573 InstallPlan install_plan;
574 EXPECT_FALSE(DoTest(in, "", &install_plan));
575}
576
577TEST_F(OmahaResponseHandlerActionTest, RollbackFirmwareVersionErrorTest) {
578 OmahaResponse in;
579 in.update_exists = true;
580 in.packages.push_back({.payload_urls = {"https://RollbackTest"},
581 .size = 1,
582 .hash = kPayloadHashHex});
583 in.is_rollback = true;
Zentaro Kavanagh0ff621c2018-07-13 13:06:56 -0700584 in.rollback_key_version.kernel_key = 1;
585 in.rollback_key_version.kernel = 2;
586 in.rollback_key_version.firmware_key = 3;
587 in.rollback_key_version.firmware = 3; // This is lower than the minimum.
Marton Hunyady199152d2018-05-07 19:08:48 +0200588
589 fake_system_state_.fake_hardware()->SetMinKernelKeyVersion(0x00010002);
590 fake_system_state_.fake_hardware()->SetMinFirmwareKeyVersion(0x00030004);
591
592 OmahaRequestParams params(&fake_system_state_);
593 params.set_rollback_allowed(true);
594
595 fake_system_state_.set_request_params(&params);
596 InstallPlan install_plan;
597 EXPECT_FALSE(DoTest(in, "", &install_plan));
598}
599
600TEST_F(OmahaResponseHandlerActionTest, RollbackNotRollbackTest) {
601 OmahaResponse in;
602 in.update_exists = true;
603 in.packages.push_back({.payload_urls = {"https://RollbackTest"},
604 .size = 1,
605 .hash = kPayloadHashHex});
606 in.is_rollback = false;
607
608 OmahaRequestParams params(&fake_system_state_);
609 params.set_rollback_allowed(true);
610
611 fake_system_state_.set_request_params(&params);
612 InstallPlan install_plan;
613 EXPECT_TRUE(DoTest(in, "", &install_plan));
614 EXPECT_FALSE(install_plan.is_rollback);
615}
616
617TEST_F(OmahaResponseHandlerActionTest, RollbackNotAllowedTest) {
618 OmahaResponse in;
619 in.update_exists = true;
620 in.packages.push_back({.payload_urls = {"https://RollbackTest"},
621 .size = 1,
622 .hash = kPayloadHashHex});
623 in.is_rollback = true;
624
625 OmahaRequestParams params(&fake_system_state_);
626 params.set_rollback_allowed(false);
627
628 fake_system_state_.set_request_params(&params);
629 InstallPlan install_plan;
630 EXPECT_FALSE(DoTest(in, "", &install_plan));
631}
632
Aaron Wood7dcdedf2017-09-06 17:17:41 -0700633TEST_F(OmahaResponseHandlerActionTest, SystemVersionTest) {
634 OmahaResponse in;
635 in.update_exists = true;
636 in.version = "a.b.c.d";
637 in.system_version = "b.c.d.e";
638 in.packages.push_back({.payload_urls = {"http://package/1"},
639 .size = 1,
640 .hash = kPayloadHashHex});
641 in.packages.push_back({.payload_urls = {"http://package/2"},
642 .size = 2,
643 .hash = kPayloadHashHex});
644 in.more_info_url = "http://more/info";
645 InstallPlan install_plan;
646 EXPECT_TRUE(DoTest(in, "", &install_plan));
647 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
648 EXPECT_EQ(2u, install_plan.payloads.size());
649 EXPECT_EQ(in.packages[0].size, install_plan.payloads[0].size);
650 EXPECT_EQ(in.packages[1].size, install_plan.payloads[1].size);
651 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
652 EXPECT_EQ(expected_hash_, install_plan.payloads[1].hash);
653 EXPECT_EQ(in.version, install_plan.version);
654 EXPECT_EQ(in.system_version, install_plan.system_version);
655}
656
Aaron Wood23bd3392017-10-06 14:48:25 -0700657TEST_F(OmahaResponseHandlerActionTest, TestDeferredByPolicy) {
658 OmahaResponse in;
659 in.update_exists = true;
660 in.version = "a.b.c.d";
661 in.packages.push_back({.payload_urls = {"http://foo/the_update_a.b.c.d.tgz"},
662 .size = 12,
663 .hash = kPayloadHashHex});
664 // Setup the UpdateManager to disallow the update.
665 FakeClock fake_clock;
666 MockPolicy* mock_policy = new MockPolicy(&fake_clock);
667 FakeUpdateManager* fake_update_manager =
668 fake_system_state_.fake_update_manager();
669 fake_update_manager->set_policy(mock_policy);
670 EXPECT_CALL(*mock_policy, UpdateCanBeApplied(_, _, _, _, _))
671 .WillOnce(
672 DoAll(SetArgPointee<3>(ErrorCode::kOmahaUpdateDeferredPerPolicy),
673 Return(EvalStatus::kSucceeded)));
674 // Perform the Action. It should "fail" with kOmahaUpdateDeferredPerPolicy.
675 InstallPlan install_plan;
676 EXPECT_FALSE(DoTest(in, "", &install_plan));
677 EXPECT_EQ(ErrorCode::kOmahaUpdateDeferredPerPolicy, action_result_code_);
678 // Verify that DoTest() didn't set the output install plan.
679 EXPECT_EQ("", install_plan.version);
Aaron Wood23bd3392017-10-06 14:48:25 -0700680 // Now verify the InstallPlan that was generated.
Amin Hassanid3f4bea2018-04-30 14:52:40 -0700681 install_plan = *delegate_.response_handler_action_install_plan_;
Aaron Wood23bd3392017-10-06 14:48:25 -0700682 EXPECT_EQ(in.packages[0].payload_urls[0], install_plan.download_url);
683 EXPECT_EQ(expected_hash_, install_plan.payloads[0].hash);
684 EXPECT_EQ(1U, install_plan.target_slot);
685 EXPECT_EQ(in.version, install_plan.version);
686}
687
adlr@google.com3defe6a2009-12-04 20:57:17 +0000688} // namespace chromeos_update_engine