blob: a1da8fc8db49604967c73cc0cae74cb6ccb75c49 [file] [log] [blame]
// Copyright 2016 The Chromium 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 "components/arc/standalone/service_helper.h"
#include <signal.h>
#include <unistd.h>
#include <memory>
#include "base/bind.h"
#include "base/macros.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/test/launcher/unit_test_launcher.h"
#include "base/test/test_suite.h"
#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace arc {
class ServiceHelperTest : public ::testing::Test {
public:
ServiceHelperTest() {}
~ServiceHelperTest() override {}
void Quit() {
CHECK(base_loop_);
CHECK(run_loop_);
base_loop_->PostTask(FROM_HERE, run_loop_->QuitClosure());
}
void Init() {
// Dynamically create the message loop to avoid thread check failure of task
// runner in Debug mode.
base_loop_.reset(new base::MessageLoopForIO());
run_loop_.reset(new base::RunLoop());
// This cannot be put inside SetUp() because we need to run it after fork().
helper_.reset(new ServiceHelper());
helper_->Init(base::Bind(&ServiceHelperTest::Quit,
base::Unretained(this)));
}
protected:
std::unique_ptr<base::MessageLoopForIO> base_loop_;
std::unique_ptr<base::RunLoop> run_loop_;
std::unique_ptr<ServiceHelper> helper_;
private:
DISALLOW_COPY_AND_ASSIGN(ServiceHelperTest);
};
TEST_F(ServiceHelperTest, CheckExternalTerm) {
// Fork ourselves and run it.
pid_t child_pid = fork();
if (child_pid == 0) { // Child process
Init();
run_loop_->Run();
helper_.reset(); // Make sure ServiceHelper dtor does not crash.
_Exit(EXIT_SUCCESS);
} else if (child_pid == -1) { // Failed to fork
FAIL();
} else { // Parent process
// Deliberate race. If ServiceHelper had bugs and stalled, the short
// timeout would kill forked process and stop the test. In that case
// there will be a crash from improperly terminated message loop
// and we shall capture the error.
base::PlatformThread::Sleep(base::TimeDelta::FromSeconds(1));
kill(child_pid, SIGTERM);
int status;
ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
ASSERT_TRUE(WIFEXITED(status));
}
}
} // namespace arc
int main(int argc, char** argv) {
base::TestSuite test_suite(argc, argv);
return base::LaunchUnitTestsSerially(
argc, argv,
base::Bind(&base::TestSuite::Run, base::Unretained(&test_suite)));
}