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