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