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 <string> 8 #include <sys/wait.h> 9 10 #include "base/bind.h" 11 #include "base/memory/scoped_ptr.h" 12 #include "base/message_loop/message_loop.h" 13 #include "base/posix/eintr_wrapper.h" 14 #include "base/process/kill.h" 15 #include "base/synchronization/waitable_event.h" 16 #include "base/threading/thread.h" 17 #include "chromeos/process_proxy/process_proxy_registry.h" 18 19 namespace chromeos { 20 21 namespace { 22 23 // The test line must have all distinct characters. 24 const char kTestLineToSend[] = "abcdefgh\n"; 25 const char kTestLineExpected[] = "abcdefgh\r\n"; 26 27 const char kCatCommand[] = "cat"; 28 const char kStdoutType[] = "stdout"; 29 const int kTestLineNum = 100; 30 31 class TestRunner { 32 public: 33 virtual ~TestRunner() {} 34 virtual void SetupExpectations(pid_t pid) = 0; 35 virtual void OnSomeRead(pid_t pid, const std::string& type, 36 const std::string& output) = 0; 37 virtual void StartRegistryTest(ProcessProxyRegistry* registry) = 0; 38 39 protected: 40 pid_t pid_; 41 }; 42 43 class RegistryTestRunner : public TestRunner { 44 public: 45 virtual ~RegistryTestRunner() {} 46 47 virtual void SetupExpectations(pid_t pid) OVERRIDE { 48 pid_ = pid; 49 left_to_check_index_[0] = 0; 50 left_to_check_index_[1] = 0; 51 // We consider that a line processing has started if a value in 52 // left_to_check__[index] is set to 0, thus -2. 53 lines_left_ = 2 * kTestLineNum - 2; 54 expected_line_ = kTestLineExpected; 55 } 56 57 // Method to test validity of received input. We will receive two streams of 58 // the same data. (input will be echoed twice by the testing process). Each 59 // stream will contain the same string repeated |kTestLineNum| times. So we 60 // have to match 2 * |kTestLineNum| lines. The problem is the received lines 61 // from different streams may be interleaved (e.g. we may receive 62 // abc|abcdef|defgh|gh). To deal with that, we allow to test received text 63 // against two lines. The lines MUST NOT have two same characters for this 64 // algorithm to work. 65 virtual void OnSomeRead(pid_t pid, const std::string& type, 66 const std::string& output) OVERRIDE { 67 EXPECT_EQ(type, kStdoutType); 68 EXPECT_EQ(pid_, pid); 69 70 bool valid = true; 71 for (size_t i = 0; i < output.length(); i++) { 72 // The character output[i] should be next in at least one of the lines we 73 // are testing. 74 valid = (ProcessReceivedCharacter(output[i], 0) || 75 ProcessReceivedCharacter(output[i], 1)); 76 EXPECT_TRUE(valid) << "Received: " << output; 77 } 78 79 if (!valid || TestSucceeded()) { 80 base::MessageLoop::current()->PostTask(FROM_HERE, 81 base::MessageLoop::QuitClosure()); 82 } 83 } 84 85 virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE { 86 for (int i = 0; i < kTestLineNum; i++) { 87 EXPECT_TRUE(registry->SendInput(pid_, kTestLineToSend)); 88 } 89 } 90 91 private: 92 bool ProcessReceivedCharacter(char received, size_t stream) { 93 if (stream >= arraysize(left_to_check_index_)) 94 return false; 95 bool success = left_to_check_index_[stream] < expected_line_.length() && 96 expected_line_[left_to_check_index_[stream]] == received; 97 if (success) 98 left_to_check_index_[stream]++; 99 if (left_to_check_index_[stream] == expected_line_.length() && 100 lines_left_ > 0) { 101 // Take another line to test for this stream, if there are any lines left. 102 // If not, this stream is done. 103 left_to_check_index_[stream] = 0; 104 lines_left_--; 105 } 106 return success; 107 } 108 109 bool TestSucceeded() { 110 return left_to_check_index_[0] == expected_line_.length() && 111 left_to_check_index_[1] == expected_line_.length() && 112 lines_left_ == 0; 113 } 114 115 size_t left_to_check_index_[2]; 116 size_t lines_left_; 117 std::string expected_line_; 118 }; 119 120 class RegistryNotifiedOnProcessExitTestRunner : public TestRunner { 121 public: 122 virtual ~RegistryNotifiedOnProcessExitTestRunner() {} 123 124 virtual void SetupExpectations(pid_t pid) OVERRIDE { 125 output_received_ = false; 126 pid_ = pid; 127 } 128 129 virtual void OnSomeRead(pid_t pid, const std::string& type, 130 const std::string& output) OVERRIDE { 131 EXPECT_EQ(pid_, pid); 132 if (!output_received_) { 133 output_received_ = true; 134 EXPECT_EQ(type, "stdout"); 135 EXPECT_EQ(output, "p"); 136 base::KillProcess(pid_, 0 , true); 137 return; 138 } 139 EXPECT_EQ("exit", type); 140 base::MessageLoop::current()->PostTask(FROM_HERE, 141 base::MessageLoop::QuitClosure()); 142 } 143 144 virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE { 145 EXPECT_TRUE(registry->SendInput(pid_, "p")); 146 } 147 148 private: 149 bool output_received_; 150 }; 151 152 class SigIntTestRunner : public TestRunner { 153 public: 154 virtual ~SigIntTestRunner() {} 155 156 virtual void SetupExpectations(pid_t pid) OVERRIDE { 157 pid_ = pid; 158 } 159 160 virtual void OnSomeRead(pid_t pid, const std::string& type, 161 const std::string& output) OVERRIDE { 162 EXPECT_EQ(pid_, pid); 163 // We may receive ^C on stdout, but we don't care about that, as long as we 164 // eventually received exit event. 165 if (type == "exit") { 166 base::MessageLoop::current()->PostTask(FROM_HERE, 167 base::MessageLoop::QuitClosure()); 168 } 169 } 170 171 virtual void StartRegistryTest(ProcessProxyRegistry* registry) OVERRIDE { 172 // Send SingInt and verify the process exited. 173 EXPECT_TRUE(registry->SendInput(pid_, "\003")); 174 } 175 }; 176 177 } // namespace 178 179 class ProcessProxyTest : public testing::Test { 180 public: 181 ProcessProxyTest() {} 182 virtual ~ProcessProxyTest() {} 183 184 protected: 185 void InitRegistryTest() { 186 registry_ = ProcessProxyRegistry::Get(); 187 188 EXPECT_TRUE(registry_->OpenProcess( 189 kCatCommand, &pid_, 190 base::Bind(&TestRunner::OnSomeRead, 191 base::Unretained(test_runner_.get())))); 192 193 test_runner_->SetupExpectations(pid_); 194 test_runner_->StartRegistryTest(registry_); 195 } 196 197 void EndRegistryTest() { 198 registry_->CloseProcess(pid_); 199 200 base::TerminationStatus status = base::GetTerminationStatus(pid_, NULL); 201 EXPECT_NE(base::TERMINATION_STATUS_STILL_RUNNING, status); 202 if (status == base::TERMINATION_STATUS_STILL_RUNNING) 203 base::KillProcess(pid_, 0, true); 204 205 base::MessageLoop::current()->PostTask(FROM_HERE, 206 base::MessageLoop::QuitClosure()); 207 } 208 209 void RunTest() { 210 base::MessageLoop::current()->PostTask( 211 FROM_HERE, 212 base::Bind(&ProcessProxyTest::InitRegistryTest, 213 base::Unretained(this))); 214 215 // Wait until all data from output watcher is received (QuitTask will be 216 // fired on watcher thread). 217 base::MessageLoop::current()->Run(); 218 219 base::MessageLoop::current()->PostTask( 220 FROM_HERE, 221 base::Bind(&ProcessProxyTest::EndRegistryTest, 222 base::Unretained(this))); 223 224 // Wait until we clean up the process proxy. 225 base::MessageLoop::current()->Run(); 226 } 227 228 scoped_ptr<TestRunner> test_runner_; 229 230 private: 231 ProcessProxyRegistry* registry_; 232 pid_t pid_; 233 234 base::MessageLoop message_loop_; 235 }; 236 237 // Test will open new process that will run cat command, and verify data we 238 // write to process gets echoed back. 239 TEST_F(ProcessProxyTest, RegistryTest) { 240 test_runner_.reset(new RegistryTestRunner()); 241 RunTest(); 242 } 243 244 // Open new process, then kill it. Verifiy that we detect when the process dies. 245 TEST_F(ProcessProxyTest, RegistryNotifiedOnProcessExit) { 246 test_runner_.reset(new RegistryNotifiedOnProcessExitTestRunner()); 247 RunTest(); 248 } 249 250 // Test verifies that \003 message send to process is processed as SigInt. 251 // Timing out on the waterfall: http://crbug.com/115064 252 TEST_F(ProcessProxyTest, DISABLED_SigInt) { 253 test_runner_.reset(new SigIntTestRunner()); 254 RunTest(); 255 } 256 257 } // namespace chromeos 258