1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2012 The Android Open Source Project
3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License.
6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at
7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software
11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and
14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License.
15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo//
163defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
1739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/payload_consumer/postinstall_runner_action.h"
181c0fe79c7ef2b43946d756b54c8505d2bf48b93bJay Srinivasan
193defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com#include <sys/stat.h>
203defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com#include <sys/types.h>
213defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com#include <unistd.h>
22bfabc3002566ba8aa4bda8c77469a075bd346f00Andrew de los Reyes
2302f7c1dee242f490143791dbb73fa23fa3007cfaBen Chan#include <memory>
243defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com#include <string>
253defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com#include <vector>
26bfabc3002566ba8aa4bda8c77469a075bd346f00Andrew de los Reyes
27d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo#include <base/bind.h>
2806c76a49bfd29c8abdb8abd5b646a6583783191aBen Chan#include <base/files/file_util.h>
290b3db6b6040f53eb9859e614f7fe4c681213d33aAlex Deymo#include <base/message_loop/message_loop.h>
3075039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/string_util.h>
3175039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/stringprintf.h>
323f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/bind_lambda.h>
333f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/message_loops/base_message_loop.h>
343f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/message_loops/message_loop_utils.h>
350d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo#include <gmock/gmock.h>
363defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com#include <gtest/gtest.h>
37bfabc3002566ba8aa4bda8c77469a075bd346f00Andrew de los Reyes
3839910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/constants.h"
39b15a0b8eaf18c9e9341706df9f4ab59ce595a67cAlex Deymo#include "update_engine/common/fake_boot_control.h"
40fb905d9b8d49f8fe41297c7aba2dd0942f1be311Alex Deymo#include "update_engine/common/fake_hardware.h"
4139910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/test_utils.h"
4239910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
433defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
443f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenkousing brillo::MessageLoop;
45cbc2274c4160805bf726df872390112654816ca7Alex Deymousing chromeos_update_engine::test_utils::ScopedLoopbackDeviceBinder;
463defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.comusing std::string;
473defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.comusing std::vector;
483defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
493defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.comnamespace chromeos_update_engine {
503defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
513defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.comclass PostinstActionProcessorDelegate : public ActionProcessorDelegate {
523defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com public:
53d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  PostinstActionProcessorDelegate() = default;
546f03a3b868d4b632931400628763036f79c449f7Darin Petkov  void ProcessingDone(const ActionProcessor* processor,
55d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo                      ErrorCode code) override {
5629b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo    MessageLoop::current()->BreakLoop();
57d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    processing_done_called_ = true;
586f03a3b868d4b632931400628763036f79c449f7Darin Petkov  }
59d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  void ProcessingStopped(const ActionProcessor* processor) override {
60d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    MessageLoop::current()->BreakLoop();
61d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    processing_stopped_called_ = true;
62d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  }
63d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo
643defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com  void ActionCompleted(ActionProcessor* processor,
653defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com                       AbstractAction* action,
66d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo                       ErrorCode code) override {
673defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com    if (action->Type() == PostinstallRunnerAction::StaticType()) {
68c1a8b426be9542bc880923711ca508ea3f84000eDarin Petkov      code_ = code;
69c1a8b426be9542bc880923711ca508ea3f84000eDarin Petkov      code_set_ = true;
703defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com    }
713defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com  }
72cbc2274c4160805bf726df872390112654816ca7Alex Deymo
73d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  ErrorCode code_{ErrorCode::kError};
74d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  bool code_set_{false};
75d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  bool processing_done_called_{false};
76d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  bool processing_stopped_called_{false};
773defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com};
783defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
790d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymoclass MockPostinstallRunnerActionDelegate
800d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo    : public PostinstallRunnerAction::DelegateInterface {
810d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo public:
820d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  MOCK_METHOD1(ProgressUpdate, void(double progress));
830d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo};
840d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
85cbc2274c4160805bf726df872390112654816ca7Alex Deymoclass PostinstallRunnerActionTest : public ::testing::Test {
86cbc2274c4160805bf726df872390112654816ca7Alex Deymo protected:
87cbc2274c4160805bf726df872390112654816ca7Alex Deymo  void SetUp() override {
88cbc2274c4160805bf726df872390112654816ca7Alex Deymo    loop_.SetAsCurrent();
89cbc2274c4160805bf726df872390112654816ca7Alex Deymo    async_signal_handler_.Init();
90cbc2274c4160805bf726df872390112654816ca7Alex Deymo    subprocess_.Init(&async_signal_handler_);
91cbc2274c4160805bf726df872390112654816ca7Alex Deymo    // These tests use the postinstall files generated by "generate_images.sh"
92d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    // stored in the "disk_ext2_unittest.img" image.
93260f03bc4d3a3de436e056c686c814444358823aSen Jiang    postinstall_image_ =
94260f03bc4d3a3de436e056c686c814444358823aSen Jiang        test_utils::GetBuildArtifactsPath("gen/disk_ext2_unittest.img");
95cbc2274c4160805bf726df872390112654816ca7Alex Deymo  }
961c0fe79c7ef2b43946d756b54c8505d2bf48b93bJay Srinivasan
97cbc2274c4160805bf726df872390112654816ca7Alex Deymo  // Setup an action processor and run the PostinstallRunnerAction with a single
98cbc2274c4160805bf726df872390112654816ca7Alex Deymo  // partition |device_path|, running the |postinstall_program| command from
99cbc2274c4160805bf726df872390112654816ca7Alex Deymo  // there.
100cbc2274c4160805bf726df872390112654816ca7Alex Deymo  void RunPosinstallAction(const string& device_path,
101cbc2274c4160805bf726df872390112654816ca7Alex Deymo                           const string& postinstall_program,
102cbc2274c4160805bf726df872390112654816ca7Alex Deymo                           bool powerwash_required);
1033defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
104d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo public:
105d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  void ResumeRunningAction() {
106d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    ASSERT_NE(nullptr, postinstall_action_);
107d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    postinstall_action_->ResumeAction();
108d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  }
109d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo
110d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  void SuspendRunningAction() {
111d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    if (!postinstall_action_ || !postinstall_action_->current_command_ ||
112d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo        test_utils::Readlink(base::StringPrintf(
113d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo            "/proc/%d/fd/0", postinstall_action_->current_command_)) !=
114d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo            "/dev/zero") {
115d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      // We need to wait for the postinstall command to start and flag that it
116d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      // is ready by redirecting its input to /dev/zero.
117d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      loop_.PostDelayedTask(
118d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo          FROM_HERE,
119d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo          base::Bind(&PostinstallRunnerActionTest::SuspendRunningAction,
120d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo                     base::Unretained(this)),
121d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo          base::TimeDelta::FromMilliseconds(100));
122d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    } else {
123d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      postinstall_action_->SuspendAction();
124d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      // Schedule to be resumed in a little bit.
125d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      loop_.PostDelayedTask(
126d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo          FROM_HERE,
127d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo          base::Bind(&PostinstallRunnerActionTest::ResumeRunningAction,
128d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo                     base::Unretained(this)),
129d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo          base::TimeDelta::FromMilliseconds(100));
130d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    }
131d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  }
132d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo
133d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  void CancelWhenStarted() {
134d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    if (!postinstall_action_ || !postinstall_action_->current_command_) {
135d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      // Wait for the postinstall command to run.
136d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      loop_.PostDelayedTask(
137d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo          FROM_HERE,
138d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo          base::Bind(&PostinstallRunnerActionTest::CancelWhenStarted,
139d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo                     base::Unretained(this)),
140d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo          base::TimeDelta::FromMilliseconds(10));
141d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    } else {
142d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      CHECK(processor_);
143d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo      processor_->StopProcessing();
144d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    }
145d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  }
146d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo
147cbc2274c4160805bf726df872390112654816ca7Alex Deymo protected:
148cbc2274c4160805bf726df872390112654816ca7Alex Deymo  base::MessageLoopForIO base_loop_;
149cbc2274c4160805bf726df872390112654816ca7Alex Deymo  brillo::BaseMessageLoop loop_{&base_loop_};
150cbc2274c4160805bf726df872390112654816ca7Alex Deymo  brillo::AsynchronousSignalHandler async_signal_handler_;
151cbc2274c4160805bf726df872390112654816ca7Alex Deymo  Subprocess subprocess_;
1523defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
153cbc2274c4160805bf726df872390112654816ca7Alex Deymo  // The path to the postinstall sample image.
154cbc2274c4160805bf726df872390112654816ca7Alex Deymo  string postinstall_image_;
15581018e089aedb07d806f5e6a18dc44e359a6fc06Don Garrett
156cbc2274c4160805bf726df872390112654816ca7Alex Deymo  FakeBootControl fake_boot_control_;
157fb905d9b8d49f8fe41297c7aba2dd0942f1be311Alex Deymo  FakeHardware fake_hardware_;
1580d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  PostinstActionProcessorDelegate processor_delegate_;
1590d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
1600d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  // The PostinstallRunnerAction delegate receiving the progress updates.
1610d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  PostinstallRunnerAction::DelegateInterface* setup_action_delegate_{nullptr};
162d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo
163d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  // A pointer to the posinstall_runner action and the processor.
164d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  PostinstallRunnerAction* postinstall_action_{nullptr};
165d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  ActionProcessor* processor_{nullptr};
166cbc2274c4160805bf726df872390112654816ca7Alex Deymo};
16730dedd82be72ffa9bbe570e9c95166ec6bcc7792Gilad Arnold
168cbc2274c4160805bf726df872390112654816ca7Alex Deymovoid PostinstallRunnerActionTest::RunPosinstallAction(
169cbc2274c4160805bf726df872390112654816ca7Alex Deymo    const string& device_path,
170cbc2274c4160805bf726df872390112654816ca7Alex Deymo    const string& postinstall_program,
1711c0fe79c7ef2b43946d756b54c8505d2bf48b93bJay Srinivasan    bool powerwash_required) {
1723defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com  ActionProcessor processor;
173d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  processor_ = &processor;
174f97144334e945a5ec88970b4b28f4e98ce0bbb80Andrew de los Reyes  ObjectFeederAction<InstallPlan> feeder_action;
175e5e5fe926e9ea45b1a381af1bee91a86643ffd72Alex Deymo  InstallPlan::Partition part;
176e5e5fe926e9ea45b1a381af1bee91a86643ffd72Alex Deymo  part.name = "part";
177cbc2274c4160805bf726df872390112654816ca7Alex Deymo  part.target_path = device_path;
178e5e5fe926e9ea45b1a381af1bee91a86643ffd72Alex Deymo  part.run_postinstall = true;
179cbc2274c4160805bf726df872390112654816ca7Alex Deymo  part.postinstall_path = postinstall_program;
180f97144334e945a5ec88970b4b28f4e98ce0bbb80Andrew de los Reyes  InstallPlan install_plan;
181e5e5fe926e9ea45b1a381af1bee91a86643ffd72Alex Deymo  install_plan.partitions = {part};
182cbc2274c4160805bf726df872390112654816ca7Alex Deymo  install_plan.download_url = "http://127.0.0.1:8080/update";
1831c0fe79c7ef2b43946d756b54c8505d2bf48b93bJay Srinivasan  install_plan.powerwash_required = powerwash_required;
184f97144334e945a5ec88970b4b28f4e98ce0bbb80Andrew de los Reyes  feeder_action.set_obj(install_plan);
185fb905d9b8d49f8fe41297c7aba2dd0942f1be311Alex Deymo  PostinstallRunnerAction runner_action(&fake_boot_control_, &fake_hardware_);
186d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  postinstall_action_ = &runner_action;
1870d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  runner_action.set_delegate(setup_action_delegate_);
1883defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com  BondActions(&feeder_action, &runner_action);
189f97144334e945a5ec88970b4b28f4e98ce0bbb80Andrew de los Reyes  ObjectCollectorAction<InstallPlan> collector_action;
1903defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com  BondActions(&runner_action, &collector_action);
1913defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com  processor.EnqueueAction(&feeder_action);
1923defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com  processor.EnqueueAction(&runner_action);
1933defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com  processor.EnqueueAction(&collector_action);
1940d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  processor.set_delegate(&processor_delegate_);
1956f03a3b868d4b632931400628763036f79c449f7Darin Petkov
196f1cf34849efdc0158fb1987ba74a51f25016c5bdLuis Hector Chavez  loop_.PostTask(
197f1cf34849efdc0158fb1987ba74a51f25016c5bdLuis Hector Chavez      FROM_HERE,
198f1cf34849efdc0158fb1987ba74a51f25016c5bdLuis Hector Chavez      base::Bind(
199f1cf34849efdc0158fb1987ba74a51f25016c5bdLuis Hector Chavez          [](ActionProcessor* processor) { processor->StartProcessing(); },
200f1cf34849efdc0158fb1987ba74a51f25016c5bdLuis Hector Chavez          base::Unretained(&processor)));
20129b815316519829f133b39dd1cae7ab6224c9da2Alex Deymo  loop_.Run();
2026f03a3b868d4b632931400628763036f79c449f7Darin Petkov  ASSERT_FALSE(processor.IsRunning());
203d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  postinstall_action_ = nullptr;
204d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  processor_ = nullptr;
2050d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_TRUE(processor_delegate_.processing_stopped_called_ ||
2060d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo              processor_delegate_.processing_done_called_);
2070d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  if (processor_delegate_.processing_done_called_) {
208d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo    // Sanity check that the code was set when the processor finishes.
2090d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo    EXPECT_TRUE(processor_delegate_.code_set_);
210d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  }
211cbc2274c4160805bf726df872390112654816ca7Alex Deymo}
212cbc2274c4160805bf726df872390112654816ca7Alex Deymo
2130d29854cf5bb05a22cf161b50052539aa420a36eAlex DeymoTEST_F(PostinstallRunnerActionTest, ProcessProgressLineTest) {
214fb905d9b8d49f8fe41297c7aba2dd0942f1be311Alex Deymo  PostinstallRunnerAction action(&fake_boot_control_, &fake_hardware_);
2150d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  testing::StrictMock<MockPostinstallRunnerActionDelegate> mock_delegate_;
2160d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  action.set_delegate(&mock_delegate_);
2170d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
2180d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  action.current_partition_ = 1;
2190d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  action.partition_weight_ = {1, 2, 5};
2200d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  action.accumulated_weight_ = 1;
2210d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  action.total_weight_ = 8;
2220d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
223d853730826e02647dee6ac818ceef73a4d0e57f0Alex Deymo  // 50% of the second action is 2/8 = 0.25 of the total.
2240d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_CALL(mock_delegate_, ProgressUpdate(0.25));
2250d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  action.ProcessProgressLine("global_progress 0.5");
2260d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
2270d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
228d853730826e02647dee6ac818ceef73a4d0e57f0Alex Deymo  // 1.5 should be read as 100%, to catch rounding error cases like 1.000001.
229d853730826e02647dee6ac818ceef73a4d0e57f0Alex Deymo  // 100% of the second is 3/8 of the total.
230d853730826e02647dee6ac818ceef73a4d0e57f0Alex Deymo  EXPECT_CALL(mock_delegate_, ProgressUpdate(0.375));
231d853730826e02647dee6ac818ceef73a4d0e57f0Alex Deymo  action.ProcessProgressLine("global_progress 1.5");
232d853730826e02647dee6ac818ceef73a4d0e57f0Alex Deymo  testing::Mock::VerifyAndClearExpectations(&mock_delegate_);
233d853730826e02647dee6ac818ceef73a4d0e57f0Alex Deymo
2340d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  // None of these should trigger a progress update.
2350d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  action.ProcessProgressLine("foo_bar");
2360d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  action.ProcessProgressLine("global_progress");
2370d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  action.ProcessProgressLine("global_progress ");
238d853730826e02647dee6ac818ceef73a4d0e57f0Alex Deymo  action.ProcessProgressLine("global_progress NaN");
239d853730826e02647dee6ac818ceef73a4d0e57f0Alex Deymo  action.ProcessProgressLine("global_progress Exception in ... :)");
2400d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo}
2410d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
242cbc2274c4160805bf726df872390112654816ca7Alex Deymo// Test that postinstall succeeds in the simple case of running the default
243cbc2274c4160805bf726df872390112654816ca7Alex Deymo// /postinst command which only exits 0.
244cbc2274c4160805bf726df872390112654816ca7Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootSimpleTest) {
245cbc2274c4160805bf726df872390112654816ca7Alex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
246cbc2274c4160805bf726df872390112654816ca7Alex Deymo  RunPosinstallAction(loop.dev(), kPostinstallDefaultScript, false);
2470d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
2480d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_TRUE(processor_delegate_.processing_done_called_);
2493defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
250cbc2274c4160805bf726df872390112654816ca7Alex Deymo  // Since powerwash_required was false, this should not trigger a powerwash.
251fb905d9b8d49f8fe41297c7aba2dd0942f1be311Alex Deymo  EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
252cbc2274c4160805bf726df872390112654816ca7Alex Deymo}
253cbc2274c4160805bf726df872390112654816ca7Alex Deymo
254cbc2274c4160805bf726df872390112654816ca7Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootRunSymlinkFileTest) {
255cbc2274c4160805bf726df872390112654816ca7Alex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
256cbc2274c4160805bf726df872390112654816ca7Alex Deymo  RunPosinstallAction(loop.dev(), "bin/postinst_link", false);
2570d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
258cbc2274c4160805bf726df872390112654816ca7Alex Deymo}
259cbc2274c4160805bf726df872390112654816ca7Alex Deymo
260cbc2274c4160805bf726df872390112654816ca7Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootPowerwashRequiredTest) {
261cbc2274c4160805bf726df872390112654816ca7Alex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
262cbc2274c4160805bf726df872390112654816ca7Alex Deymo  // Run a simple postinstall program but requiring a powerwash.
263cbc2274c4160805bf726df872390112654816ca7Alex Deymo  RunPosinstallAction(loop.dev(), "bin/postinst_example", true);
2640d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
2651c0fe79c7ef2b43946d756b54c8505d2bf48b93bJay Srinivasan
266fb905d9b8d49f8fe41297c7aba2dd0942f1be311Alex Deymo  // Check that powerwash was scheduled.
267fb905d9b8d49f8fe41297c7aba2dd0942f1be311Alex Deymo  EXPECT_TRUE(fake_hardware_.IsPowerwashScheduled());
268cbc2274c4160805bf726df872390112654816ca7Alex Deymo}
2691c0fe79c7ef2b43946d756b54c8505d2bf48b93bJay Srinivasan
270cbc2274c4160805bf726df872390112654816ca7Alex Deymo// Runs postinstall from a partition file that doesn't mount, so it should
271cbc2274c4160805bf726df872390112654816ca7Alex Deymo// fail.
272cbc2274c4160805bf726df872390112654816ca7Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootCantMountTest) {
273cbc2274c4160805bf726df872390112654816ca7Alex Deymo  RunPosinstallAction("/dev/null", kPostinstallDefaultScript, false);
2740d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
2753defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
276cbc2274c4160805bf726df872390112654816ca7Alex Deymo  // In case of failure, Postinstall should not signal a powerwash even if it
277cbc2274c4160805bf726df872390112654816ca7Alex Deymo  // was requested.
278fb905d9b8d49f8fe41297c7aba2dd0942f1be311Alex Deymo  EXPECT_FALSE(fake_hardware_.IsPowerwashScheduled());
279cbc2274c4160805bf726df872390112654816ca7Alex Deymo}
2803defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
281cbc2274c4160805bf726df872390112654816ca7Alex Deymo// Check that the failures from the postinstall script cause the action to
282cbc2274c4160805bf726df872390112654816ca7Alex Deymo// fail.
283cbc2274c4160805bf726df872390112654816ca7Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootErrScriptTest) {
284cbc2274c4160805bf726df872390112654816ca7Alex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
285cbc2274c4160805bf726df872390112654816ca7Alex Deymo  RunPosinstallAction(loop.dev(), "bin/postinst_fail1", false);
2860d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
287cbc2274c4160805bf726df872390112654816ca7Alex Deymo}
28830dedd82be72ffa9bbe570e9c95166ec6bcc7792Gilad Arnold
289cbc2274c4160805bf726df872390112654816ca7Alex Deymo// The exit code 3 and 4 are a specials cases that would be reported back to
290cbc2274c4160805bf726df872390112654816ca7Alex Deymo// UMA with a different error code. Test those cases are properly detected.
291cbc2274c4160805bf726df872390112654816ca7Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootFirmwareBErrScriptTest) {
292cbc2274c4160805bf726df872390112654816ca7Alex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
293cbc2274c4160805bf726df872390112654816ca7Alex Deymo  RunPosinstallAction(loop.dev(), "bin/postinst_fail3", false);
2940d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kPostinstallBootedFromFirmwareB,
2950d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo            processor_delegate_.code_);
296cbc2274c4160805bf726df872390112654816ca7Alex Deymo}
29730dedd82be72ffa9bbe570e9c95166ec6bcc7792Gilad Arnold
298cbc2274c4160805bf726df872390112654816ca7Alex Deymo// Check that you can't specify an absolute path.
299cbc2274c4160805bf726df872390112654816ca7Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootAbsolutePathNotAllowedTest) {
300cbc2274c4160805bf726df872390112654816ca7Alex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
301cbc2274c4160805bf726df872390112654816ca7Alex Deymo  RunPosinstallAction(loop.dev(), "/etc/../bin/sh", false);
3020d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kPostinstallRunnerError, processor_delegate_.code_);
3033defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com}
3043defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
305cbc2274c4160805bf726df872390112654816ca7Alex Deymo#ifdef __ANDROID__
306cbc2274c4160805bf726df872390112654816ca7Alex Deymo// Check that the postinstall file is relabeled to the postinstall label.
307cbc2274c4160805bf726df872390112654816ca7Alex Deymo// SElinux labels are only set on Android.
308cbc2274c4160805bf726df872390112654816ca7Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootCheckFileContextsTest) {
309cbc2274c4160805bf726df872390112654816ca7Alex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
310cbc2274c4160805bf726df872390112654816ca7Alex Deymo  RunPosinstallAction(loop.dev(), "bin/self_check_context", false);
3110d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
3123defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com}
313cbc2274c4160805bf726df872390112654816ca7Alex Deymo#endif  // __ANDROID__
3143defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com
315d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo// Check that you can suspend/resume postinstall actions.
316d15c546ed794293d0a63770467a0f3c4c84c6214Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootSuspendResumeActionTest) {
317d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
318d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo
319d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  // We need to wait for the child to run and setup its signal handler.
320d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  loop_.PostTask(FROM_HERE,
321d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo                 base::Bind(&PostinstallRunnerActionTest::SuspendRunningAction,
322d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo                            base::Unretained(this)));
323d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  RunPosinstallAction(loop.dev(), "bin/postinst_suspend", false);
324d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  // postinst_suspend returns 0 only if it was suspended at some point.
3250d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
3260d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_TRUE(processor_delegate_.processing_done_called_);
327d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo}
328d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo
329d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo// Test that we can cancel a postinstall action while it is running.
330d15c546ed794293d0a63770467a0f3c4c84c6214Alex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootCancelPostinstallActionTest) {
331d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
332d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo
333d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  // Wait for the action to start and then cancel it.
334d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  CancelWhenStarted();
335d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  RunPosinstallAction(loop.dev(), "bin/postinst_suspend", false);
336d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  // When canceling the action, the action never finished and therefore we had
337d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo  // a ProcessingStopped call instead.
3380d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_FALSE(processor_delegate_.code_set_);
3390d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_TRUE(processor_delegate_.processing_stopped_called_);
3400d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo}
3410d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
3420d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo// Test that we parse and process the progress reports from the progress
3430d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo// file descriptor.
3440d29854cf5bb05a22cf161b50052539aa420a36eAlex DeymoTEST_F(PostinstallRunnerActionTest, RunAsRootProgressUpdatesTest) {
3450d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  testing::StrictMock<MockPostinstallRunnerActionDelegate> mock_delegate_;
3460d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  testing::InSequence s;
3470d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_CALL(mock_delegate_, ProgressUpdate(0));
3480d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
3490d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  // The postinst_progress program will call with 0.25, 0.5 and 1.
3500d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_CALL(mock_delegate_, ProgressUpdate(0.25));
3510d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_CALL(mock_delegate_, ProgressUpdate(0.5));
3520d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_CALL(mock_delegate_, ProgressUpdate(1.));
3530d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
3540d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_CALL(mock_delegate_, ProgressUpdate(1.));
3550d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo
3560d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  ScopedLoopbackDeviceBinder loop(postinstall_image_, false, nullptr);
3570d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  setup_action_delegate_ = &mock_delegate_;
3580d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  RunPosinstallAction(loop.dev(), "bin/postinst_progress", false);
3590d29854cf5bb05a22cf161b50052539aa420a36eAlex Deymo  EXPECT_EQ(ErrorCode::kSuccess, processor_delegate_.code_);
360d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo}
361d15c546ed794293d0a63770467a0f3c4c84c6214Alex Deymo
3623defe6acb3609e70e851a6eff062577d25a2af9dadlr@google.com}  // namespace chromeos_update_engine
363