Home | History | Annotate | Download | only in process_proxy
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include <gtest/gtest.h>
      6 
      7 #include <string>
      8 #include <sys/wait.h>
      9 
     10 #include "base/bind.h"
     11 #include "base/memory/scoped_ptr.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "base/posix/eintr_wrapper.h"
     14 #include "base/process/kill.h"
     15 #include "base/synchronization/waitable_event.h"
     16 #include "base/threading/thread.h"
     17 #include "chromeos/process_proxy/process_proxy_registry.h"
     18 
     19 namespace chromeos {
     20 
     21 namespace {
     22 
     23 // The test line must have all distinct characters.
     24 const char kTestLineToSend[] = "abcdefgh\n";
     25 const char kTestLineExpected[] = "abcdefgh\r\n";
     26 
     27 const char kCatCommand[] = "cat";
     28 const char kStdoutType[] = "stdout";
     29 const int kTestLineNum = 100;
     30 
     31 class TestRunner {
     32  public:
     33   virtual ~TestRunner() {}
     34   virtual void SetupExpectations(pid_t pid) = 0;
     35   virtual void OnSomeRead(pid_t pid, const std::string& type,
     36                           const std::string& output) = 0;
     37   virtual void StartRegistryTest(ProcessProxyRegistry* registry) = 0;
     38 
     39  protected:
     40   pid_t pid_;
     41 };
     42 
     43 class RegistryTestRunner : public TestRunner {
     44  public:
     45   virtual ~RegistryTestRunner() {}
     46 
     47   virtual void SetupExpectations(pid_t pid) OVERRIDE {
     48     pid_ = pid;
     49     left_to_check_index_[0] = 0;
     50     left_to_check_index_[1] = 0;
     51     // We consider that a line processing has started if a value in
     52     // left_to_check__[index] is set to 0, thus -2.
     53     lines_left_ = 2 * kTestLineNum - 2;
     54     expected_line_ = kTestLineExpected;
     55   }
     56 
     57   // Method to test validity of received input. We will receive two streams of
     58   // the same data. (input will be echoed twice by the testing process). Each
     59   // stream will contain the same string repeated |kTestLineNum| times. So we
     60   // have to match 2 * |kTestLineNum| lines. The problem is the received lines
     61   // from different streams may be interleaved (e.g. we may receive
     62   // abc|abcdef|defgh|gh). To deal with that, we allow to test received text
     63   // against two lines. The lines MUST NOT have two same characters for this
     64   // algorithm to work.
     65   virtual void OnSomeRead(pid_t pid, const std::string& type,
     66                           const std::string& output) OVERRIDE {
     67     EXPECT_EQ(type, kStdoutType);
     68     EXPECT_EQ(pid_, pid);
     69 
     70     bool valid = true;
     71     for (size_t i = 0; i < output.length(); i++) {
     72       // The character output[i] should be next in at least one of the lines we
     73       // are testing.
     74       valid = (ProcessReceivedCharacter(output[i], 0) ||
     75                ProcessReceivedCharacter(output[i], 1));
     76       EXPECT_TRUE(valid) << "Received: " << output;
     77     }
     78 
     79     if (!valid || TestSucceeded()) {
     80       base::MessageLoop::current()->PostTask(FROM_HERE,
     81                                              base::MessageLoop::QuitClosure());
     82     }
     83   }
     84 
     85   virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE {
     86     for (int i = 0; i < kTestLineNum; i++) {
     87       EXPECT_TRUE(registry->SendInput(pid_, kTestLineToSend));
     88     }
     89   }
     90 
     91  private:
     92   bool ProcessReceivedCharacter(char received, size_t stream) {
     93     if (stream >= arraysize(left_to_check_index_))
     94       return false;
     95     bool success = left_to_check_index_[stream] < expected_line_.length() &&
     96         expected_line_[left_to_check_index_[stream]] == received;
     97     if (success)
     98       left_to_check_index_[stream]++;
     99     if (left_to_check_index_[stream] == expected_line_.length() &&
    100         lines_left_ > 0) {
    101       // Take another line to test for this stream, if there are any lines left.
    102       // If not, this stream is done.
    103       left_to_check_index_[stream] = 0;
    104       lines_left_--;
    105     }
    106     return success;
    107   }
    108 
    109   bool TestSucceeded() {
    110     return left_to_check_index_[0] == expected_line_.length() &&
    111         left_to_check_index_[1] == expected_line_.length() &&
    112         lines_left_ == 0;
    113   }
    114 
    115   size_t left_to_check_index_[2];
    116   size_t lines_left_;
    117   std::string expected_line_;
    118 };
    119 
    120 class RegistryNotifiedOnProcessExitTestRunner : public TestRunner {
    121  public:
    122   virtual ~RegistryNotifiedOnProcessExitTestRunner() {}
    123 
    124   virtual void SetupExpectations(pid_t pid) OVERRIDE {
    125     output_received_ = false;
    126     pid_ = pid;
    127   }
    128 
    129   virtual void OnSomeRead(pid_t pid, const std::string& type,
    130                           const std::string& output) OVERRIDE {
    131     EXPECT_EQ(pid_, pid);
    132     if (!output_received_) {
    133       output_received_ = true;
    134       EXPECT_EQ(type, "stdout");
    135       EXPECT_EQ(output, "p");
    136       base::KillProcess(pid_, 0 , true);
    137       return;
    138     }
    139     EXPECT_EQ("exit", type);
    140     base::MessageLoop::current()->PostTask(FROM_HERE,
    141                                            base::MessageLoop::QuitClosure());
    142   }
    143 
    144   virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE {
    145     EXPECT_TRUE(registry->SendInput(pid_, "p"));
    146   }
    147 
    148  private:
    149   bool output_received_;
    150 };
    151 
    152 class SigIntTestRunner : public TestRunner {
    153  public:
    154   virtual ~SigIntTestRunner() {}
    155 
    156   virtual void SetupExpectations(pid_t pid) OVERRIDE {
    157     pid_ = pid;
    158   }
    159 
    160   virtual void OnSomeRead(pid_t pid, const std::string& type,
    161                           const std::string& output) OVERRIDE {
    162     EXPECT_EQ(pid_, pid);
    163     // We may receive ^C on stdout, but we don't care about that, as long as we
    164     // eventually received exit event.
    165     if (type == "exit") {
    166       base::MessageLoop::current()->PostTask(FROM_HERE,
    167                                              base::MessageLoop::QuitClosure());
    168     }
    169   }
    170 
    171   virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE {
    172     // Send SingInt and verify the process exited.
    173     EXPECT_TRUE(registry->SendInput(pid_, "\003"));
    174   }
    175 };
    176 
    177 }  // namespace
    178 
    179 class ProcessProxyTest : public testing::Test {
    180  public:
    181   ProcessProxyTest() {}
    182   virtual ~ProcessProxyTest() {}
    183 
    184  protected:
    185   void InitRegistryTest() {
    186     registry_ = ProcessProxyRegistry::Get();
    187 
    188     EXPECT_TRUE(registry_->OpenProcess(
    189                     kCatCommand, &pid_,
    190                     base::Bind(&TestRunner::OnSomeRead,
    191                                base::Unretained(test_runner_.get()))));
    192 
    193     test_runner_->SetupExpectations(pid_);
    194     test_runner_->StartRegistryTest(registry_);
    195   }
    196 
    197   void EndRegistryTest() {
    198     registry_->CloseProcess(pid_);
    199 
    200     base::TerminationStatus status = base::GetTerminationStatus(pid_, NULL);
    201     EXPECT_NE(base::TERMINATION_STATUS_STILL_RUNNING, status);
    202     if (status == base::TERMINATION_STATUS_STILL_RUNNING)
    203       base::KillProcess(pid_, 0, true);
    204 
    205     base::MessageLoop::current()->PostTask(FROM_HERE,
    206                                            base::MessageLoop::QuitClosure());
    207   }
    208 
    209   void RunTest() {
    210     base::MessageLoop::current()->PostTask(
    211         FROM_HERE,
    212         base::Bind(&ProcessProxyTest::InitRegistryTest,
    213                    base::Unretained(this)));
    214 
    215     // Wait until all data from output watcher is received (QuitTask will be
    216     // fired on watcher thread).
    217     base::MessageLoop::current()->Run();
    218 
    219     base::MessageLoop::current()->PostTask(
    220         FROM_HERE,
    221         base::Bind(&ProcessProxyTest::EndRegistryTest,
    222                    base::Unretained(this)));
    223 
    224     // Wait until we clean up the process proxy.
    225     base::MessageLoop::current()->Run();
    226   }
    227 
    228   scoped_ptr<TestRunner> test_runner_;
    229 
    230  private:
    231   ProcessProxyRegistry* registry_;
    232   pid_t pid_;
    233 
    234   base::MessageLoop message_loop_;
    235 };
    236 
    237 // Test will open new process that will run cat command, and verify data we
    238 // write to process gets echoed back.
    239 TEST_F(ProcessProxyTest, RegistryTest) {
    240   test_runner_.reset(new RegistryTestRunner());
    241   RunTest();
    242 }
    243 
    244 // Open new process, then kill it. Verifiy that we detect when the process dies.
    245 TEST_F(ProcessProxyTest, RegistryNotifiedOnProcessExit) {
    246   test_runner_.reset(new RegistryNotifiedOnProcessExitTestRunner());
    247   RunTest();
    248 }
    249 
    250 // Test verifies that \003 message send to process is processed as SigInt.
    251 // Timing out on the waterfall: http://crbug.com/115064
    252 TEST_F(ProcessProxyTest, DISABLED_SigInt) {
    253   test_runner_.reset(new SigIntTestRunner());
    254   RunTest();
    255 }
    256 
    257 }  // namespace chromeos
    258