blob: 6684fa94269ffb6622d33e3b17e76cdf192da455 [file] [log] [blame]
// Copyright 2015 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "germ/process_reaper.h"
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <base/at_exit.h>
#include <base/bind.h>
#include <base/location.h>
#include <base/message_loop/message_loop.h>
#include <base/run_loop.h>
#include <gtest/gtest.h>
#include <libchromeos/chromeos/asynchronous_signal_handler.h>
#include "germ/test_util.h"
namespace germ {
namespace {
const int kExitCode = 0x80;
const int kNumToFork = 10;
const int kTestTimeout = 10;
class TestProcessReaper : public ProcessReaper {
public:
TestProcessReaper()
: num_to_reap_(1), expected_code_(-1), expected_status_(-1) {}
~TestProcessReaper() {}
bool PostTask(const tracked_objects::Location& from_here,
const base::Closure& task) {
return message_loop_.task_runner()->PostTask(from_here, task);
}
void Run() {
async_signal_handler_.Init();
RegisterWithAsyncHandler(&async_signal_handler_);
run_loop_.Run();
}
void set_num_to_reap(int num_to_reap) { num_to_reap_ = num_to_reap; }
void set_expected_code(int expected_code) { expected_code_ = expected_code; }
void set_expected_status(int expected_status) {
expected_status_ = expected_status;
}
private:
void HandleReapedChild(const siginfo_t& info) override {
EXPECT_EQ(expected_code_, info.si_code);
EXPECT_EQ(expected_status_, info.si_status);
EXPECT_GT(num_to_reap_, 0);
--num_to_reap_;
if (num_to_reap_ == 0) {
ASSERT_TRUE(PostTask(FROM_HERE, run_loop_.QuitClosure()));
}
}
base::AtExitManager exit_manager_;
int num_to_reap_;
int expected_code_;
int expected_status_;
base::MessageLoopForIO message_loop_;
chromeos::AsynchronousSignalHandler async_signal_handler_;
base::RunLoop run_loop_;
};
void ForkAndExit(int num_to_fork) {
for (int i = 0; i < num_to_fork; ++i) {
pid_t pid = fork();
PCHECK(pid != -1);
if (pid == 0) {
_exit(kExitCode);
}
}
}
void ForkAndRaise(int num_to_fork) {
for (int i = 0; i < num_to_fork; ++i) {
pid_t pid = fork();
PCHECK(pid != -1);
if (pid == 0) {
raise(SIGKILL);
}
}
}
TEST(ProcessReaper, ReapExitedChild) {
ScopedAlarm time_out(kTestTimeout);
TestProcessReaper test_process_reaper;
test_process_reaper.set_num_to_reap(kNumToFork);
test_process_reaper.set_expected_code(CLD_EXITED);
test_process_reaper.set_expected_status(kExitCode);
ASSERT_TRUE(test_process_reaper.PostTask(
FROM_HERE, base::Bind(&ForkAndExit, kNumToFork)));
test_process_reaper.Run();
}
TEST(ProcessReaper, ReapSignaledChild) {
ScopedAlarm time_out(kTestTimeout);
TestProcessReaper test_process_reaper;
test_process_reaper.set_num_to_reap(kNumToFork);
test_process_reaper.set_expected_code(CLD_KILLED);
test_process_reaper.set_expected_status(SIGKILL);
ASSERT_TRUE(test_process_reaper.PostTask(
FROM_HERE, base::Bind(&ForkAndRaise, kNumToFork)));
test_process_reaper.Run();
}
} // namespace
} // namespace germ