[go: nahoru, domu]

blob: 529ba18433bc6a5c580b22fba84f0ef214ea5454 [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"
thestigb44bd352014-09-10 01:47:0613#include "base/files/file_util.h"
skyostil1472c842015-06-11 18:40:2414#include "base/location.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"
skyostil1472c842015-06-11 18:40:2417#include "base/single_thread_task_runner.h"
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3718#include "base/strings/string_util.h"
tbarzic@chromium.org8f427982011-12-13 23:40:2319#include "base/threading/thread.h"
phajdan.jr@chromium.org3a01162b2013-03-12 20:22:4820#include "chromeos/process_proxy/process_output_watcher.h"
21
22namespace chromeos {
tbarzic@chromium.org8f427982011-12-13 23:40:2323
24struct TestCase {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3725 TestCase(const std::string& input, bool send_terminating_null)
26 : input(input),
27 should_send_terminating_null(send_terminating_null),
28 expected_output(input) {}
tbarzic@chromium.org8f427982011-12-13 23:40:2329
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3730 // Conctructor for cases where the output is not expected to be the same as
31 // input.
32 TestCase(const std::string& input,
33 bool send_terminating_null,
34 const std::string& expected_output)
35 : input(input),
36 should_send_terminating_null(send_terminating_null),
37 expected_output(expected_output) {}
38
39 std::string input;
40 bool should_send_terminating_null;
41 std::string expected_output;
tbarzic@chromium.org8f427982011-12-13 23:40:2342};
43
44class ProcessWatcherExpectations {
45 public:
46 ProcessWatcherExpectations() {}
47
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3748 void SetTestCase(const TestCase& test_case) {
tbarzic@chromium.org8f427982011-12-13 23:40:2349 received_from_out_ = 0;
tbarzic@chromium.org8f427982011-12-13 23:40:2350
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3751 out_expectations_ = test_case.expected_output;
52 if (test_case.should_send_terminating_null)
53 out_expectations_.append(std::string("", 1));
tbarzic@chromium.org8f427982011-12-13 23:40:2354 }
55
tbarzic@chromium.org6866c6b2012-04-09 21:38:1856 bool CheckExpectations(const std::string& data, ProcessOutputType type) {
57 EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT, type);
thakis@chromium.orge2524b02013-07-22 17:51:2858 if (type != PROCESS_OUTPUT_TYPE_OUT)
tbarzic@chromium.org6866c6b2012-04-09 21:38:1859 return false;
tbarzic@chromium.org8f427982011-12-13 23:40:2360
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3761 if (out_expectations_.length() == 0 && data.length() == 0)
62 return true;
63
tbarzic@chromium.org6866c6b2012-04-09 21:38:1864 EXPECT_LT(received_from_out_, out_expectations_.length());
65 if (received_from_out_ >= out_expectations_.length())
66 return false;
tbarzic@chromium.org8f427982011-12-13 23:40:2367
tbarzic@chromium.org6866c6b2012-04-09 21:38:1868 EXPECT_EQ(received_from_out_,
69 out_expectations_.find(data, received_from_out_));
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3770 if (received_from_out_ != out_expectations_.find(data, received_from_out_))
71 return false;
tbarzic@chromium.org8f427982011-12-13 23:40:2372
tbarzic@chromium.org6866c6b2012-04-09 21:38:1873 received_from_out_ += data.length();
74 return true;
tbarzic@chromium.org8f427982011-12-13 23:40:2375 }
76
77 bool IsDone() {
tbarzic@chromium.org6866c6b2012-04-09 21:38:1878 return received_from_out_ >= out_expectations_.length();
tbarzic@chromium.org8f427982011-12-13 23:40:2379 }
80
81 private:
82 std::string out_expectations_;
83 size_t received_from_out_;
tbarzic@chromium.org8f427982011-12-13 23:40:2384};
85
86class ProcessOutputWatcherTest : public testing::Test {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3787 public:
88 ProcessOutputWatcherTest() : output_watch_thread_started_(false),
89 failed_(false) {
90 }
tbarzic@chromium.org8f427982011-12-13 23:40:2391
dchengae98daa2015-01-21 20:30:4992 ~ProcessOutputWatcherTest() override {}
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3793
dchengae98daa2015-01-21 20:30:4994 void TearDown() override {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3795 if (output_watch_thread_started_)
96 output_watch_thread_->Stop();
97 }
98
99 void StartWatch(int pt, int stop) {
tbarzic@chromium.org8f427982011-12-13 23:40:23100 // This will delete itself.
tbarzic@chromium.orga504ba72012-01-25 01:42:57101 ProcessOutputWatcher* crosh_watcher = new ProcessOutputWatcher(pt, stop,
tbarzic@chromium.org8f427982011-12-13 23:40:23102 base::Bind(&ProcessOutputWatcherTest::OnRead, base::Unretained(this)));
103 crosh_watcher->Start();
104 }
105
106 void OnRead(ProcessOutputType type, const std::string& output) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37107 ASSERT_FALSE(failed_);
tbarzicdaf936a2015-07-29 21:05:14108 // There may be an EXIT signal sent during test tear down (which is sent
109 // by process output watcher when master end of test pseudo-terminal is
110 // closed). If this happens, ignore it. If EXIT is seen before test
111 // expectations are met, fall through in order to fail the test.
112 if (type == PROCESS_OUTPUT_TYPE_EXIT && expectations_.IsDone()) {
113 ASSERT_TRUE(test_case_done_callback_.is_null());
114 return;
115 }
116
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37117 failed_ = !expectations_.CheckExpectations(output, type);
118 if (failed_ || expectations_.IsDone()) {
119 ASSERT_FALSE(test_case_done_callback_.is_null());
skyostil1472c842015-06-11 18:40:24120 message_loop_.task_runner()->PostTask(FROM_HERE,
121 test_case_done_callback_);
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37122 test_case_done_callback_.Reset();
123 }
tbarzic@chromium.org8f427982011-12-13 23:40:23124 }
125
126 protected:
127 std::string VeryLongString() {
128 std::string result = "0123456789";
129 for (int i = 0; i < 8; i++)
130 result = result.append(result);
131 return result;
132 }
133
tbarzic@chromium.org250f7f892012-04-11 02:46:43134 void RunTest(const std::vector<TestCase>& test_cases) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37135 ASSERT_FALSE(output_watch_thread_started_);
136 output_watch_thread_.reset(new base::Thread("ProcessOutpuWatchThread"));
137 output_watch_thread_started_ = output_watch_thread_->Start();
138 ASSERT_TRUE(output_watch_thread_started_);
tbarzic@chromium.org250f7f892012-04-11 02:46:43139
140 int pt_pipe[2], stop_pipe[2];
141 ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe)));
142 ASSERT_FALSE(HANDLE_EINTR(pipe(stop_pipe)));
143
skyostil1472c842015-06-11 18:40:24144 output_watch_thread_->task_runner()->PostTask(
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37145 FROM_HERE,
tbarzic@chromium.org250f7f892012-04-11 02:46:43146 base::Bind(&ProcessOutputWatcherTest::StartWatch,
skyostil1472c842015-06-11 18:40:24147 base::Unretained(this), pt_pipe[0], stop_pipe[0]));
tbarzic@chromium.org250f7f892012-04-11 02:46:43148
149 for (size_t i = 0; i < test_cases.size(); i++) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37150 expectations_.SetTestCase(test_cases[i]);
151
152 base::RunLoop run_loop;
153 ASSERT_TRUE(test_case_done_callback_.is_null());
154 test_case_done_callback_ = run_loop.QuitClosure();
155
156 const std::string& test_str = test_cases[i].input;
tbarzic@chromium.org250f7f892012-04-11 02:46:43157 // Let's make inputs not NULL terminated, unless other is specified in
158 // the test case.
159 ssize_t test_size = test_str.length() * sizeof(*test_str.c_str());
160 if (test_cases[i].should_send_terminating_null)
161 test_size += sizeof(*test_str.c_str());
chirantan75ea2fd2014-10-07 23:15:30162 EXPECT_TRUE(base::WriteFileDescriptor(pt_pipe[1], test_str.c_str(),
163 test_size));
tbarzic@chromium.org250f7f892012-04-11 02:46:43164
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37165 run_loop.Run();
166 EXPECT_TRUE(expectations_.IsDone());
167 if (failed_)
168 break;
169 }
tbarzic@chromium.org250f7f892012-04-11 02:46:43170
171 // Send stop signal. It is not important which string we send.
chirantan75ea2fd2014-10-07 23:15:30172 EXPECT_TRUE(base::WriteFileDescriptor(stop_pipe[1], "q", 1));
tbarzic@chromium.org250f7f892012-04-11 02:46:43173
mark@chromium.orgd89eec82013-12-03 14:10:59174 EXPECT_NE(-1, IGNORE_EINTR(close(stop_pipe[1])));
175 EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe[1])));
tbarzic@chromium.org250f7f892012-04-11 02:46:43176 }
177
tbarzic@chromium.org8f427982011-12-13 23:40:23178 private:
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37179 base::Closure test_case_done_callback_;
180 base::MessageLoop message_loop_;
181 scoped_ptr<base::Thread> output_watch_thread_;
182 bool output_watch_thread_started_;
183 bool failed_;
tbarzic@chromium.org8f427982011-12-13 23:40:23184 ProcessWatcherExpectations expectations_;
185 std::vector<TestCase> exp;
186};
187
tbarzicdaf936a2015-07-29 21:05:14188TEST_F(ProcessOutputWatcherTest, OutputWatcher) {
tbarzic@chromium.org8f427982011-12-13 23:40:23189 std::vector<TestCase> test_cases;
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37190 test_cases.push_back(TestCase("t", false));
tbarzic@chromium.org250f7f892012-04-11 02:46:43191 test_cases.push_back(TestCase("testing output\n", false));
192 test_cases.push_back(TestCase("testing error\n", false));
193 test_cases.push_back(TestCase("testing error1\n", false));
194 test_cases.push_back(TestCase("testing output1\n", false));
195 test_cases.push_back(TestCase("testing output2\n", false));
196 test_cases.push_back(TestCase("testing output3\n", false));
197 test_cases.push_back(TestCase(VeryLongString(), false));
198 test_cases.push_back(TestCase("testing error2\n", false));
tbarzic@chromium.org8f427982011-12-13 23:40:23199
tbarzic@chromium.org250f7f892012-04-11 02:46:43200 RunTest(test_cases);
thestigb44bd352014-09-10 01:47:06201}
tbarzic@chromium.org8f427982011-12-13 23:40:23202
tbarzicdaf936a2015-07-29 21:05:14203TEST_F(ProcessOutputWatcherTest, SplitUTF8Character) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37204 std::vector<TestCase> test_cases;
205 test_cases.push_back(TestCase("test1\xc2", false, "test1"));
206 test_cases.push_back(TestCase("\xb5test1", false, "\xc2\xb5test1"));
207
208 RunTest(test_cases);
209}
210
tbarzicdaf936a2015-07-29 21:05:14211TEST_F(ProcessOutputWatcherTest, SplitSoleUTF8Character) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37212 std::vector<TestCase> test_cases;
213 test_cases.push_back(TestCase("\xc2", false, ""));
214 test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
215
216 RunTest(test_cases);
217}
218
tbarzicdaf936a2015-07-29 21:05:14219TEST_F(ProcessOutputWatcherTest, SplitUTF8CharacterLength3) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37220 std::vector<TestCase> test_cases;
221 test_cases.push_back(TestCase("test3\xe2\x82", false, "test3"));
222 test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
223
224 RunTest(test_cases);
225}
226
tbarzicdaf936a2015-07-29 21:05:14227TEST_F(ProcessOutputWatcherTest, SplitSoleUTF8CharacterThreeWays) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37228 std::vector<TestCase> test_cases;
229 test_cases.push_back(TestCase("\xe2", false, ""));
230 test_cases.push_back(TestCase("\x82", false, ""));
231 test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
232
233 RunTest(test_cases);
234}
235
236TEST_F(ProcessOutputWatcherTest, EndsWithThreeByteUTF8Character) {
237 std::vector<TestCase> test_cases;
238 test_cases.push_back(TestCase("test\xe2\x82\xac", false, "test\xe2\x82\xac"));
239
240 RunTest(test_cases);
241}
242
243TEST_F(ProcessOutputWatcherTest, SoleThreeByteUTF8Character) {
244 std::vector<TestCase> test_cases;
245 test_cases.push_back(TestCase("\xe2\x82\xac", false, "\xe2\x82\xac"));
246
247 RunTest(test_cases);
248}
249
250TEST_F(ProcessOutputWatcherTest, HasThreeByteUTF8Character) {
251 std::vector<TestCase> test_cases;
252 test_cases.push_back(
253 TestCase("test\xe2\x82\xac_", false, "test\xe2\x82\xac_"));
254
255 RunTest(test_cases);
256}
257
258TEST_F(ProcessOutputWatcherTest, MulitByteUTF8CharNullTerminated) {
259 std::vector<TestCase> test_cases;
260 test_cases.push_back(TestCase("test\xe2\x82\xac", true, "test\xe2\x82\xac"));
261
262 RunTest(test_cases);
263}
264
tbarzicdaf936a2015-07-29 21:05:14265TEST_F(ProcessOutputWatcherTest, MultipleMultiByteUTF8Characters) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37266 std::vector<TestCase> test_cases;
267 test_cases.push_back(
268 TestCase("test\xe2\x82\xac\xc2", false, "test\xe2\x82\xac"));
269 test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
270
271 RunTest(test_cases);
272}
273
274TEST_F(ProcessOutputWatcherTest, ContainsInvalidUTF8) {
275 std::vector<TestCase> test_cases;
276 test_cases.push_back(TestCase("\xc2_", false, "\xc2_"));
277
278 RunTest(test_cases);
279}
280
tbarzicdaf936a2015-07-29 21:05:14281TEST_F(ProcessOutputWatcherTest, InvalidUTF8SeriesOfTrailingBytes) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37282 std::vector<TestCase> test_cases;
283 test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
284 test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
285
286 RunTest(test_cases);
287}
288
289TEST_F(ProcessOutputWatcherTest, EndsWithInvalidUTF8) {
290 std::vector<TestCase> test_cases;
291 test_cases.push_back(TestCase("\xff", false, "\xff"));
292
293 RunTest(test_cases);
294}
295
tbarzicdaf936a2015-07-29 21:05:14296TEST_F(ProcessOutputWatcherTest, FourByteUTF8) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37297 std::vector<TestCase> test_cases;
298 test_cases.push_back(TestCase("\xf0\xa4\xad", false, ""));
299 test_cases.push_back(TestCase("\xa2", false, "\xf0\xa4\xad\xa2"));
300
301 RunTest(test_cases);
thestigb44bd352014-09-10 01:47:06302}
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37303
tbarzic@chromium.org250f7f892012-04-11 02:46:43304// Verifies that sending '\0' generates PROCESS_OUTPUT_TYPE_OUT event and does
305// not terminate output watcher.
tbarzicdaf936a2015-07-29 21:05:14306TEST_F(ProcessOutputWatcherTest, SendNull) {
tbarzic@chromium.org250f7f892012-04-11 02:46:43307 std::vector<TestCase> test_cases;
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37308 // This will send '\0' to output watcher.
tbarzic@chromium.org250f7f892012-04-11 02:46:43309 test_cases.push_back(TestCase("", true));
310 // Let's verify that next input also gets detected (i.e. output watcher does
311 // not exit after seeing '\0' from previous test case).
312 test_cases.push_back(TestCase("a", true));
313
314 RunTest(test_cases);
thestigb44bd352014-09-10 01:47:06315}
phajdan.jr@chromium.org3a01162b2013-03-12 20:22:48316
317} // namespace chromeos