process_output_watcher_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  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 "chromeos/process_proxy/process_output_watcher.h"
  5. #include <gtest/gtest.h>
  6. #include <stddef.h>
  7. #include <memory>
  8. #include <queue>
  9. #include <string>
  10. #include <vector>
  11. #include "base/bind.h"
  12. #include "base/callback.h"
  13. #include "base/files/file_util.h"
  14. #include "base/location.h"
  15. #include "base/message_loop/message_pump_type.h"
  16. #include "base/posix/eintr_wrapper.h"
  17. #include "base/run_loop.h"
  18. #include "base/strings/string_util.h"
  19. #include "base/task/single_thread_task_runner.h"
  20. #include "base/test/task_environment.h"
  21. #include "base/threading/thread.h"
  22. namespace chromeos {
  23. namespace {
  24. struct TestCase {
  25. TestCase(const std::string& input, bool send_terminating_null)
  26. : input(input),
  27. should_send_terminating_null(send_terminating_null),
  28. expected_output(input) {}
  29. // Conctructor for cases where the output is not expected to be the same as
  30. // input.
  31. TestCase(const std::string& input,
  32. bool send_terminating_null,
  33. const std::string& expected_output)
  34. : input(input),
  35. should_send_terminating_null(send_terminating_null),
  36. expected_output(expected_output) {}
  37. std::string input;
  38. bool should_send_terminating_null;
  39. std::string expected_output;
  40. };
  41. class ProcessWatcherExpectations {
  42. public:
  43. ProcessWatcherExpectations() = default;
  44. void SetTestCase(const TestCase& test_case) {
  45. received_from_out_ = 0;
  46. out_expectations_ = test_case.expected_output;
  47. if (test_case.should_send_terminating_null)
  48. out_expectations_.append(std::string("", 1));
  49. }
  50. bool CheckExpectations(const std::string& data, ProcessOutputType type) {
  51. EXPECT_EQ(PROCESS_OUTPUT_TYPE_OUT, type);
  52. if (type != PROCESS_OUTPUT_TYPE_OUT)
  53. return false;
  54. if (out_expectations_.length() == 0 && data.length() == 0)
  55. return true;
  56. EXPECT_LT(received_from_out_, out_expectations_.length());
  57. if (received_from_out_ >= out_expectations_.length())
  58. return false;
  59. EXPECT_EQ(received_from_out_,
  60. out_expectations_.find(data, received_from_out_));
  61. if (received_from_out_ != out_expectations_.find(data, received_from_out_))
  62. return false;
  63. received_from_out_ += data.length();
  64. return true;
  65. }
  66. bool IsDone() {
  67. return received_from_out_ >= out_expectations_.length();
  68. }
  69. private:
  70. std::string out_expectations_;
  71. size_t received_from_out_;
  72. };
  73. void StopProcessOutputWatcher(std::unique_ptr<ProcessOutputWatcher> watcher) {
  74. // Just deleting |watcher| if sufficient.
  75. }
  76. } // namespace
  77. class ProcessOutputWatcherTest : public testing::Test {
  78. public:
  79. ProcessOutputWatcherTest() : output_watch_thread_started_(false),
  80. failed_(false) {
  81. }
  82. ~ProcessOutputWatcherTest() override = default;
  83. void TearDown() override {
  84. if (output_watch_thread_started_)
  85. output_watch_thread_->Stop();
  86. }
  87. void OnRead(ProcessOutputType type, const std::string& output) {
  88. ASSERT_FALSE(failed_);
  89. // There may be an EXIT signal sent during test tear down (which is sent
  90. // by process output watcher when master end of test pseudo-terminal is
  91. // closed). If this happens, ignore it. If EXIT is seen before test
  92. // expectations are met, fall through in order to fail the test.
  93. if (type == PROCESS_OUTPUT_TYPE_EXIT && expectations_.IsDone()) {
  94. ASSERT_TRUE(test_case_done_callback_.is_null());
  95. return;
  96. }
  97. failed_ = !expectations_.CheckExpectations(output, type);
  98. if (failed_ || expectations_.IsDone()) {
  99. ASSERT_FALSE(test_case_done_callback_.is_null());
  100. task_environment_.GetMainThreadTaskRunner()->PostTask(
  101. FROM_HERE, std::move(test_case_done_callback_));
  102. test_case_done_callback_.Reset();
  103. }
  104. output_watch_thread_->task_runner()->PostTask(
  105. FROM_HERE, base::BindOnce(&ProcessOutputWatcher::AckOutput,
  106. base::Unretained(output_watcher_.get())));
  107. }
  108. protected:
  109. std::string VeryLongString() {
  110. std::string result = "0123456789";
  111. for (int i = 0; i < 8; i++)
  112. result = result.append(result);
  113. return result;
  114. }
  115. void RunTest(const std::vector<TestCase>& test_cases) {
  116. ASSERT_FALSE(output_watch_thread_started_);
  117. output_watch_thread_ =
  118. std::make_unique<base::Thread>("ProcessOutpuWatchThread");
  119. output_watch_thread_started_ = output_watch_thread_->StartWithOptions(
  120. base::Thread::Options(base::MessagePumpType::IO, 0));
  121. ASSERT_TRUE(output_watch_thread_started_);
  122. int pt_pipe[2];
  123. ASSERT_FALSE(HANDLE_EINTR(pipe(pt_pipe)));
  124. output_watcher_ = std::make_unique<ProcessOutputWatcher>(
  125. pt_pipe[0], base::BindRepeating(&ProcessOutputWatcherTest::OnRead,
  126. base::Unretained(this)));
  127. output_watch_thread_->task_runner()->PostTask(
  128. FROM_HERE, base::BindOnce(&ProcessOutputWatcher::Start,
  129. base::Unretained(output_watcher_.get())));
  130. for (size_t i = 0; i < test_cases.size(); i++) {
  131. expectations_.SetTestCase(test_cases[i]);
  132. base::RunLoop run_loop;
  133. ASSERT_TRUE(test_case_done_callback_.is_null());
  134. test_case_done_callback_ = run_loop.QuitClosure();
  135. const std::string& test_str = test_cases[i].input;
  136. // Let's make inputs not NULL terminated, unless other is specified in
  137. // the test case.
  138. ssize_t test_size = test_str.length() * sizeof(*test_str.c_str());
  139. if (test_cases[i].should_send_terminating_null)
  140. test_size += sizeof(*test_str.c_str());
  141. EXPECT_TRUE(base::WriteFileDescriptor(
  142. pt_pipe[1], base::StringPiece(test_str.c_str(), test_size)));
  143. run_loop.Run();
  144. EXPECT_TRUE(expectations_.IsDone());
  145. if (failed_)
  146. break;
  147. }
  148. output_watch_thread_->task_runner()->PostTask(
  149. FROM_HERE,
  150. base::BindOnce(&StopProcessOutputWatcher, std::move(output_watcher_)));
  151. EXPECT_NE(-1, IGNORE_EINTR(close(pt_pipe[1])));
  152. }
  153. private:
  154. base::OnceClosure test_case_done_callback_;
  155. base::test::SingleThreadTaskEnvironment task_environment_;
  156. std::unique_ptr<base::Thread> output_watch_thread_;
  157. bool output_watch_thread_started_ = false;
  158. std::unique_ptr<ProcessOutputWatcher> output_watcher_;
  159. bool failed_ = false;
  160. ProcessWatcherExpectations expectations_;
  161. std::vector<TestCase> exp;
  162. };
  163. TEST_F(ProcessOutputWatcherTest, OutputWatcher) {
  164. std::vector<TestCase> test_cases;
  165. test_cases.push_back(TestCase("t", false));
  166. test_cases.push_back(TestCase("testing output\n", false));
  167. test_cases.push_back(TestCase("testing error\n", false));
  168. test_cases.push_back(TestCase("testing error1\n", false));
  169. test_cases.push_back(TestCase("testing output1\n", false));
  170. test_cases.push_back(TestCase("testing output2\n", false));
  171. test_cases.push_back(TestCase("testing output3\n", false));
  172. test_cases.push_back(TestCase(VeryLongString(), false));
  173. test_cases.push_back(TestCase("testing error2\n", false));
  174. RunTest(test_cases);
  175. }
  176. TEST_F(ProcessOutputWatcherTest, SplitUTF8Character) {
  177. std::vector<TestCase> test_cases;
  178. test_cases.push_back(TestCase("test1\xc2", false, "test1"));
  179. test_cases.push_back(TestCase("\xb5test1", false, "\xc2\xb5test1"));
  180. RunTest(test_cases);
  181. }
  182. TEST_F(ProcessOutputWatcherTest, SplitSoleUTF8Character) {
  183. std::vector<TestCase> test_cases;
  184. test_cases.push_back(TestCase("\xc2", false, ""));
  185. test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
  186. RunTest(test_cases);
  187. }
  188. TEST_F(ProcessOutputWatcherTest, SplitUTF8CharacterLength3) {
  189. std::vector<TestCase> test_cases;
  190. test_cases.push_back(TestCase("test3\xe2\x82", false, "test3"));
  191. test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
  192. RunTest(test_cases);
  193. }
  194. TEST_F(ProcessOutputWatcherTest, SplitSoleUTF8CharacterThreeWays) {
  195. std::vector<TestCase> test_cases;
  196. test_cases.push_back(TestCase("\xe2", false, ""));
  197. test_cases.push_back(TestCase("\x82", false, ""));
  198. test_cases.push_back(TestCase("\xac", false, "\xe2\x82\xac"));
  199. RunTest(test_cases);
  200. }
  201. TEST_F(ProcessOutputWatcherTest, EndsWithThreeByteUTF8Character) {
  202. std::vector<TestCase> test_cases;
  203. test_cases.push_back(TestCase("test\xe2\x82\xac", false, "test\xe2\x82\xac"));
  204. RunTest(test_cases);
  205. }
  206. TEST_F(ProcessOutputWatcherTest, SoleThreeByteUTF8Character) {
  207. std::vector<TestCase> test_cases;
  208. test_cases.push_back(TestCase("\xe2\x82\xac", false, "\xe2\x82\xac"));
  209. RunTest(test_cases);
  210. }
  211. TEST_F(ProcessOutputWatcherTest, HasThreeByteUTF8Character) {
  212. std::vector<TestCase> test_cases;
  213. test_cases.push_back(
  214. TestCase("test\xe2\x82\xac_", false, "test\xe2\x82\xac_"));
  215. RunTest(test_cases);
  216. }
  217. TEST_F(ProcessOutputWatcherTest, MulitByteUTF8CharNullTerminated) {
  218. std::vector<TestCase> test_cases;
  219. test_cases.push_back(TestCase("test\xe2\x82\xac", true, "test\xe2\x82\xac"));
  220. RunTest(test_cases);
  221. }
  222. TEST_F(ProcessOutputWatcherTest, MultipleMultiByteUTF8Characters) {
  223. std::vector<TestCase> test_cases;
  224. test_cases.push_back(
  225. TestCase("test\xe2\x82\xac\xc2", false, "test\xe2\x82\xac"));
  226. test_cases.push_back(TestCase("\xb5", false, "\xc2\xb5"));
  227. RunTest(test_cases);
  228. }
  229. TEST_F(ProcessOutputWatcherTest, ContainsInvalidUTF8) {
  230. std::vector<TestCase> test_cases;
  231. test_cases.push_back(TestCase("\xc2_", false, "\xc2_"));
  232. RunTest(test_cases);
  233. }
  234. TEST_F(ProcessOutputWatcherTest, InvalidUTF8SeriesOfTrailingBytes) {
  235. std::vector<TestCase> test_cases;
  236. test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
  237. test_cases.push_back(TestCase("\x82\x82\x82", false, "\x82\x82\x82"));
  238. RunTest(test_cases);
  239. }
  240. TEST_F(ProcessOutputWatcherTest, EndsWithInvalidUTF8) {
  241. std::vector<TestCase> test_cases;
  242. test_cases.push_back(TestCase("\xff", false, "\xff"));
  243. RunTest(test_cases);
  244. }
  245. // TODO(crbug.com/1177137) Re-enable test
  246. TEST_F(ProcessOutputWatcherTest, DISABLED_FourByteUTF8) {
  247. std::vector<TestCase> test_cases;
  248. test_cases.push_back(TestCase("\xf0\xa4\xad", false, ""));
  249. test_cases.push_back(TestCase("\xa2", false, "\xf0\xa4\xad\xa2"));
  250. RunTest(test_cases);
  251. }
  252. // Verifies that sending '\0' generates PROCESS_OUTPUT_TYPE_OUT event and does
  253. // not terminate output watcher.
  254. TEST_F(ProcessOutputWatcherTest, SendNull) {
  255. std::vector<TestCase> test_cases;
  256. // This will send '\0' to output watcher.
  257. test_cases.push_back(TestCase("", true));
  258. // Let's verify that next input also gets detected (i.e. output watcher does
  259. // not exit after seeing '\0' from previous test case).
  260. test_cases.push_back(TestCase("a", true));
  261. RunTest(test_cases);
  262. }
  263. } // namespace chromeos