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