popen_unittest.cpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Licensed to the Apache Software Foundation (ASF) under one
  2. // or more contributor license agreements. See the NOTICE file
  3. // distributed with this work for additional information
  4. // regarding copyright ownership. The ASF licenses this file
  5. // to you under the Apache License, Version 2.0 (the
  6. // "License"); you may not use this file except in compliance
  7. // with the License. You may obtain a copy of the License at
  8. //
  9. // http://www.apache.org/licenses/LICENSE-2.0
  10. //
  11. // Unless required by applicable law or agreed to in writing,
  12. // software distributed under the License is distributed on an
  13. // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  14. // KIND, either express or implied. See the License for the
  15. // specific language governing permissions and limitations
  16. // under the License.
  17. // Date: 2017/11/06 10:57:08
  18. #include "butil/popen.h"
  19. #include "butil/errno.h"
  20. #include "butil/strings/string_piece.h"
  21. #include "butil/build_config.h"
  22. #include <gtest/gtest.h>
  23. namespace butil {
  24. extern int read_command_output_through_clone(std::ostream&, const char*);
  25. extern int read_command_output_through_popen(std::ostream&, const char*);
  26. }
  27. namespace {
  28. class PopenTest : public testing::Test {
  29. };
  30. TEST(PopenTest, posix_popen) {
  31. std::ostringstream oss;
  32. int rc = butil::read_command_output_through_popen(oss, "echo \"Hello World\"");
  33. ASSERT_EQ(0, rc) << berror(errno);
  34. ASSERT_EQ("Hello World\n", oss.str());
  35. oss.str("");
  36. rc = butil::read_command_output_through_popen(oss, "exit 1");
  37. EXPECT_EQ(1, rc) << berror(errno);
  38. ASSERT_TRUE(oss.str().empty()) << oss.str();
  39. oss.str("");
  40. rc = butil::read_command_output_through_popen(oss, "kill -9 $$");
  41. ASSERT_EQ(-1, rc);
  42. ASSERT_EQ(errno, ECHILD);
  43. ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 9"));
  44. oss.str("");
  45. rc = butil::read_command_output_through_popen(oss, "kill -15 $$");
  46. ASSERT_EQ(-1, rc);
  47. ASSERT_EQ(errno, ECHILD);
  48. ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 15"));
  49. // TODO(zhujiashun): Fix this in macos
  50. /*
  51. oss.str("");
  52. ASSERT_EQ(0, butil::read_command_output_through_popen(oss, "for i in `seq 1 100000`; do echo -n '=' ; done"));
  53. ASSERT_EQ(100000u, oss.str().length());
  54. std::string expected;
  55. expected.resize(100000, '=');
  56. ASSERT_EQ(expected, oss.str());
  57. */
  58. }
  59. #if defined(OS_LINUX)
  60. TEST(PopenTest, clone) {
  61. std::ostringstream oss;
  62. int rc = butil::read_command_output_through_clone(oss, "echo \"Hello World\"");
  63. ASSERT_EQ(0, rc) << berror(errno);
  64. ASSERT_EQ("Hello World\n", oss.str());
  65. oss.str("");
  66. rc = butil::read_command_output_through_clone(oss, "exit 1");
  67. ASSERT_EQ(1, rc) << berror(errno);
  68. ASSERT_TRUE(oss.str().empty()) << oss.str();
  69. oss.str("");
  70. rc = butil::read_command_output_through_clone(oss, "kill -9 $$");
  71. ASSERT_EQ(-1, rc);
  72. ASSERT_EQ(errno, ECHILD);
  73. ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 9"));
  74. oss.str("");
  75. rc = butil::read_command_output_through_clone(oss, "kill -15 $$");
  76. ASSERT_EQ(-1, rc);
  77. ASSERT_EQ(errno, ECHILD);
  78. ASSERT_TRUE(butil::StringPiece(oss.str()).ends_with("was killed by signal 15"));
  79. oss.str("");
  80. ASSERT_EQ(0, butil::read_command_output_through_clone(oss, "for i in `seq 1 100000`; do echo -n '=' ; done"));
  81. ASSERT_EQ(100000u, oss.str().length());
  82. std::string expected;
  83. expected.resize(100000, '=');
  84. ASSERT_EQ(expected, oss.str());
  85. }
  86. struct CounterArg {
  87. volatile int64_t counter;
  88. volatile bool stop;
  89. };
  90. static void* counter_thread(void* args) {
  91. CounterArg* ca = (CounterArg*)args;
  92. while (!ca->stop) {
  93. ++ca->counter;
  94. }
  95. return NULL;
  96. }
  97. static int fork_thread(void* arg) {
  98. usleep(100 * 1000);
  99. _exit(0);
  100. }
  101. const int CHILD_STACK_SIZE = 64 * 1024;
  102. TEST(PopenTest, does_vfork_suspend_all_threads) {
  103. pthread_t tid;
  104. CounterArg ca = { 0 , false };
  105. ASSERT_EQ(0, pthread_create(&tid, NULL, counter_thread, &ca));
  106. usleep(100 * 1000);
  107. char* child_stack_mem = (char*)malloc(CHILD_STACK_SIZE);
  108. void* child_stack = child_stack_mem + CHILD_STACK_SIZE;
  109. const int64_t counter_before_fork = ca.counter;
  110. pid_t cpid = clone(fork_thread, child_stack, CLONE_VFORK, NULL);
  111. const int64_t counter_after_fork = ca.counter;
  112. usleep(100 * 1000);
  113. const int64_t counter_after_sleep = ca.counter;
  114. int ws;
  115. ca.stop = true;
  116. pthread_join(tid, NULL);
  117. std::cout << "bc=" << counter_before_fork << " ac=" << counter_after_fork
  118. << " as=" << counter_after_sleep
  119. << std::endl;
  120. ASSERT_EQ(cpid, waitpid(cpid, &ws, __WALL));
  121. }
  122. #endif // OS_LINUX
  123. }