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 <queue> 8#include <string> 9#include <vector> 10 11#include "base/bind.h" 12#include "base/callback.h" 13#include "base/file_util.h" 14#include "base/message_loop/message_loop.h" 15#include "base/posix/eintr_wrapper.h" 16#include "base/run_loop.h" 17#include "base/strings/string_util.h" 18#include "base/threading/thread.h" 19#include "chromeos/process_proxy/process_output_watcher.h" 20 21namespace chromeos { 22 23struct TestCase { 24 TestCase(const std::string& input, bool send_terminating_null) 25 : input(input), 26 should_send_terminating_null(send_terminating_null), 27 expected_output(input) {} 28 29 // 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; 41}; 42 43class ProcessWatcherExpectations { 44 public: 45 ProcessWatcherExpectations() {} 46 47 void SetTestCase(const TestCase& test_case) { 48 received_from_out_ = 0; 49 50 out_expectations_ = test_case.expected_output; 51 if (test_case.should_send_terminating_null) 52 out_expectations_.append(std::string("", 1)); 53 } 54 55 bool CheckExpectations(const std::string& data, ProcessOutputType type) { 56 EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT, type); 57 if (type != PROCESS_OUTPUT_TYPE_OUT) 58 return false; 59 60 if (out_expectations_.length() == 0 && data.length() == 0) 61 return true; 62 63 EXPECT_LT(received_from_out_, out_expectations_.length()); 64 if (received_from_out_ >= out_expectations_.length()) 65 return false; 66 67 EXPECT_EQ(received_from_out_, 68 out_expectations_.find(data, received_from_out_)); 69 if (received_from_out_ != out_expectations_.find(data, received_from_out_)) 70 return false; 71 72 received_from_out_ += data.length(); 73 return true; 74 } 75 76 bool IsDone() { 77 return received_from_out_ >= out_expectations_.length(); 78 } 79 80 private: 81 std::string out_expectations_; 82 size_t received_from_out_; 83}; 84 85class ProcessOutputWatcherTest : public testing::Test { 86 public: 87 ProcessOutputWatcherTest() : output_watch_thread_started_(false), 88 failed_(false) { 89 } 90 91 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) { 99 // This will delete itself. 100 ProcessOutputWatcher* crosh_watcher = new ProcessOutputWatcher(pt, stop, 101 base::Bind(&ProcessOutputWatcherTest::OnRead, base::Unretained(this))); 102 crosh_watcher->Start(); 103 } 104 105 void OnRead(ProcessOutputType type, const std::string& output) { 106 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 } 113 } 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 123 void RunTest(const std::vector<TestCase>& test_cases) { 124 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_); 128 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 133 output_watch_thread_->message_loop()->PostTask( 134 FROM_HERE, 135 base::Bind(&ProcessOutputWatcherTest::StartWatch, 136 base::Unretained(this), 137 pt_pipe[0], 138 stop_pipe[0])); 139 140 for (size_t i = 0; i < test_cases.size(); i++) { 141 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; 148 // 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, 154 base::WriteFileDescriptor(pt_pipe[1], test_str.c_str(), 155 test_size)); 156 157 run_loop.Run(); 158 EXPECT_TRUE(expectations_.IsDone()); 159 if (failed_) 160 break; 161 } 162 163 // Send stop signal. It is not important which string we send. 164 EXPECT_EQ(1, base::WriteFileDescriptor(stop_pipe[1], "q", 1)); 165 166 EXPECT_NE(-1, IGNORE_EINTR(close(stop_pipe[1]))); 167 EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe[1]))); 168 } 169 170 private: 171 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_; 176 ProcessWatcherExpectations expectations_; 177 std::vector<TestCase> exp; 178}; 179 180 181TEST_F(ProcessOutputWatcherTest, OutputWatcher) { 182 std::vector<TestCase> test_cases; 183 test_cases.push_back(TestCase("t", false)); 184 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)); 192 193 RunTest(test_cases); 194}; 195 196TEST_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 297// 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; 301 // This will send '\0' to output watcher. 302 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}; 309 310} // namespace chromeos 311