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
29using base::Bind;
30using base::Callback;
31using base::CancelableClosure;
32using base::Closure;
33using base::Unretained;
34using std::string;
35using std::vector;
36using testing::_;
37using testing::DoAll;
38using testing::Return;
39using testing::SetArgumentPointee;
40using testing::StrEq;
41
42namespace shill {
43
44class 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
113MATCHER_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
126TEST_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
137TEST_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
149TEST_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
190TEST_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
219TEST_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
251TEST_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