[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 1 | // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 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> |
avi | 6e1a22d | 2015-12-21 03:43:20 | [diff] [blame] | 6 | #include <stddef.h> |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 7 | |
dcheng | 0a6e80c | 2016-04-08 18:37:38 | [diff] [blame] | 8 | #include <memory> |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 9 | #include <string> |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 10 | |
| 11 | #include "base/bind.h" |
skyostil | 1472c84 | 2015-06-11 18:40:24 | [diff] [blame] | 12 | #include "base/location.h" |
[email protected] | 99855736 | 2013-07-23 14:12:13 | [diff] [blame] | 13 | #include "base/process/kill.h" |
rvargas | f8d789c | 2015-04-01 04:10:12 | [diff] [blame] | 14 | #include "base/process/process.h" |
skyostil | 1472c84 | 2015-06-11 18:40:24 | [diff] [blame] | 15 | #include "base/single_thread_task_runner.h" |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 16 | #include "base/threading/thread.h" |
gab | d85cc46b | 2016-05-11 18:23:20 | [diff] [blame] | 17 | #include "base/threading/thread_task_runner_handle.h" |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 18 | #include "chromeos/process_proxy/process_proxy_registry.h" |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 19 | |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 20 | namespace chromeos { |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 21 | |
| 22 | namespace { |
| 23 | |
[email protected] | 56f3a81 | 2012-03-20 17:13:19 | [diff] [blame] | 24 | // The test line must have all distinct characters. |
| 25 | const char kTestLineToSend[] = "abcdefgh\n"; |
| 26 | const char kTestLineExpected[] = "abcdefgh\r\n"; |
| 27 | |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 28 | const char kCatCommand[] = "cat"; |
| 29 | const char kStdoutType[] = "stdout"; |
| 30 | const int kTestLineNum = 100; |
| 31 | |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 32 | class TestRunner { |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 33 | public: |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 34 | virtual ~TestRunner() {} |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 35 | virtual void SetupExpectations(int terminal_id) = 0; |
| 36 | virtual void OnSomeRead(int terminal_id, |
| 37 | const std::string& type, |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 38 | const std::string& output) = 0; |
| 39 | virtual void StartRegistryTest(ProcessProxyRegistry* registry) = 0; |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 40 | |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 41 | protected: |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 42 | int terminal_id_; |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 43 | }; |
| 44 | |
| 45 | class RegistryTestRunner : public TestRunner { |
| 46 | public: |
dcheng | ae98daa | 2015-01-21 20:30:49 | [diff] [blame] | 47 | ~RegistryTestRunner() override {} |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 48 | |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 49 | void SetupExpectations(int terminal_id) override { |
| 50 | terminal_id_ = terminal_id; |
[email protected] | 56f3a81 | 2012-03-20 17:13:19 | [diff] [blame] | 51 | left_to_check_index_[0] = 0; |
| 52 | left_to_check_index_[1] = 0; |
| 53 | // We consider that a line processing has started if a value in |
| 54 | // left_to_check__[index] is set to 0, thus -2. |
| 55 | lines_left_ = 2 * kTestLineNum - 2; |
| 56 | expected_line_ = kTestLineExpected; |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 57 | } |
| 58 | |
[email protected] | 56f3a81 | 2012-03-20 17:13:19 | [diff] [blame] | 59 | // Method to test validity of received input. We will receive two streams of |
| 60 | // the same data. (input will be echoed twice by the testing process). Each |
| 61 | // stream will contain the same string repeated |kTestLineNum| times. So we |
| 62 | // have to match 2 * |kTestLineNum| lines. The problem is the received lines |
| 63 | // from different streams may be interleaved (e.g. we may receive |
| 64 | // abc|abcdef|defgh|gh). To deal with that, we allow to test received text |
| 65 | // against two lines. The lines MUST NOT have two same characters for this |
| 66 | // algorithm to work. |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 67 | void OnSomeRead(int terminal_id, |
dcheng | ae98daa | 2015-01-21 20:30:49 | [diff] [blame] | 68 | const std::string& type, |
| 69 | const std::string& output) override { |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 70 | EXPECT_EQ(type, kStdoutType); |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 71 | EXPECT_EQ(terminal_id_, terminal_id); |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 72 | |
[email protected] | 56f3a81 | 2012-03-20 17:13:19 | [diff] [blame] | 73 | bool valid = true; |
| 74 | for (size_t i = 0; i < output.length(); i++) { |
| 75 | // The character output[i] should be next in at least one of the lines we |
| 76 | // are testing. |
| 77 | valid = (ProcessReceivedCharacter(output[i], 0) || |
| 78 | ProcessReceivedCharacter(output[i], 1)); |
| 79 | EXPECT_TRUE(valid) << "Received: " << output; |
| 80 | } |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 81 | |
[email protected] | 56f3a81 | 2012-03-20 17:13:19 | [diff] [blame] | 82 | if (!valid || TestSucceeded()) { |
skyostil | 1472c84 | 2015-06-11 18:40:24 | [diff] [blame] | 83 | base::ThreadTaskRunnerHandle::Get()->PostTask( |
ki.stfu | 55e0b36 | 2015-10-12 17:45:55 | [diff] [blame] | 84 | FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 85 | } |
| 86 | } |
| 87 | |
dcheng | ae98daa | 2015-01-21 20:30:49 | [diff] [blame] | 88 | void StartRegistryTest(ProcessProxyRegistry* registry) override { |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 89 | for (int i = 0; i < kTestLineNum; i++) { |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 90 | EXPECT_TRUE(registry->SendInput(terminal_id_, kTestLineToSend)); |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 91 | } |
| 92 | } |
| 93 | |
| 94 | private: |
[email protected] | 56f3a81 | 2012-03-20 17:13:19 | [diff] [blame] | 95 | bool ProcessReceivedCharacter(char received, size_t stream) { |
[email protected] | b1701a7 | 2012-03-22 23:59:03 | [diff] [blame] | 96 | if (stream >= arraysize(left_to_check_index_)) |
[email protected] | 56f3a81 | 2012-03-20 17:13:19 | [diff] [blame] | 97 | return false; |
| 98 | bool success = left_to_check_index_[stream] < expected_line_.length() && |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 99 | expected_line_[left_to_check_index_[stream]] == received; |
[email protected] | 56f3a81 | 2012-03-20 17:13:19 | [diff] [blame] | 100 | if (success) |
| 101 | left_to_check_index_[stream]++; |
| 102 | if (left_to_check_index_[stream] == expected_line_.length() && |
| 103 | lines_left_ > 0) { |
| 104 | // Take another line to test for this stream, if there are any lines left. |
| 105 | // If not, this stream is done. |
| 106 | left_to_check_index_[stream] = 0; |
| 107 | lines_left_--; |
| 108 | } |
| 109 | return success; |
| 110 | } |
| 111 | |
| 112 | bool TestSucceeded() { |
| 113 | return left_to_check_index_[0] == expected_line_.length() && |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 114 | left_to_check_index_[1] == expected_line_.length() && |
| 115 | lines_left_ == 0; |
[email protected] | 56f3a81 | 2012-03-20 17:13:19 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | size_t left_to_check_index_[2]; |
| 119 | size_t lines_left_; |
| 120 | std::string expected_line_; |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 121 | }; |
| 122 | |
| 123 | class RegistryNotifiedOnProcessExitTestRunner : public TestRunner { |
| 124 | public: |
dcheng | ae98daa | 2015-01-21 20:30:49 | [diff] [blame] | 125 | ~RegistryNotifiedOnProcessExitTestRunner() override {} |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 126 | |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 127 | void SetupExpectations(int terminal_id) override { |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 128 | output_received_ = false; |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 129 | terminal_id_ = terminal_id; |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 130 | } |
| 131 | |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 132 | void OnSomeRead(int terminal_id, |
dcheng | ae98daa | 2015-01-21 20:30:49 | [diff] [blame] | 133 | const std::string& type, |
| 134 | const std::string& output) override { |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 135 | EXPECT_EQ(terminal_id_, terminal_id); |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 136 | if (!output_received_) { |
| 137 | output_received_ = true; |
| 138 | EXPECT_EQ(type, "stdout"); |
| 139 | EXPECT_EQ(output, "p"); |
rvargas | f8d789c | 2015-04-01 04:10:12 | [diff] [blame] | 140 | base::Process process = |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 141 | base::Process::DeprecatedGetProcessFromHandle(terminal_id_); |
rvargas | f8d789c | 2015-04-01 04:10:12 | [diff] [blame] | 142 | process.Terminate(0, true); |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 143 | return; |
| 144 | } |
| 145 | EXPECT_EQ("exit", type); |
skyostil | 1472c84 | 2015-06-11 18:40:24 | [diff] [blame] | 146 | base::ThreadTaskRunnerHandle::Get()->PostTask( |
ki.stfu | 55e0b36 | 2015-10-12 17:45:55 | [diff] [blame] | 147 | FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 148 | } |
| 149 | |
dcheng | ae98daa | 2015-01-21 20:30:49 | [diff] [blame] | 150 | void StartRegistryTest(ProcessProxyRegistry* registry) override { |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 151 | EXPECT_TRUE(registry->SendInput(terminal_id_, "p")); |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 152 | } |
| 153 | |
| 154 | private: |
| 155 | bool output_received_; |
| 156 | }; |
| 157 | |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 158 | } // namespace |
| 159 | |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 160 | class ProcessProxyTest : public testing::Test { |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 161 | public: |
| 162 | ProcessProxyTest() {} |
dcheng | ae98daa | 2015-01-21 20:30:49 | [diff] [blame] | 163 | ~ProcessProxyTest() override {} |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 164 | |
| 165 | protected: |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 166 | void InitRegistryTest() { |
| 167 | registry_ = ProcessProxyRegistry::Get(); |
| 168 | |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 169 | terminal_id_ = registry_->OpenProcess( |
| 170 | kCatCommand, |
| 171 | base::Bind(&ProcessProxyTest::HandleRead, base::Unretained(this))); |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 172 | |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 173 | EXPECT_GE(terminal_id_, 0); |
| 174 | test_runner_->SetupExpectations(terminal_id_); |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 175 | test_runner_->StartRegistryTest(registry_); |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 176 | } |
| 177 | |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 178 | void HandleRead(int terminal_id, |
| 179 | const std::string& output_type, |
| 180 | const std::string& output) { |
| 181 | test_runner_->OnSomeRead(terminal_id, output_type, output); |
| 182 | registry_->AckOutput(terminal_id); |
| 183 | } |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 184 | |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 185 | void EndRegistryTest() { |
| 186 | registry_->CloseProcess(terminal_id_); |
| 187 | |
| 188 | base::TerminationStatus status = |
| 189 | base::GetTerminationStatus(terminal_id_, NULL); |
[email protected] | dc86a86d | 2011-12-21 00:11:36 | [diff] [blame] | 190 | EXPECT_NE(base::TERMINATION_STATUS_STILL_RUNNING, status); |
rvargas | f8d789c | 2015-04-01 04:10:12 | [diff] [blame] | 191 | if (status == base::TERMINATION_STATUS_STILL_RUNNING) { |
| 192 | base::Process process = |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 193 | base::Process::DeprecatedGetProcessFromHandle(terminal_id_); |
rvargas | f8d789c | 2015-04-01 04:10:12 | [diff] [blame] | 194 | process.Terminate(0, true); |
| 195 | } |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 196 | |
tbarzic | 6ca5055 | 2015-08-10 22:32:45 | [diff] [blame] | 197 | registry_->ShutDown(); |
| 198 | |
skyostil | 1472c84 | 2015-06-11 18:40:24 | [diff] [blame] | 199 | base::ThreadTaskRunnerHandle::Get()->PostTask( |
ki.stfu | 55e0b36 | 2015-10-12 17:45:55 | [diff] [blame] | 200 | FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 201 | } |
| 202 | |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 203 | void RunTest() { |
skyostil | 1472c84 | 2015-06-11 18:40:24 | [diff] [blame] | 204 | base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 205 | FROM_HERE, base::Bind(&ProcessProxyTest::InitRegistryTest, |
| 206 | base::Unretained(this))); |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 207 | |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 208 | // Wait until all data from output watcher is received (QuitTask will be |
| 209 | // fired on watcher thread). |
[email protected] | df90563 | 2013-05-29 23:04:36 | [diff] [blame] | 210 | base::MessageLoop::current()->Run(); |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 211 | |
skyostil | 1472c84 | 2015-06-11 18:40:24 | [diff] [blame] | 212 | base::ThreadTaskRunnerHandle::Get()->PostTask( |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 213 | FROM_HERE, |
skyostil | 1472c84 | 2015-06-11 18:40:24 | [diff] [blame] | 214 | base::Bind(&ProcessProxyTest::EndRegistryTest, base::Unretained(this))); |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 215 | |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 216 | // Wait until we clean up the process proxy. |
[email protected] | df90563 | 2013-05-29 23:04:36 | [diff] [blame] | 217 | base::MessageLoop::current()->Run(); |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 218 | } |
| 219 | |
dcheng | 0a6e80c | 2016-04-08 18:37:38 | [diff] [blame] | 220 | std::unique_ptr<TestRunner> test_runner_; |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 221 | |
| 222 | private: |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 223 | ProcessProxyRegistry* registry_; |
tbarzic | 170f12c | 2016-01-08 05:15:29 | [diff] [blame] | 224 | int terminal_id_; |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 225 | |
[email protected] | df90563 | 2013-05-29 23:04:36 | [diff] [blame] | 226 | base::MessageLoop message_loop_; |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 227 | }; |
| 228 | |
| 229 | // Test will open new process that will run cat command, and verify data we |
| 230 | // write to process gets echoed back. |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 231 | TEST_F(ProcessProxyTest, RegistryTest) { |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 232 | test_runner_.reset(new RegistryTestRunner()); |
| 233 | RunTest(); |
[email protected] | 8f42798 | 2011-12-13 23:40:23 | [diff] [blame] | 234 | } |
| 235 | |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 236 | // Open new process, then kill it. Verifiy that we detect when the process dies. |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 237 | TEST_F(ProcessProxyTest, RegistryNotifiedOnProcessExit) { |
[email protected] | a504ba7 | 2012-01-25 01:42:57 | [diff] [blame] | 238 | test_runner_.reset(new RegistryNotifiedOnProcessExitTestRunner()); |
| 239 | RunTest(); |
| 240 | } |
| 241 | |
[email protected] | 3a01162b | 2013-03-12 20:22:48 | [diff] [blame] | 242 | } // namespace chromeos |