[go: nahoru, domu]

blob: 8e4c166516edf6f00052feb5890e7b9cb81a3bc1 [file] [log] [blame]
tbarzic@chromium.orga504ba72012-01-25 01:42:571// Copyright (c) 2012 The Chromium Authors. All rights reserved.
tbarzic@chromium.org8f427982011-12-13 23:40:232// 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 <queue>
8#include <string>
9#include <vector>
10
tbarzic@chromium.org8f427982011-12-13 23:40:2311#include "base/bind.h"
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3712#include "base/callback.h"
tbarzic@chromium.org8f427982011-12-13 23:40:2313#include "base/file_util.h"
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3714#include "base/message_loop/message_loop.h"
brettw@chromium.org2025d002012-11-14 20:54:3515#include "base/posix/eintr_wrapper.h"
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3716#include "base/run_loop.h"
17#include "base/strings/string_util.h"
tbarzic@chromium.org8f427982011-12-13 23:40:2318#include "base/threading/thread.h"
phajdan.jr@chromium.org3a01162b2013-03-12 20:22:4819#include "chromeos/process_proxy/process_output_watcher.h"
20
21namespace chromeos {
tbarzic@chromium.org8f427982011-12-13 23:40:2322
23struct TestCase {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3724 TestCase(const std::string& input, bool send_terminating_null)
25 : input(input),
26 should_send_terminating_null(send_terminating_null),
27 expected_output(input) {}
tbarzic@chromium.org8f427982011-12-13 23:40:2328
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3729 // Conctructor for cases where the output is not expected to be the same as
30 // input.
31 TestCase(const std::string& input,
32 bool send_terminating_null,
33 const std::string& expected_output)
34 : input(input),
35 should_send_terminating_null(send_terminating_null),
36 expected_output(expected_output) {}
37
38 std::string input;
39 bool should_send_terminating_null;
40 std::string expected_output;
tbarzic@chromium.org8f427982011-12-13 23:40:2341};
42
43class ProcessWatcherExpectations {
44 public:
45 ProcessWatcherExpectations() {}
46
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3747 void SetTestCase(const TestCase& test_case) {
tbarzic@chromium.org8f427982011-12-13 23:40:2348 received_from_out_ = 0;
tbarzic@chromium.org8f427982011-12-13 23:40:2349
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3750 out_expectations_ = test_case.expected_output;
51 if (test_case.should_send_terminating_null)
52 out_expectations_.append(std::string("", 1));
tbarzic@chromium.org8f427982011-12-13 23:40:2353 }
54
tbarzic@chromium.org6866c6b2012-04-09 21:38:1855 bool CheckExpectations(const std::string& data, ProcessOutputType type) {
56 EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT, type);
thakis@chromium.orge2524b02013-07-22 17:51:2857 if (type != PROCESS_OUTPUT_TYPE_OUT)
tbarzic@chromium.org6866c6b2012-04-09 21:38:1858 return false;
tbarzic@chromium.org8f427982011-12-13 23:40:2359
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3760 if (out_expectations_.length() == 0 && data.length() == 0)
61 return true;
62
tbarzic@chromium.org6866c6b2012-04-09 21:38:1863 EXPECT_LT(received_from_out_, out_expectations_.length());
64 if (received_from_out_ >= out_expectations_.length())
65 return false;
tbarzic@chromium.org8f427982011-12-13 23:40:2366
tbarzic@chromium.org6866c6b2012-04-09 21:38:1867 EXPECT_EQ(received_from_out_,
68 out_expectations_.find(data, received_from_out_));
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3769 if (received_from_out_ != out_expectations_.find(data, received_from_out_))
70 return false;
tbarzic@chromium.org8f427982011-12-13 23:40:2371
tbarzic@chromium.org6866c6b2012-04-09 21:38:1872 received_from_out_ += data.length();
73 return true;
tbarzic@chromium.org8f427982011-12-13 23:40:2374 }
75
76 bool IsDone() {
tbarzic@chromium.org6866c6b2012-04-09 21:38:1877 return received_from_out_ >= out_expectations_.length();
tbarzic@chromium.org8f427982011-12-13 23:40:2378 }
79
80 private:
81 std::string out_expectations_;
82 size_t received_from_out_;
tbarzic@chromium.org8f427982011-12-13 23:40:2383};
84
85class ProcessOutputWatcherTest : public testing::Test {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3786 public:
87 ProcessOutputWatcherTest() : output_watch_thread_started_(false),
88 failed_(false) {
89 }
tbarzic@chromium.org8f427982011-12-13 23:40:2390
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3791 virtual ~ProcessOutputWatcherTest() {}
92
93 virtual void TearDown() OVERRIDE {
94 if (output_watch_thread_started_)
95 output_watch_thread_->Stop();
96 }
97
98 void StartWatch(int pt, int stop) {
tbarzic@chromium.org8f427982011-12-13 23:40:2399 // This will delete itself.
tbarzic@chromium.orga504ba72012-01-25 01:42:57100 ProcessOutputWatcher* crosh_watcher = new ProcessOutputWatcher(pt, stop,
tbarzic@chromium.org8f427982011-12-13 23:40:23101 base::Bind(&ProcessOutputWatcherTest::OnRead, base::Unretained(this)));
102 crosh_watcher->Start();
103 }
104
105 void OnRead(ProcessOutputType type, const std::string& output) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37106 ASSERT_FALSE(failed_);
107 failed_ = !expectations_.CheckExpectations(output, type);
108 if (failed_ || expectations_.IsDone()) {
109 ASSERT_FALSE(test_case_done_callback_.is_null());
110 message_loop_.PostTask(FROM_HERE, test_case_done_callback_);
111 test_case_done_callback_.Reset();
112 }
tbarzic@chromium.org8f427982011-12-13 23:40:23113 }
114
115 protected:
116 std::string VeryLongString() {
117 std::string result = "0123456789";
118 for (int i = 0; i < 8; i++)
119 result = result.append(result);
120 return result;
121 }
122
tbarzic@chromium.org250f7f892012-04-11 02:46:43123 void RunTest(const std::vector<TestCase>& test_cases) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37124 ASSERT_FALSE(output_watch_thread_started_);
125 output_watch_thread_.reset(new base::Thread("ProcessOutpuWatchThread"));
126 output_watch_thread_started_ = output_watch_thread_->Start();
127 ASSERT_TRUE(output_watch_thread_started_);
tbarzic@chromium.org250f7f892012-04-11 02:46:43128
129 int pt_pipe[2], stop_pipe[2];
130 ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe)));
131 ASSERT_FALSE(HANDLE_EINTR(pipe(stop_pipe)));
132
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37133 output_watch_thread_->message_loop()->PostTask(
134 FROM_HERE,
tbarzic@chromium.org250f7f892012-04-11 02:46:43135 base::Bind(&ProcessOutputWatcherTest::StartWatch,
136 base::Unretained(this),
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37137 pt_pipe[0],
138 stop_pipe[0]));
tbarzic@chromium.org250f7f892012-04-11 02:46:43139
140 for (size_t i = 0; i < test_cases.size(); i++) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37141 expectations_.SetTestCase(test_cases[i]);
142
143 base::RunLoop run_loop;
144 ASSERT_TRUE(test_case_done_callback_.is_null());
145 test_case_done_callback_ = run_loop.QuitClosure();
146
147 const std::string& test_str = test_cases[i].input;
tbarzic@chromium.org250f7f892012-04-11 02:46:43148 // Let's make inputs not NULL terminated, unless other is specified in
149 // the test case.
150 ssize_t test_size = test_str.length() * sizeof(*test_str.c_str());
151 if (test_cases[i].should_send_terminating_null)
152 test_size += sizeof(*test_str.c_str());
153 EXPECT_EQ(test_size,
brettw@chromium.orge5c2a22e2014-03-06 20:42:30154 base::WriteFileDescriptor(pt_pipe[1], test_str.c_str(),
155 test_size));
tbarzic@chromium.org250f7f892012-04-11 02:46:43156
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37157 run_loop.Run();
158 EXPECT_TRUE(expectations_.IsDone());
159 if (failed_)
160 break;
161 }
tbarzic@chromium.org250f7f892012-04-11 02:46:43162
163 // Send stop signal. It is not important which string we send.
brettw@chromium.orge5c2a22e2014-03-06 20:42:30164 EXPECT_EQ(1, base::WriteFileDescriptor(stop_pipe[1], "q", 1));
tbarzic@chromium.org250f7f892012-04-11 02:46:43165
mark@chromium.orgd89eec82013-12-03 14:10:59166 EXPECT_NE(-1, IGNORE_EINTR(close(stop_pipe[1])));
167 EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe[1])));
tbarzic@chromium.org250f7f892012-04-11 02:46:43168 }
169
tbarzic@chromium.org8f427982011-12-13 23:40:23170 private:
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37171 base::Closure test_case_done_callback_;
172 base::MessageLoop message_loop_;
173 scoped_ptr<base::Thread> output_watch_thread_;
174 bool output_watch_thread_started_;
175 bool failed_;
tbarzic@chromium.org8f427982011-12-13 23:40:23176 ProcessWatcherExpectations expectations_;
177 std::vector<TestCase> exp;
178};
179
180
181TEST_F(ProcessOutputWatcherTest, OutputWatcher) {
tbarzic@chromium.org8f427982011-12-13 23:40:23182 std::vector<TestCase> test_cases;
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37183 test_cases.push_back(TestCase("t", false));
tbarzic@chromium.org250f7f892012-04-11 02:46:43184 test_cases.push_back(TestCase("testing output\n", false));
185 test_cases.push_back(TestCase("testing error\n", false));
186 test_cases.push_back(TestCase("testing error1\n", false));
187 test_cases.push_back(TestCase("testing output1\n", false));
188 test_cases.push_back(TestCase("testing output2\n", false));
189 test_cases.push_back(TestCase("testing output3\n", false));
190 test_cases.push_back(TestCase(VeryLongString(), false));
191 test_cases.push_back(TestCase("testing error2\n", false));
tbarzic@chromium.org8f427982011-12-13 23:40:23192
tbarzic@chromium.org250f7f892012-04-11 02:46:43193 RunTest(test_cases);
tbarzic@chromium.org8f427982011-12-13 23:40:23194};
195
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37196TEST_F(ProcessOutputWatcherTest, SplitUTF8Character) {
197 std::vector<TestCase> test_cases;
198 test_cases.push_back(TestCase("test1\xc2", false, "test1"));
199 test_cases.push_back(TestCase("\xb5test1", false, "\xc2\xb5test1"));
200
201 RunTest(test_cases);
202}
203
204TEST_F(ProcessOutputWatcherTest, SplitSoleUTF8Character) {
205 std::vector<TestCase> test_cases;
206 test_cases.push_back(TestCase("\xc2", false, ""));
207 test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
208
209 RunTest(test_cases);
210}
211
212TEST_F(ProcessOutputWatcherTest, SplitUTF8CharacterLength3) {
213 std::vector<TestCase> test_cases;
214 test_cases.push_back(TestCase("test3\xe2\x82", false, "test3"));
215 test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
216
217 RunTest(test_cases);
218}
219
220TEST_F(ProcessOutputWatcherTest, SplitSoleUTF8CharacterThreeWays) {
221 std::vector<TestCase> test_cases;
222 test_cases.push_back(TestCase("\xe2", false, ""));
223 test_cases.push_back(TestCase("\x82", false, ""));
224 test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
225
226 RunTest(test_cases);
227}
228
229TEST_F(ProcessOutputWatcherTest, EndsWithThreeByteUTF8Character) {
230 std::vector<TestCase> test_cases;
231 test_cases.push_back(TestCase("test\xe2\x82\xac", false, "test\xe2\x82\xac"));
232
233 RunTest(test_cases);
234}
235
236TEST_F(ProcessOutputWatcherTest, SoleThreeByteUTF8Character) {
237 std::vector<TestCase> test_cases;
238 test_cases.push_back(TestCase("\xe2\x82\xac", false, "\xe2\x82\xac"));
239
240 RunTest(test_cases);
241}
242
243TEST_F(ProcessOutputWatcherTest, HasThreeByteUTF8Character) {
244 std::vector<TestCase> test_cases;
245 test_cases.push_back(
246 TestCase("test\xe2\x82\xac_", false, "test\xe2\x82\xac_"));
247
248 RunTest(test_cases);
249}
250
251TEST_F(ProcessOutputWatcherTest, MulitByteUTF8CharNullTerminated) {
252 std::vector<TestCase> test_cases;
253 test_cases.push_back(TestCase("test\xe2\x82\xac", true, "test\xe2\x82\xac"));
254
255 RunTest(test_cases);
256}
257
258TEST_F(ProcessOutputWatcherTest, MultipleMultiByteUTF8Characters) {
259 std::vector<TestCase> test_cases;
260 test_cases.push_back(
261 TestCase("test\xe2\x82\xac\xc2", false, "test\xe2\x82\xac"));
262 test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
263
264 RunTest(test_cases);
265}
266
267TEST_F(ProcessOutputWatcherTest, ContainsInvalidUTF8) {
268 std::vector<TestCase> test_cases;
269 test_cases.push_back(TestCase("\xc2_", false, "\xc2_"));
270
271 RunTest(test_cases);
272}
273
274TEST_F(ProcessOutputWatcherTest, InvalidUTF8SeriesOfTrailingBytes) {
275 std::vector<TestCase> test_cases;
276 test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
277 test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
278
279 RunTest(test_cases);
280}
281
282TEST_F(ProcessOutputWatcherTest, EndsWithInvalidUTF8) {
283 std::vector<TestCase> test_cases;
284 test_cases.push_back(TestCase("\xff", false, "\xff"));
285
286 RunTest(test_cases);
287}
288
289TEST_F(ProcessOutputWatcherTest, FourByteUTF8) {
290 std::vector<TestCase> test_cases;
291 test_cases.push_back(TestCase("\xf0\xa4\xad", false, ""));
292 test_cases.push_back(TestCase("\xa2", false, "\xf0\xa4\xad\xa2"));
293
294 RunTest(test_cases);
295};
296
tbarzic@chromium.org250f7f892012-04-11 02:46:43297// Verifies that sending '\0' generates PROCESS_OUTPUT_TYPE_OUT event and does
298// not terminate output watcher.
299TEST_F(ProcessOutputWatcherTest, SendNull) {
300 std::vector<TestCase> test_cases;
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37301 // This will send '\0' to output watcher.
tbarzic@chromium.org250f7f892012-04-11 02:46:43302 test_cases.push_back(TestCase("", true));
303 // Let's verify that next input also gets detected (i.e. output watcher does
304 // not exit after seeing '\0' from previous test case).
305 test_cases.push_back(TestCase("a", true));
306
307 RunTest(test_cases);
308};
phajdan.jr@chromium.org3a01162b2013-03-12 20:22:48309
310} // namespace chromeos