[go: nahoru, domu]

blob: 4473442854a0f8f7b4af32c794da603249373b5e [file] [log] [blame]
Avi Drissmane4714ce92022-09-12 21:41:581// Copyright 2012 The Chromium Authors
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
dcheng0a6e80c2016-04-08 18:37:385#include "chromeos/process_proxy/process_output_watcher.h"
6
tbarzic@chromium.org8f427982011-12-13 23:40:237#include <gtest/gtest.h>
avi6e1a22d2015-12-21 03:43:208#include <stddef.h>
tbarzic@chromium.org8f427982011-12-13 23:40:239
dcheng0a6e80c2016-04-08 18:37:3810#include <memory>
tbarzic@chromium.org8f427982011-12-13 23:40:2311#include <queue>
12#include <string>
13#include <vector>
14
thestigb44bd352014-09-10 01:47:0615#include "base/files/file_util.h"
Avi Drissman710fdab2023-01-11 04:37:3616#include "base/functional/bind.h"
17#include "base/functional/callback.h"
skyostil1472c842015-06-11 18:40:2418#include "base/location.h"
Carlos Caballerodd8bf7b02019-07-30 14:14:1519#include "base/message_loop/message_pump_type.h"
brettw@chromium.org2025d002012-11-14 20:54:3520#include "base/posix/eintr_wrapper.h"
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3721#include "base/run_loop.h"
22#include "base/strings/string_util.h"
Patrick Monette643cdf62021-10-15 19:13:4223#include "base/task/single_thread_task_runner.h"
Gabriel Charettec7108742019-08-23 03:31:4024#include "base/test/task_environment.h"
tbarzic@chromium.org8f427982011-12-13 23:40:2325#include "base/threading/thread.h"
phajdan.jr@chromium.org3a01162b2013-03-12 20:22:4826
27namespace chromeos {
tbarzic@chromium.org8f427982011-12-13 23:40:2328
tbarzic6ca50552015-08-10 22:32:4529namespace {
30
tbarzic@chromium.org8f427982011-12-13 23:40:2331struct TestCase {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3732 TestCase(const std::string& input, bool send_terminating_null)
33 : input(input),
34 should_send_terminating_null(send_terminating_null),
35 expected_output(input) {}
tbarzic@chromium.org8f427982011-12-13 23:40:2336
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3737 // Conctructor for cases where the output is not expected to be the same as
38 // input.
39 TestCase(const std::string& input,
40 bool send_terminating_null,
41 const std::string& expected_output)
42 : input(input),
43 should_send_terminating_null(send_terminating_null),
44 expected_output(expected_output) {}
45
46 std::string input;
47 bool should_send_terminating_null;
48 std::string expected_output;
tbarzic@chromium.org8f427982011-12-13 23:40:2349};
50
51class ProcessWatcherExpectations {
52 public:
Chris Watkins2c529d62017-11-29 02:14:4153 ProcessWatcherExpectations() = default;
tbarzic@chromium.org8f427982011-12-13 23:40:2354
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3755 void SetTestCase(const TestCase& test_case) {
tbarzic@chromium.org8f427982011-12-13 23:40:2356 received_from_out_ = 0;
tbarzic@chromium.org8f427982011-12-13 23:40:2357
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3758 out_expectations_ = test_case.expected_output;
59 if (test_case.should_send_terminating_null)
60 out_expectations_.append(std::string("", 1));
tbarzic@chromium.org8f427982011-12-13 23:40:2361 }
62
tbarzic@chromium.org6866c6b2012-04-09 21:38:1863 bool CheckExpectations(const std::string& data, ProcessOutputType type) {
64 EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT, type);
thakis@chromium.orge2524b02013-07-22 17:51:2865 if (type != PROCESS_OUTPUT_TYPE_OUT)
tbarzic@chromium.org6866c6b2012-04-09 21:38:1866 return false;
tbarzic@chromium.org8f427982011-12-13 23:40:2367
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3768 if (out_expectations_.length() == 0 && data.length() == 0)
69 return true;
70
tbarzic@chromium.org6866c6b2012-04-09 21:38:1871 EXPECT_LT(received_from_out_, out_expectations_.length());
72 if (received_from_out_ >= out_expectations_.length())
73 return false;
tbarzic@chromium.org8f427982011-12-13 23:40:2374
tbarzic@chromium.org6866c6b2012-04-09 21:38:1875 EXPECT_EQ(received_from_out_,
76 out_expectations_.find(data, received_from_out_));
tbarzic@chromium.org65bbd9d22014-05-15 20:34:3777 if (received_from_out_ != out_expectations_.find(data, received_from_out_))
78 return false;
tbarzic@chromium.org8f427982011-12-13 23:40:2379
tbarzic@chromium.org6866c6b2012-04-09 21:38:1880 received_from_out_ += data.length();
81 return true;
tbarzic@chromium.org8f427982011-12-13 23:40:2382 }
83
84 bool IsDone() {
tbarzic@chromium.org6866c6b2012-04-09 21:38:1885 return received_from_out_ >= out_expectations_.length();
tbarzic@chromium.org8f427982011-12-13 23:40:2386 }
87
88 private:
89 std::string out_expectations_;
90 size_t received_from_out_;
tbarzic@chromium.org8f427982011-12-13 23:40:2391};
92
dcheng0a6e80c2016-04-08 18:37:3893void StopProcessOutputWatcher(std::unique_ptr<ProcessOutputWatcher> watcher) {
tbarzic6ca50552015-08-10 22:32:4594 // Just deleting |watcher| if sufficient.
95}
96
97} // namespace
98
tbarzic@chromium.org8f427982011-12-13 23:40:2399class ProcessOutputWatcherTest : public testing::Test {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37100 public:
101 ProcessOutputWatcherTest() : output_watch_thread_started_(false),
102 failed_(false) {
103 }
tbarzic@chromium.org8f427982011-12-13 23:40:23104
Chris Watkins2c529d62017-11-29 02:14:41105 ~ProcessOutputWatcherTest() override = default;
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37106
dchengae98daa2015-01-21 20:30:49107 void TearDown() override {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37108 if (output_watch_thread_started_)
109 output_watch_thread_->Stop();
110 }
111
Joel Hockey8d1d0192022-07-29 02:38:35112 void OnRead(ProcessOutputType type, const std::string& output) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37113 ASSERT_FALSE(failed_);
tbarzicdaf936a2015-07-29 21:05:14114 // There may be an EXIT signal sent during test tear down (which is sent
115 // by process output watcher when master end of test pseudo-terminal is
116 // closed). If this happens, ignore it. If EXIT is seen before test
117 // expectations are met, fall through in order to fail the test.
118 if (type == PROCESS_OUTPUT_TYPE_EXIT && expectations_.IsDone()) {
119 ASSERT_TRUE(test_case_done_callback_.is_null());
120 return;
121 }
122
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37123 failed_ = !expectations_.CheckExpectations(output, type);
124 if (failed_ || expectations_.IsDone()) {
125 ASSERT_FALSE(test_case_done_callback_.is_null());
Gabriel Charette694c3c332019-08-19 14:53:05126 task_environment_.GetMainThreadTaskRunner()->PostTask(
Reilly Grant65820a52019-11-19 20:45:11127 FROM_HERE, std::move(test_case_done_callback_));
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37128 test_case_done_callback_.Reset();
129 }
tbarzic170f12c2016-01-08 05:15:29130
Joel Hockey8d1d0192022-07-29 02:38:35131 output_watch_thread_->task_runner()->PostTask(
132 FROM_HERE, base::BindOnce(&ProcessOutputWatcher::AckOutput,
133 base::Unretained(output_watcher_.get())));
tbarzic@chromium.org8f427982011-12-13 23:40:23134 }
135
136 protected:
137 std::string VeryLongString() {
138 std::string result = "0123456789";
139 for (int i = 0; i < 8; i++)
140 result = result.append(result);
141 return result;
142 }
143
tbarzic@chromium.org250f7f892012-04-11 02:46:43144 void RunTest(const std::vector<TestCase>& test_cases) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37145 ASSERT_FALSE(output_watch_thread_started_);
Peter Boström6b701822021-04-15 03:53:08146 output_watch_thread_ =
147 std::make_unique<base::Thread>("ProcessOutpuWatchThread");
tbarzic6ca50552015-08-10 22:32:45148 output_watch_thread_started_ = output_watch_thread_->StartWithOptions(
Carlos Caballerodd8bf7b02019-07-30 14:14:15149 base::Thread::Options(base::MessagePumpType::IO, 0));
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37150 ASSERT_TRUE(output_watch_thread_started_);
tbarzic@chromium.org250f7f892012-04-11 02:46:43151
tbarzic6ca50552015-08-10 22:32:45152 int pt_pipe[2];
tbarzic@chromium.org250f7f892012-04-11 02:46:43153 ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe)));
tbarzic6ca50552015-08-10 22:32:45154
Joel Hockey8d1d0192022-07-29 02:38:35155 output_watcher_ = std::make_unique<ProcessOutputWatcher>(
Reilly Grant65820a52019-11-19 20:45:11156 pt_pipe[0], base::BindRepeating(&ProcessOutputWatcherTest::OnRead,
157 base::Unretained(this)));
tbarzic@chromium.org250f7f892012-04-11 02:46:43158
skyostil1472c842015-06-11 18:40:24159 output_watch_thread_->task_runner()->PostTask(
tzikc8fdd6c32018-04-11 04:02:40160 FROM_HERE, base::BindOnce(&ProcessOutputWatcher::Start,
Joel Hockey8d1d0192022-07-29 02:38:35161 base::Unretained(output_watcher_.get())));
tbarzic@chromium.org250f7f892012-04-11 02:46:43162
163 for (size_t i = 0; i < test_cases.size(); i++) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37164 expectations_.SetTestCase(test_cases[i]);
165
166 base::RunLoop run_loop;
167 ASSERT_TRUE(test_case_done_callback_.is_null());
168 test_case_done_callback_ = run_loop.QuitClosure();
169
170 const std::string& test_str = test_cases[i].input;
tbarzic@chromium.org250f7f892012-04-11 02:46:43171 // Let's make inputs not NULL terminated, unless other is specified in
172 // the test case.
173 ssize_t test_size = test_str.length() * sizeof(*test_str.c_str());
174 if (test_cases[i].should_send_terminating_null)
175 test_size += sizeof(*test_str.c_str());
Lei Zhangc9e8a162021-05-14 09:33:52176 EXPECT_TRUE(base::WriteFileDescriptor(
177 pt_pipe[1], base::StringPiece(test_str.c_str(), test_size)));
tbarzic@chromium.org250f7f892012-04-11 02:46:43178
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37179 run_loop.Run();
180 EXPECT_TRUE(expectations_.IsDone());
181 if (failed_)
182 break;
183 }
tbarzic@chromium.org250f7f892012-04-11 02:46:43184
tbarzic6ca50552015-08-10 22:32:45185 output_watch_thread_->task_runner()->PostTask(
186 FROM_HERE,
Joel Hockey8d1d0192022-07-29 02:38:35187 base::BindOnce(&StopProcessOutputWatcher, std::move(output_watcher_)));
tbarzic@chromium.org250f7f892012-04-11 02:46:43188
mark@chromium.orgd89eec82013-12-03 14:10:59189 EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe[1])));
tbarzic@chromium.org250f7f892012-04-11 02:46:43190 }
191
tbarzic@chromium.org8f427982011-12-13 23:40:23192 private:
Reilly Grant65820a52019-11-19 20:45:11193 base::OnceClosure test_case_done_callback_;
Gabriel Charette58ea6de8b2019-09-07 13:18:33194 base::test::SingleThreadTaskEnvironment task_environment_;
dcheng0a6e80c2016-04-08 18:37:38195 std::unique_ptr<base::Thread> output_watch_thread_;
Joel Hockey8d1d0192022-07-29 02:38:35196 bool output_watch_thread_started_ = false;
197 std::unique_ptr<ProcessOutputWatcher> output_watcher_;
198 bool failed_ = false;
tbarzic@chromium.org8f427982011-12-13 23:40:23199 ProcessWatcherExpectations expectations_;
200 std::vector<TestCase> exp;
201};
202
Sergey Ulanovc7ddfb6c2022-12-13 05:04:02203TEST_F(ProcessOutputWatcherTest, DISABLED_OutputWatcher) {
tbarzic@chromium.org8f427982011-12-13 23:40:23204 std::vector<TestCase> test_cases;
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37205 test_cases.push_back(TestCase("t", false));
tbarzic@chromium.org250f7f892012-04-11 02:46:43206 test_cases.push_back(TestCase("testing output\n", false));
207 test_cases.push_back(TestCase("testing error\n", false));
208 test_cases.push_back(TestCase("testing error1\n", false));
209 test_cases.push_back(TestCase("testing output1\n", false));
210 test_cases.push_back(TestCase("testing output2\n", false));
211 test_cases.push_back(TestCase("testing output3\n", false));
212 test_cases.push_back(TestCase(VeryLongString(), false));
213 test_cases.push_back(TestCase("testing error2\n", false));
tbarzic@chromium.org8f427982011-12-13 23:40:23214
tbarzic@chromium.org250f7f892012-04-11 02:46:43215 RunTest(test_cases);
thestigb44bd352014-09-10 01:47:06216}
tbarzic@chromium.org8f427982011-12-13 23:40:23217
Sergey Ulanovc7ddfb6c2022-12-13 05:04:02218TEST_F(ProcessOutputWatcherTest, DISABLED_SplitUTF8Character) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37219 std::vector<TestCase> test_cases;
220 test_cases.push_back(TestCase("test1\xc2", false, "test1"));
221 test_cases.push_back(TestCase("\xb5test1", false, "\xc2\xb5test1"));
222
223 RunTest(test_cases);
224}
225
Sergey Ulanovc7ddfb6c2022-12-13 05:04:02226TEST_F(ProcessOutputWatcherTest, DISABLED_SplitSoleUTF8Character) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37227 std::vector<TestCase> test_cases;
228 test_cases.push_back(TestCase("\xc2", false, ""));
229 test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
230
231 RunTest(test_cases);
232}
233
Sergey Ulanovc7ddfb6c2022-12-13 05:04:02234TEST_F(ProcessOutputWatcherTest, DISABLED_SplitUTF8CharacterLength3) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37235 std::vector<TestCase> test_cases;
236 test_cases.push_back(TestCase("test3\xe2\x82", false, "test3"));
237 test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
238
239 RunTest(test_cases);
240}
241
Sergey Ulanovc7ddfb6c2022-12-13 05:04:02242TEST_F(ProcessOutputWatcherTest, DISABLED_SplitSoleUTF8CharacterThreeWays) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37243 std::vector<TestCase> test_cases;
244 test_cases.push_back(TestCase("\xe2", false, ""));
245 test_cases.push_back(TestCase("\x82", false, ""));
246 test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
247
248 RunTest(test_cases);
249}
250
Yuzu Saijo5b44b5b2022-11-08 01:09:13251// TODO(crbug.com/1382252) Re-enable test
252TEST_F(ProcessOutputWatcherTest, DISABLED_EndsWithThreeByteUTF8Character) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37253 std::vector<TestCase> test_cases;
254 test_cases.push_back(TestCase("test\xe2\x82\xac", false, "test\xe2\x82\xac"));
255
256 RunTest(test_cases);
257}
258
Sergey Ulanovc7ddfb6c2022-12-13 05:04:02259TEST_F(ProcessOutputWatcherTest, DISABLED_SoleThreeByteUTF8Character) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37260 std::vector<TestCase> test_cases;
261 test_cases.push_back(TestCase("\xe2\x82\xac", false, "\xe2\x82\xac"));
262
263 RunTest(test_cases);
264}
265
Sergey Ulanovc7ddfb6c2022-12-13 05:04:02266TEST_F(ProcessOutputWatcherTest, DISABLED_HasThreeByteUTF8Character) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37267 std::vector<TestCase> test_cases;
268 test_cases.push_back(
269 TestCase("test\xe2\x82\xac_", false, "test\xe2\x82\xac_"));
270
271 RunTest(test_cases);
272}
273
Alison Galeb08fa1c22022-12-02 21:59:02274// TODO(crbug.com/1395483) Re-enable test
275TEST_F(ProcessOutputWatcherTest, DISABLED_MultiByteUTF8CharNullTerminated) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37276 std::vector<TestCase> test_cases;
277 test_cases.push_back(TestCase("test\xe2\x82\xac", true, "test\xe2\x82\xac"));
278
279 RunTest(test_cases);
280}
281
Sergey Ulanovc7ddfb6c2022-12-13 05:04:02282TEST_F(ProcessOutputWatcherTest, DISABLED_MultipleMultiByteUTF8Characters) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37283 std::vector<TestCase> test_cases;
284 test_cases.push_back(
285 TestCase("test\xe2\x82\xac\xc2", false, "test\xe2\x82\xac"));
286 test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
287
288 RunTest(test_cases);
289}
290
Sergey Ulanovc7ddfb6c2022-12-13 05:04:02291TEST_F(ProcessOutputWatcherTest, DISABLED_ContainsInvalidUTF8) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37292 std::vector<TestCase> test_cases;
293 test_cases.push_back(TestCase("\xc2_", false, "\xc2_"));
294
295 RunTest(test_cases);
296}
297
Keishi Hattori1c8b2f512022-12-09 02:50:05298// TODO(crbug.com/1399698): Re-enable this test
299TEST_F(ProcessOutputWatcherTest, DISABLED_InvalidUTF8SeriesOfTrailingBytes) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37300 std::vector<TestCase> test_cases;
301 test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
302 test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
303
304 RunTest(test_cases);
305}
306
Alison Galeb08fa1c22022-12-02 21:59:02307// TODO(crbug.com/1395483) Re-enable test
308TEST_F(ProcessOutputWatcherTest, DISABLED_EndsWithInvalidUTF8) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37309 std::vector<TestCase> test_cases;
310 test_cases.push_back(TestCase("\xff", false, "\xff"));
311
312 RunTest(test_cases);
313}
314
Fergus Dall794ffeb2021-02-11 07:17:29315// TODO(crbug.com/1177137) Re-enable test
316TEST_F(ProcessOutputWatcherTest, DISABLED_FourByteUTF8) {
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37317 std::vector<TestCase> test_cases;
318 test_cases.push_back(TestCase("\xf0\xa4\xad", false, ""));
319 test_cases.push_back(TestCase("\xa2", false, "\xf0\xa4\xad\xa2"));
320
321 RunTest(test_cases);
thestigb44bd352014-09-10 01:47:06322}
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37323
tbarzic@chromium.org250f7f892012-04-11 02:46:43324// Verifies that sending '\0' generates PROCESS_OUTPUT_TYPE_OUT event and does
325// not terminate output watcher.
Alison Galeb08fa1c22022-12-02 21:59:02326// TODO(crbug.com/1395483) Re-enable test
327TEST_F(ProcessOutputWatcherTest, DISABLED_SendNull) {
tbarzic@chromium.org250f7f892012-04-11 02:46:43328 std::vector<TestCase> test_cases;
tbarzic@chromium.org65bbd9d22014-05-15 20:34:37329 // This will send '\0' to output watcher.
tbarzic@chromium.org250f7f892012-04-11 02:46:43330 test_cases.push_back(TestCase("", true));
331 // Let's verify that next input also gets detected (i.e. output watcher does
332 // not exit after seeing '\0' from previous test case).
333 test_cases.push_back(TestCase("a", true));
334
335 RunTest(test_cases);
thestigb44bd352014-09-10 01:47:06336}
phajdan.jr@chromium.org3a01162b2013-03-12 20:22:48337
338} // namespace chromeos