• 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 
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:
~TestRunner()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:
~RegistryTestRunner()42   virtual ~RegistryTestRunner() {}
43 
SetupExpectations(pid_t pid)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.
OnSomeRead(pid_t pid,const std::string & type,const std::string & output)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 
StartRegistryTest(ProcessProxyRegistry * registry)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:
ProcessReceivedCharacter(char received,size_t stream)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 
TestSucceeded()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:
~RegistryNotifiedOnProcessExitTestRunner()119   virtual ~RegistryNotifiedOnProcessExitTestRunner() {}
120 
SetupExpectations(pid_t pid)121   virtual void SetupExpectations(pid_t pid) OVERRIDE {
122     output_received_ = false;
123     pid_ = pid;
124   }
125 
OnSomeRead(pid_t pid,const std::string & type,const std::string & output)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 
StartRegistryTest(ProcessProxyRegistry * registry)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:
~SigIntTestRunner()151   virtual ~SigIntTestRunner() {}
152 
SetupExpectations(pid_t pid)153   virtual void SetupExpectations(pid_t pid) OVERRIDE {
154     pid_ = pid;
155   }
156 
OnSomeRead(pid_t pid,const std::string & type,const std::string & output)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 
StartRegistryTest(ProcessProxyRegistry * registry)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:
ProcessProxyTest()178   ProcessProxyTest() {}
~ProcessProxyTest()179   virtual ~ProcessProxyTest() {}
180 
181  protected:
InitRegistryTest()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 
EndRegistryTest()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 
RunTest()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.
TEST_F(ProcessProxyTest,RegistryTest)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.
TEST_F(ProcessProxyTest,RegistryNotifiedOnProcessExit)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
TEST_F(ProcessProxyTest,DISABLED_SigInt)249 TEST_F(ProcessProxyTest, DISABLED_SigInt) {
250   test_runner_.reset(new SigIntTestRunner());
251   RunTest();
252 }
253 
254 }  // namespace chromeos
255