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 <sys/wait.h> 12 13 #include "base/bind.h" 14 #include "base/file_util.h" 15 #include "base/posix/eintr_wrapper.h" 16 #include "base/synchronization/waitable_event.h" 17 #include "base/threading/thread.h" 18 #include "chromeos/process_proxy/process_output_watcher.h" 19 20 namespace chromeos { 21 22 struct TestCase { 23 std::string str; 24 bool should_send_terminating_null; 25 26 TestCase(const std::string& expected_string, 27 bool send_terminating_null) 28 : str(expected_string), 29 should_send_terminating_null(send_terminating_null) { 30 } 31 }; 32 33 class ProcessWatcherExpectations { 34 public: 35 ProcessWatcherExpectations() {} 36 37 void Init(const std::vector<TestCase>& expectations) { 38 received_from_out_ = 0; 39 40 for (size_t i = 0; i < expectations.size(); i++) { 41 out_expectations_.append(expectations[i].str); 42 if (expectations[i].should_send_terminating_null) 43 out_expectations_.append(std::string("", 1)); 44 } 45 } 46 47 bool CheckExpectations(const std::string& data, ProcessOutputType type) { 48 EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT, type); 49 if (type != PROCESS_OUTPUT_TYPE_OUT) 50 return false; 51 52 EXPECT_LT(received_from_out_, out_expectations_.length()); 53 if (received_from_out_ >= out_expectations_.length()) 54 return false; 55 56 EXPECT_EQ(received_from_out_, 57 out_expectations_.find(data, received_from_out_)); 58 59 received_from_out_ += data.length(); 60 return true; 61 } 62 63 bool IsDone() { 64 return received_from_out_ >= out_expectations_.length(); 65 } 66 67 private: 68 std::string out_expectations_; 69 size_t received_from_out_; 70 }; 71 72 class ProcessOutputWatcherTest : public testing::Test { 73 public: 74 void StartWatch(int pt, int stop, 75 const std::vector<TestCase>& expectations) { 76 expectations_.Init(expectations); 77 78 // This will delete itself. 79 ProcessOutputWatcher* crosh_watcher = new ProcessOutputWatcher(pt, stop, 80 base::Bind(&ProcessOutputWatcherTest::OnRead, base::Unretained(this))); 81 crosh_watcher->Start(); 82 } 83 84 void OnRead(ProcessOutputType type, const std::string& output) { 85 bool success = expectations_.CheckExpectations(output, type); 86 if (!success || expectations_.IsDone()) 87 all_data_received_->Signal(); 88 } 89 90 protected: 91 std::string VeryLongString() { 92 std::string result = "0123456789"; 93 for (int i = 0; i < 8; i++) 94 result = result.append(result); 95 return result; 96 } 97 98 void RunTest(const std::vector<TestCase>& test_cases) { 99 all_data_received_.reset(new base::WaitableEvent(true, false)); 100 101 base::Thread output_watch_thread("ProcessOutpuWatchThread"); 102 ASSERT_TRUE(output_watch_thread.Start()); 103 104 int pt_pipe[2], stop_pipe[2]; 105 ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe))); 106 ASSERT_FALSE(HANDLE_EINTR(pipe(stop_pipe))); 107 108 output_watch_thread.message_loop()->PostTask(FROM_HERE, 109 base::Bind(&ProcessOutputWatcherTest::StartWatch, 110 base::Unretained(this), 111 pt_pipe[0], stop_pipe[0], test_cases)); 112 113 for (size_t i = 0; i < test_cases.size(); i++) { 114 const std::string& test_str = test_cases[i].str; 115 // Let's make inputs not NULL terminated, unless other is specified in 116 // the test case. 117 ssize_t test_size = test_str.length() * sizeof(*test_str.c_str()); 118 if (test_cases[i].should_send_terminating_null) 119 test_size += sizeof(*test_str.c_str()); 120 EXPECT_EQ(test_size, 121 file_util::WriteFileDescriptor(pt_pipe[1], test_str.c_str(), 122 test_size)); 123 } 124 125 all_data_received_->Wait(); 126 127 // Send stop signal. It is not important which string we send. 128 EXPECT_EQ(1, file_util::WriteFileDescriptor(stop_pipe[1], "q", 1)); 129 130 EXPECT_NE(-1, IGNORE_EINTR(close(stop_pipe[1]))); 131 EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe[1]))); 132 133 output_watch_thread.Stop(); 134 } 135 136 scoped_ptr<base::WaitableEvent> all_data_received_; 137 138 private: 139 ProcessWatcherExpectations expectations_; 140 std::vector<TestCase> exp; 141 }; 142 143 144 TEST_F(ProcessOutputWatcherTest, OutputWatcher) { 145 std::vector<TestCase> test_cases; 146 test_cases.push_back(TestCase("testing output\n", false)); 147 test_cases.push_back(TestCase("testing error\n", false)); 148 test_cases.push_back(TestCase("testing error1\n", false)); 149 test_cases.push_back(TestCase("testing output1\n", false)); 150 test_cases.push_back(TestCase("testing output2\n", false)); 151 test_cases.push_back(TestCase("testing output3\n", false)); 152 test_cases.push_back(TestCase(VeryLongString(), false)); 153 test_cases.push_back(TestCase("testing error2\n", false)); 154 155 RunTest(test_cases); 156 }; 157 158 // Verifies that sending '\0' generates PROCESS_OUTPUT_TYPE_OUT event and does 159 // not terminate output watcher. 160 TEST_F(ProcessOutputWatcherTest, SendNull) { 161 std::vector<TestCase> test_cases; 162 // This will send '\0' to output wathcer. 163 test_cases.push_back(TestCase("", true)); 164 // Let's verify that next input also gets detected (i.e. output watcher does 165 // not exit after seeing '\0' from previous test case). 166 test_cases.push_back(TestCase("a", true)); 167 168 RunTest(test_cases); 169 }; 170 171 } // namespace chromeos 172