Home | History | Annotate | Download | only in shill
      1 //
      2 // Copyright (C) 2015 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 "shill/process_manager.h"
     18 
     19 #include <string>
     20 #include <vector>
     21 
     22 #include <base/bind.h>
     23 #include <brillo/minijail/mock_minijail.h>
     24 #include <gmock/gmock.h>
     25 #include <gtest/gtest.h>
     26 
     27 #include "shill/mock_event_dispatcher.h"
     28 
     29 using base::Bind;
     30 using base::Callback;
     31 using base::CancelableClosure;
     32 using base::Closure;
     33 using base::Unretained;
     34 using std::string;
     35 using std::vector;
     36 using testing::_;
     37 using testing::DoAll;
     38 using testing::Return;
     39 using testing::SetArgumentPointee;
     40 using testing::StrEq;
     41 
     42 namespace shill {
     43 
     44 class ProcessManagerTest : public testing::Test {
     45  public:
     46   ProcessManagerTest() : process_manager_(ProcessManager::GetInstance()) {}
     47 
     48   virtual void SetUp() {
     49     process_manager_->dispatcher_ = &dispatcher_;
     50     process_manager_->minijail_ = &minijail_;
     51   }
     52 
     53   virtual void TearDown() {
     54     process_manager_->watched_processes_.clear();
     55     process_manager_->pending_termination_processes_.clear();
     56   }
     57 
     58   void AddWatchedProcess(pid_t pid, const Callback<void(int)>& callback) {
     59     process_manager_->watched_processes_.emplace(pid, callback);
     60   }
     61 
     62   void AddTerminateProcess(pid_t pid,
     63                            std::unique_ptr<CancelableClosure> timeout_handler) {
     64     process_manager_->pending_termination_processes_.emplace(
     65         pid, std::move(timeout_handler));
     66   }
     67 
     68   void AssertEmptyWatchedProcesses() {
     69     EXPECT_TRUE(process_manager_->watched_processes_.empty());
     70   }
     71 
     72   void AssertNonEmptyWatchedProcesses() {
     73     EXPECT_FALSE(process_manager_->watched_processes_.empty());
     74   }
     75 
     76   void AssertEmptyTerminateProcesses() {
     77     EXPECT_TRUE(process_manager_->pending_termination_processes_.empty());
     78   }
     79 
     80   void OnProcessExited(pid_t pid, int exit_status) {
     81     siginfo_t info;
     82     info.si_status = exit_status;
     83     process_manager_->OnProcessExited(pid, info);
     84   }
     85 
     86   void OnTerminationTimeout(pid_t pid, bool kill_signal) {
     87     process_manager_->ProcessTerminationTimeoutHandler(pid, kill_signal);
     88   }
     89 
     90  protected:
     91   class CallbackObserver {
     92    public:
     93     CallbackObserver()
     94         : exited_callback_(
     95               Bind(&CallbackObserver::OnProcessExited, Unretained(this))),
     96           termination_timeout_callback_(
     97               Bind(&CallbackObserver::OnTerminationTimeout,
     98                    Unretained(this))) {}
     99     virtual ~CallbackObserver() {}
    100 
    101     MOCK_METHOD1(OnProcessExited, void(int exit_status));
    102     MOCK_METHOD0(OnTerminationTimeout, void());
    103 
    104     Callback<void(int)> exited_callback_;
    105     Closure termination_timeout_callback_;
    106   };
    107 
    108   MockEventDispatcher dispatcher_;
    109   brillo::MockMinijail minijail_;
    110   ProcessManager* process_manager_;
    111 };
    112 
    113 MATCHER_P2(IsProcessArgs, program, args, "") {
    114   if (string(arg[0]) != program) {
    115     return false;
    116   }
    117   int index = 1;
    118   for (const auto& option : args) {
    119     if (string(arg[index++]) != option) {
    120       return false;
    121     }
    122   }
    123   return arg[index] == nullptr;
    124 }
    125 
    126 TEST_F(ProcessManagerTest, WatchedProcessExited) {
    127   const pid_t kPid = 123;
    128   const int kExitStatus = 1;
    129   CallbackObserver observer;
    130   AddWatchedProcess(kPid, observer.exited_callback_);
    131 
    132   EXPECT_CALL(observer, OnProcessExited(kExitStatus)).Times(1);
    133   OnProcessExited(kPid, kExitStatus);
    134   AssertEmptyWatchedProcesses();
    135 }
    136 
    137 TEST_F(ProcessManagerTest, TerminateProcessExited) {
    138   const pid_t kPid = 123;
    139   CallbackObserver observer;
    140   std::unique_ptr<CancelableClosure> timeout_handler(
    141       new CancelableClosure(observer.termination_timeout_callback_));
    142   AddTerminateProcess(kPid, std::move(timeout_handler));
    143 
    144   EXPECT_CALL(observer, OnTerminationTimeout()).Times(0);
    145   OnProcessExited(kPid, 1);
    146   AssertEmptyTerminateProcesses();
    147 }
    148 
    149 TEST_F(ProcessManagerTest,
    150        StartProcessInMinijailWithPipesReturnsPidAndWatchesChild) {
    151   const string kProgram = "/usr/bin/dump";
    152   const vector<string> kArgs = { "-b", "-g" };
    153   const string kUser = "user";
    154   const string kGroup = "group";
    155   const uint64_t kCapMask = 1;
    156   const pid_t kPid = 123;
    157   int stdin_fd;
    158   int stdout_fd;
    159   int stderr_fd;
    160 
    161   EXPECT_CALL(minijail_, DropRoot(_, StrEq(kUser), StrEq(kGroup)))
    162       .WillOnce(Return(true));
    163 #if !defined(__ANDROID__)
    164   EXPECT_CALL(minijail_, UseCapabilities(_, kCapMask)).Times(1);
    165 #endif  // __ANDROID__
    166   EXPECT_CALL(minijail_,
    167               RunPipesAndDestroy(_,  // minijail*
    168                                  IsProcessArgs(kProgram, kArgs),
    169                                  _,  // pid_t*
    170                                  &stdin_fd,
    171                                  &stdout_fd,
    172                                  &stderr_fd))
    173       .WillOnce(DoAll(SetArgumentPointee<2>(kPid), Return(true)));
    174   pid_t actual_pid =
    175       process_manager_->StartProcessInMinijailWithPipes(
    176           FROM_HERE,
    177           base::FilePath(kProgram),
    178           kArgs,
    179           kUser,
    180           kGroup,
    181           kCapMask,
    182           Callback<void(int)>(),
    183           &stdin_fd,
    184           &stdout_fd,
    185           &stderr_fd);
    186   EXPECT_EQ(kPid, actual_pid);
    187   AssertNonEmptyWatchedProcesses();
    188 }
    189 
    190 TEST_F(ProcessManagerTest,
    191        StartProcessInMinijailWithPipesHandlesFailureOfDropRoot) {
    192   const string kProgram = "/usr/bin/dump";
    193   const vector<string> kArgs = { "-b", "-g" };
    194   const string kUser = "user";
    195   const string kGroup = "group";
    196   const uint64_t kCapMask = 1;
    197 
    198   EXPECT_CALL(minijail_, DropRoot(_, StrEq(kUser), StrEq(kGroup)))
    199       .WillOnce(Return(false));
    200   EXPECT_CALL(minijail_,
    201               RunPipesAndDestroy(_, IsProcessArgs(kProgram, kArgs), _, _, _, _))
    202       .Times(0);
    203   pid_t actual_pid =
    204       process_manager_->StartProcessInMinijailWithPipes(
    205           FROM_HERE,
    206           base::FilePath(kProgram),
    207           kArgs,
    208           kUser,
    209           kGroup,
    210           kCapMask,
    211           Callback<void(int)>(),
    212           nullptr,
    213           nullptr,
    214           nullptr);
    215   EXPECT_EQ(-1, actual_pid);
    216   AssertEmptyWatchedProcesses();
    217 }
    218 
    219 TEST_F(ProcessManagerTest,
    220        StartProcessInMinijailWithPipesHandlesFailureOfRunAndDestroy) {
    221   const string kProgram = "/usr/bin/dump";
    222   const vector<string> kArgs = { "-b", "-g" };
    223   const string kUser = "user";
    224   const string kGroup = "group";
    225   const uint64_t kCapMask = 1;
    226 
    227   EXPECT_CALL(minijail_, DropRoot(_, StrEq(kUser), StrEq(kGroup)))
    228       .WillOnce(Return(true));
    229 #if !defined(__ANDROID__)
    230   EXPECT_CALL(minijail_, UseCapabilities(_, kCapMask)).Times(1);
    231 #endif  // __ANDROID__
    232   EXPECT_CALL(minijail_,
    233               RunPipesAndDestroy(_, IsProcessArgs(kProgram, kArgs), _, _, _, _))
    234       .WillOnce(Return(false));
    235   pid_t actual_pid =
    236       process_manager_->StartProcessInMinijailWithPipes(
    237           FROM_HERE,
    238           base::FilePath(kProgram),
    239           kArgs,
    240           kUser,
    241           kGroup,
    242           kCapMask,
    243           Callback<void(int)>(),
    244           nullptr,
    245           nullptr,
    246           nullptr);
    247   EXPECT_EQ(-1, actual_pid);
    248   AssertEmptyWatchedProcesses();
    249 }
    250 
    251 TEST_F(ProcessManagerTest, UpdateExitCallbackUpdatesCallback) {
    252   const pid_t kPid = 123;
    253   const int kExitStatus = 1;
    254   CallbackObserver original_observer;
    255   AddWatchedProcess(kPid, original_observer.exited_callback_);
    256 
    257   CallbackObserver new_observer;
    258   EXPECT_CALL(original_observer, OnProcessExited(_)).Times(0);
    259   EXPECT_TRUE(process_manager_->UpdateExitCallback(
    260       kPid,
    261       new_observer.exited_callback_));
    262   EXPECT_CALL(new_observer, OnProcessExited(_)).Times(1);
    263   OnProcessExited(kPid, kExitStatus);
    264 }
    265 
    266 }  // namespace shill
    267