/ipc/chromium/src/base/process_util_unittest.cc

http://github.com/zpao/v8monkey · C++ · 274 lines · 201 code · 40 blank · 33 comment · 19 complexity · 1a3ba9fba095e31d3803145dbd40a441 MD5 · raw file

  1. // Copyright (c) 2009 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. #define _CRT_SECURE_NO_WARNINGS
  5. #include "base/command_line.h"
  6. #include "base/eintr_wrapper.h"
  7. #include "base/file_path.h"
  8. #include "base/multiprocess_test.h"
  9. #include "base/path_service.h"
  10. #include "base/platform_thread.h"
  11. #include "base/process_util.h"
  12. #include "testing/gtest/include/gtest/gtest.h"
  13. #if defined(OS_LINUX)
  14. #include <dlfcn.h>
  15. #endif
  16. #if defined(OS_POSIX)
  17. #include <fcntl.h>
  18. #include <sys/socket.h>
  19. #endif
  20. #if defined(OS_WIN)
  21. #include <windows.h>
  22. #endif
  23. namespace base {
  24. class ProcessUtilTest : public MultiProcessTest {
  25. };
  26. MULTIPROCESS_TEST_MAIN(SimpleChildProcess) {
  27. return 0;
  28. }
  29. TEST_F(ProcessUtilTest, SpawnChild) {
  30. ProcessHandle handle = this->SpawnChild(L"SimpleChildProcess");
  31. ASSERT_NE(static_cast<ProcessHandle>(NULL), handle);
  32. EXPECT_TRUE(WaitForSingleProcess(handle, 5000));
  33. base::CloseProcessHandle(handle);
  34. }
  35. MULTIPROCESS_TEST_MAIN(SlowChildProcess) {
  36. // Sleep until file "SlowChildProcess.die" is created.
  37. FILE *fp;
  38. do {
  39. PlatformThread::Sleep(100);
  40. fp = fopen("SlowChildProcess.die", "r");
  41. } while (!fp);
  42. fclose(fp);
  43. remove("SlowChildProcess.die");
  44. exit(0);
  45. return 0;
  46. }
  47. TEST_F(ProcessUtilTest, KillSlowChild) {
  48. remove("SlowChildProcess.die");
  49. ProcessHandle handle = this->SpawnChild(L"SlowChildProcess");
  50. ASSERT_NE(static_cast<ProcessHandle>(NULL), handle);
  51. FILE *fp = fopen("SlowChildProcess.die", "w");
  52. fclose(fp);
  53. EXPECT_TRUE(base::WaitForSingleProcess(handle, 5000));
  54. base::CloseProcessHandle(handle);
  55. }
  56. // TODO(estade): if possible, port these 2 tests.
  57. #if defined(OS_WIN)
  58. TEST_F(ProcessUtilTest, EnableLFH) {
  59. ASSERT_TRUE(EnableLowFragmentationHeap());
  60. if (IsDebuggerPresent()) {
  61. // Under these conditions, LFH can't be enabled. There's no point to test
  62. // anything.
  63. const char* no_debug_env = getenv("_NO_DEBUG_HEAP");
  64. if (!no_debug_env || strcmp(no_debug_env, "1"))
  65. return;
  66. }
  67. HANDLE heaps[1024] = { 0 };
  68. unsigned number_heaps = GetProcessHeaps(1024, heaps);
  69. EXPECT_GT(number_heaps, 0u);
  70. for (unsigned i = 0; i < number_heaps; ++i) {
  71. ULONG flag = 0;
  72. SIZE_T length;
  73. ASSERT_NE(0, HeapQueryInformation(heaps[i],
  74. HeapCompatibilityInformation,
  75. &flag,
  76. sizeof(flag),
  77. &length));
  78. // If flag is 0, the heap is a standard heap that does not support
  79. // look-asides. If flag is 1, the heap supports look-asides. If flag is 2,
  80. // the heap is a low-fragmentation heap (LFH). Note that look-asides are not
  81. // supported on the LFH.
  82. // We don't have any documented way of querying the HEAP_NO_SERIALIZE flag.
  83. EXPECT_LE(flag, 2u);
  84. EXPECT_NE(flag, 1u);
  85. }
  86. }
  87. TEST_F(ProcessUtilTest, CalcFreeMemory) {
  88. ProcessMetrics* metrics =
  89. ProcessMetrics::CreateProcessMetrics(::GetCurrentProcess());
  90. ASSERT_TRUE(NULL != metrics);
  91. // Typical values here is ~1900 for total and ~1000 for largest. Obviously
  92. // it depends in what other tests have done to this process.
  93. FreeMBytes free_mem1 = {0};
  94. EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem1));
  95. EXPECT_LT(10u, free_mem1.total);
  96. EXPECT_LT(10u, free_mem1.largest);
  97. EXPECT_GT(2048u, free_mem1.total);
  98. EXPECT_GT(2048u, free_mem1.largest);
  99. EXPECT_GE(free_mem1.total, free_mem1.largest);
  100. EXPECT_TRUE(NULL != free_mem1.largest_ptr);
  101. // Allocate 20M and check again. It should have gone down.
  102. const int kAllocMB = 20;
  103. char* alloc = new char[kAllocMB * 1024 * 1024];
  104. EXPECT_TRUE(NULL != alloc);
  105. size_t expected_total = free_mem1.total - kAllocMB;
  106. size_t expected_largest = free_mem1.largest;
  107. FreeMBytes free_mem2 = {0};
  108. EXPECT_TRUE(metrics->CalculateFreeMemory(&free_mem2));
  109. EXPECT_GE(free_mem2.total, free_mem2.largest);
  110. EXPECT_GE(expected_total, free_mem2.total);
  111. EXPECT_GE(expected_largest, free_mem2.largest);
  112. EXPECT_TRUE(NULL != free_mem2.largest_ptr);
  113. delete[] alloc;
  114. delete metrics;
  115. }
  116. TEST_F(ProcessUtilTest, GetAppOutput) {
  117. // Let's create a decently long message.
  118. std::string message;
  119. for (int i = 0; i < 1025; i++) { // 1025 so it does not end on a kilo-byte
  120. // boundary.
  121. message += "Hello!";
  122. }
  123. FilePath python_runtime;
  124. ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &python_runtime));
  125. python_runtime = python_runtime.Append(FILE_PATH_LITERAL("third_party"))
  126. .Append(FILE_PATH_LITERAL("python_24"))
  127. .Append(FILE_PATH_LITERAL("python.exe"));
  128. // You have to put every parameter between quotes, otherwise this won't work,
  129. // don't ask me why.
  130. std::wstring cmd_line = L"\"" + python_runtime.value() + L"\" " +
  131. L"\"-c\" \"import sys; sys.stdout.write('" + ASCIIToWide(message) +
  132. L"');\"";
  133. std::string output;
  134. ASSERT_TRUE(base::GetAppOutput(cmd_line, &output));
  135. EXPECT_EQ(message, output);
  136. // Let's make sure stderr is ignored.
  137. cmd_line = L"\"" + python_runtime.value() + L"\" " +
  138. L"\"-c\" \"import sys; sys.stderr.write('Hello!');\"";
  139. output.clear();
  140. ASSERT_TRUE(base::GetAppOutput(cmd_line, &output));
  141. EXPECT_EQ("", output);
  142. }
  143. #endif // defined(OS_WIN)
  144. #if defined(OS_POSIX)
  145. // Returns the maximum number of files that a process can have open.
  146. // Returns 0 on error.
  147. int GetMaxFilesOpenInProcess() {
  148. struct rlimit rlim;
  149. if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
  150. return 0;
  151. }
  152. // rlim_t is a uint64 - clip to maxint. We do this since FD #s are ints
  153. // which are all 32 bits on the supported platforms.
  154. rlim_t max_int = static_cast<rlim_t>(std::numeric_limits<int32>::max());
  155. if (rlim.rlim_cur > max_int) {
  156. return max_int;
  157. }
  158. return rlim.rlim_cur;
  159. }
  160. const int kChildPipe = 20; // FD # for write end of pipe in child process.
  161. MULTIPROCESS_TEST_MAIN(ProcessUtilsLeakFDChildProcess) {
  162. // This child process counts the number of open FDs, it then writes that
  163. // number out to a pipe connected to the parent.
  164. int num_open_files = 0;
  165. int write_pipe = kChildPipe;
  166. int max_files = GetMaxFilesOpenInProcess();
  167. for (int i = STDERR_FILENO + 1; i < max_files; i++) {
  168. if (i != kChildPipe) {
  169. if (HANDLE_EINTR(close(i)) != -1) {
  170. LOG(WARNING) << "Leaked FD " << i;
  171. num_open_files += 1;
  172. }
  173. }
  174. }
  175. // InitLogging always opens a file at startup.
  176. int expected_num_open_fds = 1;
  177. #if defined(OS_LINUX)
  178. // On Linux, '/etc/localtime' is opened before the test's main() enters.
  179. expected_num_open_fds += 1;
  180. #endif // defined(OS_LINUX)
  181. num_open_files -= expected_num_open_fds;
  182. int written = HANDLE_EINTR(write(write_pipe, &num_open_files,
  183. sizeof(num_open_files)));
  184. DCHECK_EQ(static_cast<size_t>(written), sizeof(num_open_files));
  185. HANDLE_EINTR(close(write_pipe));
  186. return 0;
  187. }
  188. TEST_F(ProcessUtilTest, FDRemapping) {
  189. // Open some files to check they don't get leaked to the child process.
  190. int fds[2];
  191. if (pipe(fds) < 0)
  192. NOTREACHED();
  193. int pipe_read_fd = fds[0];
  194. int pipe_write_fd = fds[1];
  195. // open some dummy fds to make sure they don't propogate over to the
  196. // child process.
  197. int dev_null = open("/dev/null", O_RDONLY);
  198. int sockets[2];
  199. socketpair(AF_UNIX, SOCK_STREAM, 0, sockets);
  200. file_handle_mapping_vector fd_mapping_vec;
  201. fd_mapping_vec.push_back(std::pair<int,int>(pipe_write_fd, kChildPipe));
  202. ProcessHandle handle = this->SpawnChild(L"ProcessUtilsLeakFDChildProcess",
  203. fd_mapping_vec,
  204. false);
  205. ASSERT_NE(static_cast<ProcessHandle>(NULL), handle);
  206. HANDLE_EINTR(close(pipe_write_fd));
  207. // Read number of open files in client process from pipe;
  208. int num_open_files = -1;
  209. ssize_t bytes_read =
  210. HANDLE_EINTR(read(pipe_read_fd, &num_open_files, sizeof(num_open_files)));
  211. ASSERT_EQ(bytes_read, static_cast<ssize_t>(sizeof(num_open_files)));
  212. // Make sure 0 fds are leaked to the client.
  213. ASSERT_EQ(0, num_open_files);
  214. EXPECT_TRUE(WaitForSingleProcess(handle, 1000));
  215. base::CloseProcessHandle(handle);
  216. HANDLE_EINTR(close(fds[0]));
  217. HANDLE_EINTR(close(sockets[0]));
  218. HANDLE_EINTR(close(sockets[1]));
  219. HANDLE_EINTR(close(dev_null));
  220. }
  221. TEST_F(ProcessUtilTest, GetAppOutput) {
  222. std::string output;
  223. EXPECT_TRUE(GetAppOutput(CommandLine(L"true"), &output));
  224. EXPECT_STREQ("", output.c_str());
  225. EXPECT_FALSE(GetAppOutput(CommandLine(L"false"), &output));
  226. std::vector<std::string> argv;
  227. argv.push_back("/bin/echo");
  228. argv.push_back("-n");
  229. argv.push_back("foobar42");
  230. EXPECT_TRUE(GetAppOutput(CommandLine(argv), &output));
  231. EXPECT_STREQ("foobar42", output.c_str());
  232. }
  233. #endif // defined(OS_POSIX)
  234. } // namespace base