process_proxy_unittest.cc 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  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. #include <gtest/gtest.h>
  5. #include <stddef.h>
  6. #include <memory>
  7. #include <string>
  8. #include "base/at_exit.h"
  9. #include "base/bind.h"
  10. #include "base/command_line.h"
  11. #include "base/location.h"
  12. #include "base/memory/raw_ptr.h"
  13. #include "base/process/kill.h"
  14. #include "base/process/process.h"
  15. #include "base/run_loop.h"
  16. #include "base/task/single_thread_task_runner.h"
  17. #include "base/test/task_environment.h"
  18. #include "base/threading/sequenced_task_runner_handle.h"
  19. #include "base/threading/thread.h"
  20. #include "base/threading/thread_task_runner_handle.h"
  21. #include "chromeos/process_proxy/process_proxy_registry.h"
  22. namespace chromeos {
  23. namespace {
  24. // The test line must have all distinct characters.
  25. const char kTestLineToSend[] = "abcdefgh\n";
  26. const char kTestLineExpected[] = "abcdefgh\r\n";
  27. const char kCatCommand[] = "cat";
  28. const char kFakeUserHash[] = "0123456789abcdef";
  29. const char kStdoutType[] = "stdout";
  30. const int kTestLineNum = 100;
  31. void RunOnTaskRunner(
  32. base::OnceClosure closure,
  33. const scoped_refptr<base::SequencedTaskRunner>& task_runner) {
  34. task_runner->PostTask(FROM_HERE, std::move(closure));
  35. }
  36. class TestRunner {
  37. public:
  38. TestRunner() = default;
  39. virtual ~TestRunner() = default;
  40. virtual void SetupExpectations(const std::string& id,
  41. const base::Process* process) = 0;
  42. virtual void OnSomeRead(const std::string& id,
  43. const std::string& type,
  44. const std::string& output) = 0;
  45. virtual void StartRegistryTest(ProcessProxyRegistry* registry) = 0;
  46. void set_done_read_closure(base::OnceClosure done_closure) {
  47. done_read_closure_ = std::move(done_closure);
  48. }
  49. protected:
  50. std::string id_;
  51. raw_ptr<const base::Process> process_;
  52. base::OnceClosure done_read_closure_;
  53. };
  54. class RegistryTestRunner : public TestRunner {
  55. public:
  56. ~RegistryTestRunner() override = default;
  57. void SetupExpectations(const std::string& id,
  58. const base::Process* process) override {
  59. id_ = id;
  60. process_ = process;
  61. left_to_check_index_[0] = 0;
  62. left_to_check_index_[1] = 0;
  63. // We consider that a line processing has started if a value in
  64. // left_to_check__[index] is set to 0, thus -2.
  65. lines_left_ = 2 * kTestLineNum - 2;
  66. expected_line_ = kTestLineExpected;
  67. }
  68. // Method to test validity of received input. We will receive two streams of
  69. // the same data. (input will be echoed twice by the testing process). Each
  70. // stream will contain the same string repeated |kTestLineNum| times. So we
  71. // have to match 2 * |kTestLineNum| lines. The problem is the received lines
  72. // from different streams may be interleaved (e.g. we may receive
  73. // abc|abcdef|defgh|gh). To deal with that, we allow to test received text
  74. // against two lines. The lines MUST NOT have two same characters for this
  75. // algorithm to work.
  76. void OnSomeRead(const std::string& id,
  77. const std::string& type,
  78. const std::string& output) override {
  79. EXPECT_EQ(type, kStdoutType);
  80. EXPECT_EQ(id_, id);
  81. bool valid = true;
  82. for (size_t i = 0; i < output.length(); i++) {
  83. // The character output[i] should be next in at least one of the lines we
  84. // are testing.
  85. valid = (ProcessReceivedCharacter(output[i], 0) ||
  86. ProcessReceivedCharacter(output[i], 1));
  87. EXPECT_TRUE(valid) << "Received: " << output;
  88. }
  89. if (!valid || TestSucceeded()) {
  90. ASSERT_FALSE(done_read_closure_.is_null());
  91. std::move(done_read_closure_).Run();
  92. }
  93. }
  94. void StartRegistryTest(ProcessProxyRegistry* registry) override {
  95. for (int i = 0; i < kTestLineNum; i++) {
  96. registry->SendInput(id_, kTestLineToSend, base::BindOnce([](bool result) {
  97. EXPECT_TRUE(result);
  98. }));
  99. }
  100. }
  101. private:
  102. bool ProcessReceivedCharacter(char received, size_t stream) {
  103. if (stream >= std::size(left_to_check_index_))
  104. return false;
  105. bool success = left_to_check_index_[stream] < expected_line_.length() &&
  106. expected_line_[left_to_check_index_[stream]] == received;
  107. if (success)
  108. left_to_check_index_[stream]++;
  109. if (left_to_check_index_[stream] == expected_line_.length() &&
  110. lines_left_ > 0) {
  111. // Take another line to test for this stream, if there are any lines left.
  112. // If not, this stream is done.
  113. left_to_check_index_[stream] = 0;
  114. lines_left_--;
  115. }
  116. return success;
  117. }
  118. bool TestSucceeded() {
  119. return left_to_check_index_[0] == expected_line_.length() &&
  120. left_to_check_index_[1] == expected_line_.length() &&
  121. lines_left_ == 0;
  122. }
  123. size_t left_to_check_index_[2];
  124. size_t lines_left_;
  125. std::string expected_line_;
  126. };
  127. class RegistryNotifiedOnProcessExitTestRunner : public TestRunner {
  128. public:
  129. ~RegistryNotifiedOnProcessExitTestRunner() override = default;
  130. void SetupExpectations(const std::string& id,
  131. const base::Process* process) override {
  132. output_received_ = false;
  133. id_ = id;
  134. process_ = process;
  135. }
  136. void OnSomeRead(const std::string& id,
  137. const std::string& type,
  138. const std::string& output) override {
  139. EXPECT_EQ(id_, id);
  140. if (!output_received_) {
  141. base::ScopedAllowBaseSyncPrimitivesForTesting allow_sync_primitives;
  142. output_received_ = true;
  143. EXPECT_EQ(type, "stdout");
  144. EXPECT_EQ(output, "p");
  145. process_->Terminate(0, true);
  146. return;
  147. }
  148. EXPECT_EQ("exit", type);
  149. ASSERT_FALSE(done_read_closure_.is_null());
  150. std::move(done_read_closure_).Run();
  151. }
  152. void StartRegistryTest(ProcessProxyRegistry* registry) override {
  153. registry->SendInput(
  154. id_, "p", base::BindOnce([](bool result) { EXPECT_TRUE(result); }));
  155. }
  156. private:
  157. bool output_received_;
  158. };
  159. } // namespace
  160. class ProcessProxyTest : public testing::Test {
  161. public:
  162. ProcessProxyTest() = default;
  163. ~ProcessProxyTest() override = default;
  164. protected:
  165. void InitRegistryTest(base::OnceClosure done_closure) {
  166. registry_ = ProcessProxyRegistry::Get();
  167. base::CommandLine cmdline{{kCatCommand}};
  168. bool success = registry_->OpenProcess(
  169. cmdline, kFakeUserHash,
  170. base::BindRepeating(&ProcessProxyTest::HandleRead,
  171. base::Unretained(this)),
  172. &id_);
  173. process_ = registry_->GetProcessForTesting(id_);
  174. EXPECT_TRUE(success);
  175. test_runner_->set_done_read_closure(std::move(done_closure));
  176. test_runner_->SetupExpectations(id_, process_);
  177. test_runner_->StartRegistryTest(registry_);
  178. }
  179. void HandleRead(const std::string& id,
  180. const std::string& output_type,
  181. const std::string& output) {
  182. test_runner_->OnSomeRead(id, output_type, output);
  183. registry_->AckOutput(id);
  184. }
  185. void EndRegistryTest(base::OnceClosure done_closure) {
  186. base::ScopedAllowBaseSyncPrimitivesForTesting allow_sync_primitives;
  187. registry_->CloseProcess(id_);
  188. int unused_exit_code = 0;
  189. base::TerminationStatus status =
  190. base::GetTerminationStatus(process_->Handle(), &unused_exit_code);
  191. EXPECT_NE(base::TERMINATION_STATUS_STILL_RUNNING, status);
  192. if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
  193. process_->Terminate(0, true);
  194. }
  195. registry_->ShutDown();
  196. std::move(done_closure).Run();
  197. }
  198. void RunTest() {
  199. base::RunLoop init_registry_waiter;
  200. ProcessProxyRegistry::GetTaskRunner()->PostTask(
  201. FROM_HERE,
  202. base::BindOnce(
  203. &ProcessProxyTest::InitRegistryTest, base::Unretained(this),
  204. base::BindOnce(&RunOnTaskRunner, init_registry_waiter.QuitClosure(),
  205. base::SequencedTaskRunnerHandle::Get())));
  206. // Wait until all data from output watcher is received (QuitTask will be
  207. // fired on watcher thread).
  208. init_registry_waiter.Run();
  209. base::RunLoop end_registry_waiter;
  210. ProcessProxyRegistry::GetTaskRunner()->PostTask(
  211. FROM_HERE,
  212. base::BindOnce(
  213. &ProcessProxyTest::EndRegistryTest, base::Unretained(this),
  214. base::BindOnce(&RunOnTaskRunner, end_registry_waiter.QuitClosure(),
  215. base::SequencedTaskRunnerHandle::Get())));
  216. // Wait until we clean up the process proxy.
  217. end_registry_waiter.Run();
  218. }
  219. std::unique_ptr<TestRunner> test_runner_;
  220. private:
  221. // Destroys ProcessProxyRegistry LazyInstance after each test.
  222. base::ShadowingAtExitManager shadowing_at_exit_manager_;
  223. raw_ptr<ProcessProxyRegistry> registry_;
  224. std::string id_;
  225. raw_ptr<const base::Process> process_ = nullptr;
  226. base::test::TaskEnvironment task_environment_;
  227. };
  228. // Test will open new process that will run cat command, and verify data we
  229. // write to process gets echoed back.
  230. TEST_F(ProcessProxyTest, RegistryTest) {
  231. test_runner_ = std::make_unique<RegistryTestRunner>();
  232. RunTest();
  233. }
  234. // Open new process, then kill it. Verifiy that we detect when the process dies.
  235. //
  236. // Disabled due to flakiness: https://crbug.com/1151205
  237. TEST_F(ProcessProxyTest, DISABLED_RegistryNotifiedOnProcessExit) {
  238. test_runner_ = std::make_unique<RegistryNotifiedOnProcessExitTestRunner>();
  239. RunTest();
  240. }
  241. } // namespace chromeos