• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
~TestRunner()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:
~RegistryTestRunner()44   virtual ~RegistryTestRunner() {}
45 
SetupExpectations(pid_t pid)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.
OnSomeRead(pid_t pid,const std::string & type,const std::string & output)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 
StartRegistryTest(ProcessProxyRegistry * registry)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:
ProcessReceivedCharacter(char received,size_t stream)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 
TestSucceeded()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:
~RegistryNotifiedOnProcessExitTestRunner()121   virtual ~RegistryNotifiedOnProcessExitTestRunner() {}
122 
SetupExpectations(pid_t pid)123   virtual void SetupExpectations(pid_t pid) OVERRIDE {
124     output_received_ = false;
125     pid_ = pid;
126   }
127 
OnSomeRead(pid_t pid,const std::string & type,const std::string & output)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 
StartRegistryTest(ProcessProxyRegistry * registry)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:
~SigIntTestRunner()153   virtual ~SigIntTestRunner() {}
154 
SetupExpectations(pid_t pid)155   virtual void SetupExpectations(pid_t pid) OVERRIDE {
156     pid_ = pid;
157   }
158 
OnSomeRead(pid_t pid,const std::string & type,const std::string & output)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 
StartRegistryTest(ProcessProxyRegistry * registry)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:
ProcessProxyTest()180   ProcessProxyTest() {}
~ProcessProxyTest()181   virtual ~ProcessProxyTest() {}
182 
183  protected:
InitRegistryTest()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 
EndRegistryTest()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 
RunTest()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.
TEST_F(ProcessProxyTest,RegistryTest)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.
TEST_F(ProcessProxyTest,RegistryNotifiedOnProcessExit)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
TEST_F(ProcessProxyTest,DISABLED_SigInt)251 TEST_F(ProcessProxyTest, DISABLED_SigInt) {
252   test_runner_.reset(new SigIntTestRunner());
253   RunTest();
254 }
255 
256 }  // namespace chromeos
257