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