- add sources.
[platform/framework/web/crosswalk.git] / src / chromeos / process_proxy / process_proxy_unittest.cc
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