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.
5 #include <gtest/gtest.h>
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/files/file_util.h"
14 #include "base/location.h"
15 #include "base/posix/eintr_wrapper.h"
16 #include "base/run_loop.h"
17 #include "base/single_thread_task_runner.h"
18 #include "base/strings/string_util.h"
19 #include "base/threading/thread.h"
20 #include "chromeos/process_proxy/process_output_watcher.h"
27 TestCase(const std::string
& input
, bool send_terminating_null
)
29 should_send_terminating_null(send_terminating_null
),
30 expected_output(input
) {}
32 // Conctructor for cases where the output is not expected to be the same as
34 TestCase(const std::string
& input
,
35 bool send_terminating_null
,
36 const std::string
& expected_output
)
38 should_send_terminating_null(send_terminating_null
),
39 expected_output(expected_output
) {}
42 bool should_send_terminating_null
;
43 std::string expected_output
;
46 class ProcessWatcherExpectations
{
48 ProcessWatcherExpectations() {}
50 void SetTestCase(const TestCase
& test_case
) {
51 received_from_out_
= 0;
53 out_expectations_
= test_case
.expected_output
;
54 if (test_case
.should_send_terminating_null
)
55 out_expectations_
.append(std::string("", 1));
58 bool CheckExpectations(const std::string
& data
, ProcessOutputType type
) {
59 EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT
, type
);
60 if (type
!= PROCESS_OUTPUT_TYPE_OUT
)
63 if (out_expectations_
.length() == 0 && data
.length() == 0)
66 EXPECT_LT(received_from_out_
, out_expectations_
.length());
67 if (received_from_out_
>= out_expectations_
.length())
70 EXPECT_EQ(received_from_out_
,
71 out_expectations_
.find(data
, received_from_out_
));
72 if (received_from_out_
!= out_expectations_
.find(data
, received_from_out_
))
75 received_from_out_
+= data
.length();
80 return received_from_out_
>= out_expectations_
.length();
84 std::string out_expectations_
;
85 size_t received_from_out_
;
88 void StopProcessOutputWatcher(scoped_ptr
<ProcessOutputWatcher
> watcher
) {
89 // Just deleting |watcher| if sufficient.
94 class ProcessOutputWatcherTest
: public testing::Test
{
96 ProcessOutputWatcherTest() : output_watch_thread_started_(false),
100 ~ProcessOutputWatcherTest() override
{}
102 void TearDown() override
{
103 if (output_watch_thread_started_
)
104 output_watch_thread_
->Stop();
107 void OnRead(ProcessOutputType type
, const std::string
& output
) {
108 ASSERT_FALSE(failed_
);
109 // There may be an EXIT signal sent during test tear down (which is sent
110 // by process output watcher when master end of test pseudo-terminal is
111 // closed). If this happens, ignore it. If EXIT is seen before test
112 // expectations are met, fall through in order to fail the test.
113 if (type
== PROCESS_OUTPUT_TYPE_EXIT
&& expectations_
.IsDone()) {
114 ASSERT_TRUE(test_case_done_callback_
.is_null());
118 failed_
= !expectations_
.CheckExpectations(output
, type
);
119 if (failed_
|| expectations_
.IsDone()) {
120 ASSERT_FALSE(test_case_done_callback_
.is_null());
121 message_loop_
.task_runner()->PostTask(FROM_HERE
,
122 test_case_done_callback_
);
123 test_case_done_callback_
.Reset();
128 std::string
VeryLongString() {
129 std::string result
= "0123456789";
130 for (int i
= 0; i
< 8; i
++)
131 result
= result
.append(result
);
135 void RunTest(const std::vector
<TestCase
>& test_cases
) {
136 ASSERT_FALSE(output_watch_thread_started_
);
137 output_watch_thread_
.reset(new base::Thread("ProcessOutpuWatchThread"));
138 output_watch_thread_started_
= output_watch_thread_
->StartWithOptions(
139 base::Thread::Options(base::MessageLoop::TYPE_IO
, 0));
140 ASSERT_TRUE(output_watch_thread_started_
);
143 ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe
)));
145 scoped_ptr
<ProcessOutputWatcher
> crosh_watcher(new ProcessOutputWatcher(
147 base::Bind(&ProcessOutputWatcherTest::OnRead
, base::Unretained(this))));
149 output_watch_thread_
->task_runner()->PostTask(
150 FROM_HERE
, base::Bind(&ProcessOutputWatcher::Start
,
151 base::Unretained(crosh_watcher
.get())));
153 for (size_t i
= 0; i
< test_cases
.size(); i
++) {
154 expectations_
.SetTestCase(test_cases
[i
]);
156 base::RunLoop run_loop
;
157 ASSERT_TRUE(test_case_done_callback_
.is_null());
158 test_case_done_callback_
= run_loop
.QuitClosure();
160 const std::string
& test_str
= test_cases
[i
].input
;
161 // Let's make inputs not NULL terminated, unless other is specified in
163 ssize_t test_size
= test_str
.length() * sizeof(*test_str
.c_str());
164 if (test_cases
[i
].should_send_terminating_null
)
165 test_size
+= sizeof(*test_str
.c_str());
166 EXPECT_TRUE(base::WriteFileDescriptor(pt_pipe
[1], test_str
.c_str(),
170 EXPECT_TRUE(expectations_
.IsDone());
175 output_watch_thread_
->task_runner()->PostTask(
177 base::Bind(&StopProcessOutputWatcher
, base::Passed(&crosh_watcher
)));
179 EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe
[1])));
183 base::Closure test_case_done_callback_
;
184 base::MessageLoop message_loop_
;
185 scoped_ptr
<base::Thread
> output_watch_thread_
;
186 bool output_watch_thread_started_
;
188 ProcessWatcherExpectations expectations_
;
189 std::vector
<TestCase
> exp
;
192 TEST_F(ProcessOutputWatcherTest
, OutputWatcher
) {
193 std::vector
<TestCase
> test_cases
;
194 test_cases
.push_back(TestCase("t", false));
195 test_cases
.push_back(TestCase("testing output\n", false));
196 test_cases
.push_back(TestCase("testing error\n", false));
197 test_cases
.push_back(TestCase("testing error1\n", false));
198 test_cases
.push_back(TestCase("testing output1\n", false));
199 test_cases
.push_back(TestCase("testing output2\n", false));
200 test_cases
.push_back(TestCase("testing output3\n", false));
201 test_cases
.push_back(TestCase(VeryLongString(), false));
202 test_cases
.push_back(TestCase("testing error2\n", false));
207 TEST_F(ProcessOutputWatcherTest
, SplitUTF8Character
) {
208 std::vector
<TestCase
> test_cases
;
209 test_cases
.push_back(TestCase("test1\xc2", false, "test1"));
210 test_cases
.push_back(TestCase("\xb5test1", false, "\xc2\xb5test1"));
215 TEST_F(ProcessOutputWatcherTest
, SplitSoleUTF8Character
) {
216 std::vector
<TestCase
> test_cases
;
217 test_cases
.push_back(TestCase("\xc2", false, ""));
218 test_cases
.push_back(TestCase("\xb5", false, "\xc2\xb5"));
223 TEST_F(ProcessOutputWatcherTest
, SplitUTF8CharacterLength3
) {
224 std::vector
<TestCase
> test_cases
;
225 test_cases
.push_back(TestCase("test3\xe2\x82", false, "test3"));
226 test_cases
.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
231 TEST_F(ProcessOutputWatcherTest
, SplitSoleUTF8CharacterThreeWays
) {
232 std::vector
<TestCase
> test_cases
;
233 test_cases
.push_back(TestCase("\xe2", false, ""));
234 test_cases
.push_back(TestCase("\x82", false, ""));
235 test_cases
.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
240 TEST_F(ProcessOutputWatcherTest
, EndsWithThreeByteUTF8Character
) {
241 std::vector
<TestCase
> test_cases
;
242 test_cases
.push_back(TestCase("test\xe2\x82\xac", false, "test\xe2\x82\xac"));
247 TEST_F(ProcessOutputWatcherTest
, SoleThreeByteUTF8Character
) {
248 std::vector
<TestCase
> test_cases
;
249 test_cases
.push_back(TestCase("\xe2\x82\xac", false, "\xe2\x82\xac"));
254 TEST_F(ProcessOutputWatcherTest
, HasThreeByteUTF8Character
) {
255 std::vector
<TestCase
> test_cases
;
256 test_cases
.push_back(
257 TestCase("test\xe2\x82\xac_", false, "test\xe2\x82\xac_"));
262 TEST_F(ProcessOutputWatcherTest
, MulitByteUTF8CharNullTerminated
) {
263 std::vector
<TestCase
> test_cases
;
264 test_cases
.push_back(TestCase("test\xe2\x82\xac", true, "test\xe2\x82\xac"));
269 TEST_F(ProcessOutputWatcherTest
, MultipleMultiByteUTF8Characters
) {
270 std::vector
<TestCase
> test_cases
;
271 test_cases
.push_back(
272 TestCase("test\xe2\x82\xac\xc2", false, "test\xe2\x82\xac"));
273 test_cases
.push_back(TestCase("\xb5", false, "\xc2\xb5"));
278 TEST_F(ProcessOutputWatcherTest
, ContainsInvalidUTF8
) {
279 std::vector
<TestCase
> test_cases
;
280 test_cases
.push_back(TestCase("\xc2_", false, "\xc2_"));
285 TEST_F(ProcessOutputWatcherTest
, InvalidUTF8SeriesOfTrailingBytes
) {
286 std::vector
<TestCase
> test_cases
;
287 test_cases
.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
288 test_cases
.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
293 TEST_F(ProcessOutputWatcherTest
, EndsWithInvalidUTF8
) {
294 std::vector
<TestCase
> test_cases
;
295 test_cases
.push_back(TestCase("\xff", false, "\xff"));
300 TEST_F(ProcessOutputWatcherTest
, FourByteUTF8
) {
301 std::vector
<TestCase
> test_cases
;
302 test_cases
.push_back(TestCase("\xf0\xa4\xad", false, ""));
303 test_cases
.push_back(TestCase("\xa2", false, "\xf0\xa4\xad\xa2"));
308 // Verifies that sending '\0' generates PROCESS_OUTPUT_TYPE_OUT event and does
309 // not terminate output watcher.
310 TEST_F(ProcessOutputWatcherTest
, SendNull
) {
311 std::vector
<TestCase
> test_cases
;
312 // This will send '\0' to output watcher.
313 test_cases
.push_back(TestCase("", true));
314 // Let's verify that next input also gets detected (i.e. output watcher does
315 // not exit after seeing '\0' from previous test case).
316 test_cases
.push_back(TestCase("a", true));
321 } // namespace chromeos