diff options
author | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-12 20:22:48 +0000 |
---|---|---|
committer | phajdan.jr@chromium.org <phajdan.jr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-03-12 20:22:48 +0000 |
commit | 3a01162bc4f385c6353a603662721eb95530b526 (patch) | |
tree | 8a46fdd70745d81c24288705f2e1539b64047a5a /chromeos/process_proxy/process_proxy_unittest.cc | |
parent | b0cc590aacd6c9908d154970eabe41cb370c2cbe (diff) | |
download | chromium_src-3a01162bc4f385c6353a603662721eb95530b526.zip chromium_src-3a01162bc4f385c6353a603662721eb95530b526.tar.gz chromium_src-3a01162bc4f385c6353a603662721eb95530b526.tar.bz2 |
Move chrome/browser/chromeos/process_proxy to chromeos
BUG=180711
Review URL: https://codereview.chromium.org/12433023
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@187641 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/process_proxy/process_proxy_unittest.cc')
-rw-r--r-- | chromeos/process_proxy/process_proxy_unittest.cc | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/chromeos/process_proxy/process_proxy_unittest.cc b/chromeos/process_proxy/process_proxy_unittest.cc new file mode 100644 index 0000000..ad0ba4b --- /dev/null +++ b/chromeos/process_proxy/process_proxy_unittest.cc @@ -0,0 +1,257 @@ +// Copyright (c) 2012 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 <gtest/gtest.h> + +#include <string> +#include <sys/wait.h> + +#include "base/bind.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/posix/eintr_wrapper.h" +#include "base/process_util.h" +#include "base/synchronization/waitable_event.h" +#include "base/threading/thread.h" +#include "chromeos/process_proxy/process_proxy_registry.h" + +namespace chromeos { + +namespace { + +// The test line must have all distinct characters. +const char kTestLineToSend[] = "abcdefgh\n"; +const char kTestLineExpected[] = "abcdefgh\r\n"; + +const char kCatCommand[] = "cat"; +const char kStdoutType[] = "stdout"; +const int kTestLineNum = 100; + +class TestRunner { + public: + virtual ~TestRunner() {} + virtual void SetupExpectations(pid_t pid) = 0; + virtual void OnSomeRead(pid_t pid, const std::string& type, + const std::string& output) = 0; + virtual void StartRegistryTest(ProcessProxyRegistry* registry) = 0; + + protected: + pid_t pid_; +}; + +class RegistryTestRunner : public TestRunner { + public: + virtual ~RegistryTestRunner() {} + + virtual void SetupExpectations(pid_t pid) OVERRIDE { + pid_ = pid; + left_to_check_index_[0] = 0; + left_to_check_index_[1] = 0; + // We consider that a line processing has started if a value in + // left_to_check__[index] is set to 0, thus -2. + lines_left_ = 2 * kTestLineNum - 2; + expected_line_ = kTestLineExpected; + } + + // Method to test validity of received input. We will receive two streams of + // the same data. (input will be echoed twice by the testing process). Each + // stream will contain the same string repeated |kTestLineNum| times. So we + // have to match 2 * |kTestLineNum| lines. The problem is the received lines + // from different streams may be interleaved (e.g. we may receive + // abc|abcdef|defgh|gh). To deal with that, we allow to test received text + // against two lines. The lines MUST NOT have two same characters for this + // algorithm to work. + virtual void OnSomeRead(pid_t pid, const std::string& type, + const std::string& output) OVERRIDE { + EXPECT_EQ(type, kStdoutType); + EXPECT_EQ(pid_, pid); + + bool valid = true; + for (size_t i = 0; i < output.length(); i++) { + // The character output[i] should be next in at least one of the lines we + // are testing. + valid = (ProcessReceivedCharacter(output[i], 0) || + ProcessReceivedCharacter(output[i], 1)); + EXPECT_TRUE(valid) << "Received: " << output; + } + + if (!valid || TestSucceeded()) { + MessageLoop::current()->PostTask(FROM_HERE, + MessageLoop::QuitClosure()); + } + } + + virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE { + for (int i = 0; i < kTestLineNum; i++) { + EXPECT_TRUE(registry->SendInput(pid_, kTestLineToSend)); + } + } + + private: + bool ProcessReceivedCharacter(char received, size_t stream) { + if (stream >= arraysize(left_to_check_index_)) + return false; + bool success = left_to_check_index_[stream] < expected_line_.length() && + expected_line_[left_to_check_index_[stream]] == received; + if (success) + left_to_check_index_[stream]++; + if (left_to_check_index_[stream] == expected_line_.length() && + lines_left_ > 0) { + // Take another line to test for this stream, if there are any lines left. + // If not, this stream is done. + left_to_check_index_[stream] = 0; + lines_left_--; + } + return success; + } + + bool TestSucceeded() { + return left_to_check_index_[0] == expected_line_.length() && + left_to_check_index_[1] == expected_line_.length() && + lines_left_ == 0; + } + + size_t left_to_check_index_[2]; + size_t lines_left_; + std::string expected_line_; +}; + +class RegistryNotifiedOnProcessExitTestRunner : public TestRunner { + public: + virtual ~RegistryNotifiedOnProcessExitTestRunner() {} + + virtual void SetupExpectations(pid_t pid) OVERRIDE { + output_received_ = false; + pid_ = pid; + } + + virtual void OnSomeRead(pid_t pid, const std::string& type, + const std::string& output) OVERRIDE { + EXPECT_EQ(pid_, pid); + if (!output_received_) { + output_received_ = true; + EXPECT_EQ(type, "stdout"); + EXPECT_EQ(output, "p"); + base::KillProcess(pid_, 0 , true); + return; + } + EXPECT_EQ("exit", type); + MessageLoop::current()->PostTask(FROM_HERE, + MessageLoop::QuitClosure()); + } + + virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE { + EXPECT_TRUE(registry->SendInput(pid_, "p")); + } + + private: + bool output_received_; +}; + +class SigIntTestRunner : public TestRunner { + public: + virtual ~SigIntTestRunner() {} + + virtual void SetupExpectations(pid_t pid) OVERRIDE { + pid_ = pid; + } + + virtual void OnSomeRead(pid_t pid, const std::string& type, + const std::string& output) OVERRIDE { + EXPECT_EQ(pid_, pid); + // We may receive ^C on stdout, but we don't care about that, as long as we + // eventually received exit event. + if (type == "exit") { + MessageLoop::current()->PostTask(FROM_HERE, + MessageLoop::QuitClosure()); + } + } + + virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE { + // Send SingInt and verify the process exited. + EXPECT_TRUE(registry->SendInput(pid_, "\003")); + } +}; + +} // namespace + +class ProcessProxyTest : public testing::Test { + public: + ProcessProxyTest() {} + virtual ~ProcessProxyTest() {} + + protected: + void InitRegistryTest() { + registry_ = ProcessProxyRegistry::Get(); + + EXPECT_TRUE(registry_->OpenProcess( + kCatCommand, &pid_, + base::Bind(&TestRunner::OnSomeRead, + base::Unretained(test_runner_.get())))); + + test_runner_->SetupExpectations(pid_); + test_runner_->StartRegistryTest(registry_); + } + + void EndRegistryTest() { + registry_->CloseProcess(pid_); + + base::TerminationStatus status = base::GetTerminationStatus(pid_, NULL); + EXPECT_NE(base::TERMINATION_STATUS_STILL_RUNNING, status); + if (status == base::TERMINATION_STATUS_STILL_RUNNING) + base::KillProcess(pid_, 0, true); + + MessageLoop::current()->PostTask(FROM_HERE, + MessageLoop::QuitClosure()); + } + + void RunTest() { + MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&ProcessProxyTest::InitRegistryTest, + base::Unretained(this))); + + // Wait until all data from output watcher is received (QuitTask will be + // fired on watcher thread). + MessageLoop::current()->Run(); + + MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&ProcessProxyTest::EndRegistryTest, + base::Unretained(this))); + + // Wait until we clean up the process proxy. + MessageLoop::current()->Run(); + } + + scoped_ptr<TestRunner> test_runner_; + + private: + ProcessProxyRegistry* registry_; + pid_t pid_; + + MessageLoop message_loop_; +}; + +// Test will open new process that will run cat command, and verify data we +// write to process gets echoed back. +TEST_F(ProcessProxyTest, RegistryTest) { + test_runner_.reset(new RegistryTestRunner()); + RunTest(); +} + +// Open new process, then kill it. Verifiy that we detect when the process dies. +TEST_F(ProcessProxyTest, RegistryNotifiedOnProcessExit) { + test_runner_.reset(new RegistryNotifiedOnProcessExitTestRunner()); + RunTest(); +} + +// Test verifies that \003 message send to process is processed as SigInt. +// Timing out on the waterfall: http://crbug.com/115064 +TEST_F(ProcessProxyTest, DISABLED_SigInt) { + test_runner_.reset(new SigIntTestRunner()); + RunTest(); +} + +} // namespace chromeos |