• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
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 //
16 
17 #include "update_engine/omaha_response_handler_action.h"
18 
19 #include <string>
20 
21 #include <base/files/file_util.h>
22 #include <gtest/gtest.h>
23 
24 #include "update_engine/common/constants.h"
25 #include "update_engine/common/platform_constants.h"
26 #include "update_engine/common/test_utils.h"
27 #include "update_engine/common/utils.h"
28 #include "update_engine/fake_system_state.h"
29 #include "update_engine/mock_payload_state.h"
30 #include "update_engine/payload_consumer/payload_constants.h"
31 
32 using chromeos_update_engine::test_utils::System;
33 using chromeos_update_engine::test_utils::WriteFileString;
34 using std::string;
35 using testing::Return;
36 
37 namespace chromeos_update_engine {
38 
39 class OmahaResponseHandlerActionTest : public ::testing::Test {
40  protected:
SetUp()41   void SetUp() override {
42     FakeBootControl* fake_boot_control = fake_system_state_.fake_boot_control();
43     fake_boot_control->SetPartitionDevice(
44         kLegacyPartitionNameKernel, 0, "/dev/sdz2");
45     fake_boot_control->SetPartitionDevice(
46         kLegacyPartitionNameRoot, 0, "/dev/sdz3");
47     fake_boot_control->SetPartitionDevice(
48         kLegacyPartitionNameKernel, 1, "/dev/sdz4");
49     fake_boot_control->SetPartitionDevice(
50         kLegacyPartitionNameRoot, 1, "/dev/sdz5");
51   }
52 
53   // Return true iff the OmahaResponseHandlerAction succeeded.
54   // If out is non-null, it's set w/ the response from the action.
55   bool DoTest(const OmahaResponse& in,
56               const string& deadline_file,
57               InstallPlan* out);
58 
59   FakeSystemState fake_system_state_;
60 };
61 
62 class OmahaResponseHandlerActionProcessorDelegate
63     : public ActionProcessorDelegate {
64  public:
OmahaResponseHandlerActionProcessorDelegate()65   OmahaResponseHandlerActionProcessorDelegate()
66       : code_(ErrorCode::kError),
67         code_set_(false) {}
ActionCompleted(ActionProcessor * processor,AbstractAction * action,ErrorCode code)68   void ActionCompleted(ActionProcessor* processor,
69                        AbstractAction* action,
70                        ErrorCode code) {
71     if (action->Type() == OmahaResponseHandlerAction::StaticType()) {
72       code_ = code;
73       code_set_ = true;
74     }
75   }
76   ErrorCode code_;
77   bool code_set_;
78 };
79 
80 namespace {
81 const char* const kLongName =
82     "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
83     "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
84     "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
85     "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
86     "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
87     "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
88     "very_long_name_and_no_slashes-very_long_name_and_no_slashes"
89     "-the_update_a.b.c.d_DELTA_.tgz";
90 const char* const kBadVersion = "don't update me";
91 }  // namespace
92 
DoTest(const OmahaResponse & in,const string & test_deadline_file,InstallPlan * out)93 bool OmahaResponseHandlerActionTest::DoTest(
94     const OmahaResponse& in,
95     const string& test_deadline_file,
96     InstallPlan* out) {
97   ActionProcessor processor;
98   OmahaResponseHandlerActionProcessorDelegate delegate;
99   processor.set_delegate(&delegate);
100 
101   ObjectFeederAction<OmahaResponse> feeder_action;
102   feeder_action.set_obj(in);
103   if (in.update_exists && in.version != kBadVersion) {
104     EXPECT_CALL(*(fake_system_state_.mock_prefs()),
105                 SetString(kPrefsUpdateCheckResponseHash, in.hash))
106         .WillOnce(Return(true));
107 
108     int slot = 1 - fake_system_state_.fake_boot_control()->GetCurrentSlot();
109     string key = kPrefsChannelOnSlotPrefix + std::to_string(slot);
110     EXPECT_CALL(*(fake_system_state_.mock_prefs()), SetString(key, testing::_))
111         .WillOnce(Return(true));
112   }
113 
114   string current_url = in.payload_urls.size() ? in.payload_urls[0] : "";
115   EXPECT_CALL(*(fake_system_state_.mock_payload_state()), GetCurrentUrl())
116       .WillRepeatedly(Return(current_url));
117 
118   OmahaResponseHandlerAction response_handler_action(
119       &fake_system_state_,
120       (test_deadline_file.empty() ?
121        constants::kOmahaResponseDeadlineFile : test_deadline_file));
122   BondActions(&feeder_action, &response_handler_action);
123   ObjectCollectorAction<InstallPlan> collector_action;
124   BondActions(&response_handler_action, &collector_action);
125   processor.EnqueueAction(&feeder_action);
126   processor.EnqueueAction(&response_handler_action);
127   processor.EnqueueAction(&collector_action);
128   processor.StartProcessing();
129   EXPECT_TRUE(!processor.IsRunning())
130       << "Update test to handle non-async actions";
131   if (out)
132     *out = collector_action.object();
133   EXPECT_TRUE(delegate.code_set_);
134   return delegate.code_ == ErrorCode::kSuccess;
135 }
136 
TEST_F(OmahaResponseHandlerActionTest,SimpleTest)137 TEST_F(OmahaResponseHandlerActionTest, SimpleTest) {
138   string test_deadline_file;
139   CHECK(utils::MakeTempFile(
140           "omaha_response_handler_action_unittest-XXXXXX",
141           &test_deadline_file, nullptr));
142   ScopedPathUnlinker deadline_unlinker(test_deadline_file);
143   {
144     OmahaResponse in;
145     in.update_exists = true;
146     in.version = "a.b.c.d";
147     in.payload_urls.push_back("http://foo/the_update_a.b.c.d.tgz");
148     in.more_info_url = "http://more/info";
149     in.hash = "HASH+";
150     in.size = 12;
151     in.prompt = false;
152     in.deadline = "20101020";
153     InstallPlan install_plan;
154     EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
155     EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
156     EXPECT_EQ(in.hash, install_plan.payload_hash);
157     EXPECT_EQ(1U, install_plan.target_slot);
158     string deadline;
159     EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline));
160     EXPECT_EQ("20101020", deadline);
161     struct stat deadline_stat;
162     EXPECT_EQ(0, stat(test_deadline_file.c_str(), &deadline_stat));
163     EXPECT_EQ(
164         static_cast<mode_t>(S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH),
165         deadline_stat.st_mode);
166     EXPECT_EQ(in.version, install_plan.version);
167   }
168   {
169     OmahaResponse in;
170     in.update_exists = true;
171     in.version = "a.b.c.d";
172     in.payload_urls.push_back("http://foo/the_update_a.b.c.d.tgz");
173     in.more_info_url = "http://more/info";
174     in.hash = "HASHj+";
175     in.size = 12;
176     in.prompt = true;
177     InstallPlan install_plan;
178     // Set the other slot as current.
179     fake_system_state_.fake_boot_control()->SetCurrentSlot(1);
180     EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
181     EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
182     EXPECT_EQ(in.hash, install_plan.payload_hash);
183     EXPECT_EQ(0U, install_plan.target_slot);
184     string deadline;
185     EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline) &&
186                 deadline.empty());
187     EXPECT_EQ(in.version, install_plan.version);
188   }
189   {
190     OmahaResponse in;
191     in.update_exists = true;
192     in.version = "a.b.c.d";
193     in.payload_urls.push_back(kLongName);
194     in.more_info_url = "http://more/info";
195     in.hash = "HASHj+";
196     in.size = 12;
197     in.prompt = true;
198     in.deadline = "some-deadline";
199     InstallPlan install_plan;
200     fake_system_state_.fake_boot_control()->SetCurrentSlot(0);
201     EXPECT_TRUE(DoTest(in, test_deadline_file, &install_plan));
202     EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
203     EXPECT_EQ(in.hash, install_plan.payload_hash);
204     EXPECT_EQ(1U, install_plan.target_slot);
205     string deadline;
206     EXPECT_TRUE(utils::ReadFile(test_deadline_file, &deadline));
207     EXPECT_EQ("some-deadline", deadline);
208     EXPECT_EQ(in.version, install_plan.version);
209   }
210 }
211 
TEST_F(OmahaResponseHandlerActionTest,NoUpdatesTest)212 TEST_F(OmahaResponseHandlerActionTest, NoUpdatesTest) {
213   OmahaResponse in;
214   in.update_exists = false;
215   InstallPlan install_plan;
216   EXPECT_FALSE(DoTest(in, "", &install_plan));
217   EXPECT_TRUE(install_plan.partitions.empty());
218 }
219 
TEST_F(OmahaResponseHandlerActionTest,HashChecksForHttpTest)220 TEST_F(OmahaResponseHandlerActionTest, HashChecksForHttpTest) {
221   OmahaResponse in;
222   in.update_exists = true;
223   in.version = "a.b.c.d";
224   in.payload_urls.push_back("http://test.should/need/hash.checks.signed");
225   in.more_info_url = "http://more/info";
226   in.hash = "HASHj+";
227   in.size = 12;
228   // Hash checks are always skipped for non-official update URLs.
229   EXPECT_CALL(*(fake_system_state_.mock_request_params()),
230               IsUpdateUrlOfficial())
231       .WillRepeatedly(Return(true));
232   InstallPlan install_plan;
233   EXPECT_TRUE(DoTest(in, "", &install_plan));
234   EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
235   EXPECT_EQ(in.hash, install_plan.payload_hash);
236   EXPECT_TRUE(install_plan.hash_checks_mandatory);
237   EXPECT_EQ(in.version, install_plan.version);
238 }
239 
TEST_F(OmahaResponseHandlerActionTest,HashChecksForUnofficialUpdateUrl)240 TEST_F(OmahaResponseHandlerActionTest, HashChecksForUnofficialUpdateUrl) {
241   OmahaResponse in;
242   in.update_exists = true;
243   in.version = "a.b.c.d";
244   in.payload_urls.push_back("http://url.normally/needs/hash.checks.signed");
245   in.more_info_url = "http://more/info";
246   in.hash = "HASHj+";
247   in.size = 12;
248   EXPECT_CALL(*(fake_system_state_.mock_request_params()),
249               IsUpdateUrlOfficial())
250       .WillRepeatedly(Return(false));
251   InstallPlan install_plan;
252   EXPECT_TRUE(DoTest(in, "", &install_plan));
253   EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
254   EXPECT_EQ(in.hash, install_plan.payload_hash);
255   EXPECT_FALSE(install_plan.hash_checks_mandatory);
256   EXPECT_EQ(in.version, install_plan.version);
257 }
258 
TEST_F(OmahaResponseHandlerActionTest,HashChecksForOfficialUrlUnofficialBuildTest)259 TEST_F(OmahaResponseHandlerActionTest,
260        HashChecksForOfficialUrlUnofficialBuildTest) {
261   // Official URLs for unofficial builds (dev/test images) don't require hash.
262   OmahaResponse in;
263   in.update_exists = true;
264   in.version = "a.b.c.d";
265   in.payload_urls.push_back("http://url.normally/needs/hash.checks.signed");
266   in.more_info_url = "http://more/info";
267   in.hash = "HASHj+";
268   in.size = 12;
269   EXPECT_CALL(*(fake_system_state_.mock_request_params()),
270               IsUpdateUrlOfficial())
271       .WillRepeatedly(Return(true));
272   fake_system_state_.fake_hardware()->SetIsOfficialBuild(false);
273   InstallPlan install_plan;
274   EXPECT_TRUE(DoTest(in, "", &install_plan));
275   EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
276   EXPECT_EQ(in.hash, install_plan.payload_hash);
277   EXPECT_FALSE(install_plan.hash_checks_mandatory);
278   EXPECT_EQ(in.version, install_plan.version);
279 }
280 
TEST_F(OmahaResponseHandlerActionTest,HashChecksForHttpsTest)281 TEST_F(OmahaResponseHandlerActionTest, HashChecksForHttpsTest) {
282   OmahaResponse in;
283   in.update_exists = true;
284   in.version = "a.b.c.d";
285   in.payload_urls.push_back("https://test.should.not/need/hash.checks.signed");
286   in.more_info_url = "http://more/info";
287   in.hash = "HASHj+";
288   in.size = 12;
289   EXPECT_CALL(*(fake_system_state_.mock_request_params()),
290               IsUpdateUrlOfficial())
291       .WillRepeatedly(Return(true));
292   InstallPlan install_plan;
293   EXPECT_TRUE(DoTest(in, "", &install_plan));
294   EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
295   EXPECT_EQ(in.hash, install_plan.payload_hash);
296   EXPECT_FALSE(install_plan.hash_checks_mandatory);
297   EXPECT_EQ(in.version, install_plan.version);
298 }
299 
TEST_F(OmahaResponseHandlerActionTest,HashChecksForBothHttpAndHttpsTest)300 TEST_F(OmahaResponseHandlerActionTest, HashChecksForBothHttpAndHttpsTest) {
301   OmahaResponse in;
302   in.update_exists = true;
303   in.version = "a.b.c.d";
304   in.payload_urls.push_back("http://test.should.still/need/hash.checks");
305   in.payload_urls.push_back("https://test.should.still/need/hash.checks");
306   in.more_info_url = "http://more/info";
307   in.hash = "HASHj+";
308   in.size = 12;
309   EXPECT_CALL(*(fake_system_state_.mock_request_params()),
310               IsUpdateUrlOfficial())
311       .WillRepeatedly(Return(true));
312   InstallPlan install_plan;
313   EXPECT_TRUE(DoTest(in, "", &install_plan));
314   EXPECT_EQ(in.payload_urls[0], install_plan.download_url);
315   EXPECT_EQ(in.hash, install_plan.payload_hash);
316   EXPECT_TRUE(install_plan.hash_checks_mandatory);
317   EXPECT_EQ(in.version, install_plan.version);
318 }
319 
TEST_F(OmahaResponseHandlerActionTest,ChangeToMoreStableChannelTest)320 TEST_F(OmahaResponseHandlerActionTest, ChangeToMoreStableChannelTest) {
321   OmahaResponse in;
322   in.update_exists = true;
323   in.version = "a.b.c.d";
324   in.payload_urls.push_back("https://MoreStableChannelTest");
325   in.more_info_url = "http://more/info";
326   in.hash = "HASHjk";
327   in.size = 15;
328 
329   // Create a uniquely named test directory.
330   string test_dir;
331   ASSERT_TRUE(utils::MakeTempDirectory(
332           "omaha_response_handler_action-test-XXXXXX", &test_dir));
333 
334   ASSERT_EQ(0, System(string("mkdir -p ") + test_dir + "/etc"));
335   ASSERT_EQ(0, System(string("mkdir -p ") + test_dir +
336                       kStatefulPartition + "/etc"));
337   ASSERT_TRUE(WriteFileString(
338       test_dir + "/etc/lsb-release",
339       "CHROMEOS_RELEASE_TRACK=canary-channel\n"));
340   ASSERT_TRUE(WriteFileString(
341       test_dir + kStatefulPartition + "/etc/lsb-release",
342       "CHROMEOS_IS_POWERWASH_ALLOWED=true\n"
343       "CHROMEOS_RELEASE_TRACK=stable-channel\n"));
344 
345   OmahaRequestParams params(&fake_system_state_);
346   fake_system_state_.fake_hardware()->SetIsOfficialBuild(false);
347   params.set_root(test_dir);
348   params.Init("1.2.3.4", "", 0);
349   EXPECT_EQ("canary-channel", params.current_channel());
350   EXPECT_EQ("stable-channel", params.target_channel());
351   EXPECT_TRUE(params.to_more_stable_channel());
352   EXPECT_TRUE(params.is_powerwash_allowed());
353 
354   fake_system_state_.set_request_params(&params);
355   InstallPlan install_plan;
356   EXPECT_TRUE(DoTest(in, "", &install_plan));
357   EXPECT_TRUE(install_plan.powerwash_required);
358 
359   ASSERT_TRUE(base::DeleteFile(base::FilePath(test_dir), true));
360 }
361 
TEST_F(OmahaResponseHandlerActionTest,ChangeToLessStableChannelTest)362 TEST_F(OmahaResponseHandlerActionTest, ChangeToLessStableChannelTest) {
363   OmahaResponse in;
364   in.update_exists = true;
365   in.version = "a.b.c.d";
366   in.payload_urls.push_back("https://LessStableChannelTest");
367   in.more_info_url = "http://more/info";
368   in.hash = "HASHjk";
369   in.size = 15;
370 
371   // Create a uniquely named test directory.
372   string test_dir;
373   ASSERT_TRUE(utils::MakeTempDirectory(
374           "omaha_response_handler_action-test-XXXXXX", &test_dir));
375 
376   ASSERT_EQ(0, System(string("mkdir -p ") + test_dir + "/etc"));
377   ASSERT_EQ(0, System(string("mkdir -p ") + test_dir +
378                       kStatefulPartition + "/etc"));
379   ASSERT_TRUE(WriteFileString(
380       test_dir + "/etc/lsb-release",
381       "CHROMEOS_RELEASE_TRACK=stable-channel\n"));
382   ASSERT_TRUE(WriteFileString(
383       test_dir + kStatefulPartition + "/etc/lsb-release",
384       "CHROMEOS_RELEASE_TRACK=canary-channel\n"));
385 
386   OmahaRequestParams params(&fake_system_state_);
387   fake_system_state_.fake_hardware()->SetIsOfficialBuild(false);
388   params.set_root(test_dir);
389   params.Init("5.6.7.8", "", 0);
390   EXPECT_EQ("stable-channel", params.current_channel());
391   params.SetTargetChannel("canary-channel", false, nullptr);
392   EXPECT_EQ("canary-channel", params.target_channel());
393   EXPECT_FALSE(params.to_more_stable_channel());
394   EXPECT_FALSE(params.is_powerwash_allowed());
395 
396   fake_system_state_.set_request_params(&params);
397   InstallPlan install_plan;
398   EXPECT_TRUE(DoTest(in, "", &install_plan));
399   EXPECT_FALSE(install_plan.powerwash_required);
400 
401   ASSERT_TRUE(base::DeleteFile(base::FilePath(test_dir), true));
402 }
403 
TEST_F(OmahaResponseHandlerActionTest,P2PUrlIsUsedAndHashChecksMandatory)404 TEST_F(OmahaResponseHandlerActionTest, P2PUrlIsUsedAndHashChecksMandatory) {
405   OmahaResponse in;
406   in.update_exists = true;
407   in.version = "a.b.c.d";
408   in.payload_urls.push_back("https://would.not/cause/hash/checks");
409   in.more_info_url = "http://more/info";
410   in.hash = "HASHj+";
411   in.size = 12;
412 
413   OmahaRequestParams params(&fake_system_state_);
414   // We're using a real OmahaRequestParams object here so we can't mock
415   // IsUpdateUrlOfficial(), but setting the update URL to the AutoUpdate test
416   // server will cause IsUpdateUrlOfficial() to return true.
417   params.set_update_url(constants::kOmahaDefaultAUTestURL);
418   fake_system_state_.set_request_params(&params);
419 
420   EXPECT_CALL(*fake_system_state_.mock_payload_state(),
421               SetUsingP2PForDownloading(true));
422 
423   string p2p_url = "http://9.8.7.6/p2p";
424   EXPECT_CALL(*fake_system_state_.mock_payload_state(), GetP2PUrl())
425       .WillRepeatedly(Return(p2p_url));
426   EXPECT_CALL(*fake_system_state_.mock_payload_state(),
427               GetUsingP2PForDownloading()).WillRepeatedly(Return(true));
428 
429   InstallPlan install_plan;
430   EXPECT_TRUE(DoTest(in, "", &install_plan));
431   EXPECT_EQ(in.hash, install_plan.payload_hash);
432   EXPECT_EQ(install_plan.download_url, p2p_url);
433   EXPECT_TRUE(install_plan.hash_checks_mandatory);
434 }
435 
436 }  // namespace chromeos_update_engine
437