• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (C) 2012 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 "gmock/gmock.h"
18 #include "update_engine/payload_consumer/postinstall_runner_action.h"
19 
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23 
24 #include <memory>
25 #include <string>
26 #include <utility>
27 #include "common/dynamic_partition_control_interface.h"
28 
29 #include <base/bind.h>
30 #include <base/files/file_util.h>
31 #include <base/message_loop/message_loop.h>
32 #include <android-base/stringprintf.h>
33 #include <brillo/message_loops/base_message_loop.h>
34 #include <brillo/message_loops/message_loop_utils.h>
35 #include <gmock/gmock.h>
36 #include <gtest/gtest.h>
37 
38 #include "update_engine/common/fake_boot_control.h"
39 #include "update_engine/common/fake_hardware.h"
40 #include "update_engine/common/test_utils.h"
41 #include "update_engine/common/utils.h"
42 #include "update_engine/common/mock_dynamic_partition_control.h"
43 
44 using brillo::MessageLoop;
45 using chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
46 using std::string;
47 using testing::_;
48 using testing::AtLeast;
49 using testing::Return;
50 
51 namespace chromeos_update_engine {
52 
53 class PostinstActionProcessorDelegate : public ActionProcessorDelegate {
54  public:
55   PostinstActionProcessorDelegate() = default;
ProcessingDone(const ActionProcessor * processor,ErrorCode code)56   void ProcessingDone(const ActionProcessor* processor,
57                       ErrorCode code) override {
58     MessageLoop::current()->BreakLoop();
59     processing_done_called_ = true;
60   }
ProcessingStopped(const ActionProcessor * processor)61   void ProcessingStopped(const ActionProcessor* processor) override {
62     MessageLoop::current()->BreakLoop();
63     processing_stopped_called_ = true;
64   }
65 
ActionCompleted(ActionProcessor * processor,AbstractAction * action,ErrorCode code)66   void ActionCompleted(ActionProcessor* processor,
67                        AbstractAction* action,
68                        ErrorCode code) override {
69     if (action->Type() == PostinstallRunnerAction::StaticType()) {
70       code_ = code;
71       code_set_ = true;
72     }
73   }
74 
75   ErrorCode code_{ErrorCode::kError};
76   bool code_set_{false};
77   bool processing_done_called_{false};
78   bool processing_stopped_called_{false};
79 };
80 
81 class MockPostinstallRunnerActionDelegate
82     : public PostinstallRunnerAction::DelegateInterface {
83  public:
84   MOCK_METHOD1(ProgressUpdate, void(double progress));
85 };
86 
87 class PostinstallRunnerActionTest : public ::testing::Test {
88  protected:
SetUp()89   void SetUp() override {
90     loop_.SetAsCurrent();
91     {
92       auto mock_dynamic_control =
93           std::make_unique<MockDynamicPartitionControl>();
94       mock_dynamic_control_ = mock_dynamic_control.get();
95       fake_boot_control_.SetDynamicPartitionControl(
96           std::move(mock_dynamic_control));
97     }
98     ON_CALL(*mock_dynamic_control_, FinishUpdate(_))
99         .WillByDefault(Return(true));
100     ON_CALL(*mock_dynamic_control_, GetVirtualAbFeatureFlag())
101         .WillByDefault(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
102   }
103 
104   // Setup an action processor and run the PostinstallRunnerAction with a single
105   // partition |device_path|, running the |postinstall_program| command from
106   // there.
107   void RunPostinstallAction(bool powerwash_required, bool save_rollback_data);
108 
109   void RunPostinstallActionWithInstallPlan(const InstallPlan& install_plan);
110 
111  public:
ResumeRunningAction()112   void ResumeRunningAction() {
113     ASSERT_NE(nullptr, postinstall_action_);
114     postinstall_action_->ResumeAction();
115   }
116 
117  protected:
118   base::MessageLoopForIO base_loop_;
119   brillo::BaseMessageLoop loop_{&base_loop_};
120 
121   FakeBootControl fake_boot_control_;
122   FakeHardware fake_hardware_;
123   MockDynamicPartitionControl* mock_dynamic_control_;
124   PostinstActionProcessorDelegate processor_delegate_;
125 
126   // The PostinstallRunnerAction delegate receiving the progress updates.
127   PostinstallRunnerAction::DelegateInterface* setup_action_delegate_{nullptr};
128 
129   // A pointer to the posinstall_runner action and the processor.
130   PostinstallRunnerAction* postinstall_action_{nullptr};
131   ActionProcessor* processor_{nullptr};
132 };
133 
RunPostinstallAction(bool powerwash_required,bool save_rollback_data)134 void PostinstallRunnerActionTest::RunPostinstallAction(
135     bool powerwash_required, bool save_rollback_data) {
136   InstallPlan::Partition part;
137   part.name = "part";
138   part.target_path = "/dev/invalid";
139   part.readonly_target_path = "/dev/invalid";
140   part.run_postinstall = false;
141   part.postinstall_path.clear();
142   InstallPlan install_plan;
143   install_plan.partitions = {part};
144   install_plan.download_url = "http://127.0.0.1:8080/update";
145   install_plan.powerwash_required = powerwash_required;
146   RunPostinstallActionWithInstallPlan(install_plan);
147 }
148 
RunPostinstallActionWithInstallPlan(const chromeos_update_engine::InstallPlan & install_plan)149 void PostinstallRunnerActionTest::RunPostinstallActionWithInstallPlan(
150     const chromeos_update_engine::InstallPlan& install_plan) {
151   ActionProcessor processor;
152   processor_ = &processor;
153   auto feeder_action = std::make_unique<ObjectFeederAction<InstallPlan>>();
154   feeder_action->set_obj(install_plan);
155   auto runner_action = std::make_unique<PostinstallRunnerAction>(
156       &fake_boot_control_, &fake_hardware_);
157   postinstall_action_ = runner_action.get();
158   base::FilePath temp_dir;
159   TEST_AND_RETURN(base::CreateNewTempDirectory("postinstall", &temp_dir));
160   postinstall_action_->SetMountDir(temp_dir.value());
161   runner_action->set_delegate(setup_action_delegate_);
162   BondActions(feeder_action.get(), runner_action.get());
163   auto collector_action =
164       std::make_unique<ObjectCollectorAction<InstallPlan>>();
165   BondActions(runner_action.get(), collector_action.get());
166   processor.EnqueueAction(std::move(feeder_action));
167   processor.EnqueueAction(std::move(runner_action));
168   processor.EnqueueAction(std::move(collector_action));
169   processor.set_delegate(&processor_delegate_);
170 
171   loop_.PostTask(
172       FROM_HERE,
173       base::Bind(
174           [](ActionProcessor* processor) { processor->StartProcessing(); },
175           base::Unretained(&processor)));
176   loop_.Run();
177   ASSERT_FALSE(processor.IsRunning());
178   postinstall_action_ = nullptr;
179   processor_ = nullptr;
180   ASSERT_TRUE(processor_delegate_.processing_stopped_called_ ||
181               processor_delegate_.processing_done_called_);
182   if (processor_delegate_.processing_done_called_) {
183     // Validation check that the code was set when the processor finishes.
184     ASSERT_TRUE(processor_delegate_.code_set_);
185   }
186 }
187 
188 // Test that postinstall succeeds in the simple case of running the default
189 // /postinst command which only exits 0.
TEST_F(PostinstallRunnerActionTest,RunAsRootSimpleTest)190 TEST_F(PostinstallRunnerActionTest, RunAsRootSimpleTest) {
191   EXPECT_CALL(*mock_dynamic_control_, GetVirtualAbFeatureFlag())
192       .WillOnce(Return(FeatureFlag(FeatureFlag::Value::LAUNCH)));
193   RunPostinstallAction(false, false);
194   ASSERT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
195   ASSERT_TRUE(processor_delegate_.processing_done_called_);
196 
197   // Since powerwash_required was false, this should not trigger a powerwash.
198   ASSERT_FALSE(fake_hardware_.IsPowerwashScheduled());
199   ASSERT_FALSE(fake_hardware_.GetIsRollbackPowerwashScheduled());
200 }
201 
202 }  // namespace chromeos_update_engine
203