process_spawn_unittest.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <util/process_spawn.h>
  15. #include <gtest/gtest.h>
  16. #include <signal.h>
  17. #include <stdint.h>
  18. #include <sys/types.h>
  19. #include <unistd.h>
  20. namespace {
  21. using namespace isc;
  22. using namespace isc::util;
  23. /// @brief Returns a location of the test script.
  24. ///
  25. /// The test script is no-op and it returns the exit code equal to
  26. /// the argument passed to it.
  27. ///
  28. /// @return Absolute location of the test script.
  29. std::string getApp() {
  30. std::ostringstream s;
  31. s << TEST_DATA_TOPBUILDDIR << "/src/lib/util/tests/process_spawn_app.sh";
  32. return (s.str());
  33. }
  34. /// @brief Waits for the specified process to finish.
  35. ///
  36. /// @param process An object which started the process.
  37. /// @param pid ID of the spawned process.
  38. /// @param timeout Timeout in seconds.
  39. ///
  40. /// @return true if the process ended, false otherwise
  41. bool waitForProcess(const ProcessSpawn& process, const pid_t pid,
  42. const uint8_t timeout) {
  43. uint32_t iterations = 0;
  44. const uint32_t iterations_max = timeout * 1000;
  45. while (process.isRunning(pid) && (iterations < iterations_max)) {
  46. usleep(1000);
  47. ++iterations;
  48. }
  49. return (iterations < iterations_max);
  50. }
  51. // This test verifies that the external application can be ran with
  52. // arguments and that the exit code is gathered.
  53. TEST(ProcessSpawn, spawnWithArgs) {
  54. std::vector<std::string> args;
  55. args.push_back("-e");
  56. args.push_back("64");
  57. ProcessSpawn process(getApp(), args);
  58. pid_t pid = 0;
  59. ASSERT_NO_THROW(pid = process.spawn());
  60. ASSERT_TRUE(waitForProcess(process, pid, 2));
  61. EXPECT_EQ(64, process.getExitStatus(pid));
  62. }
  63. // This test verifies that the single ProcessSpawn object can be used
  64. // to start two processes and that their status codes can be gathered.
  65. // It also checks that it is possible to clear the status of the
  66. // process.
  67. TEST(ProcessSpawn, spawnTwoProcesses) {
  68. std::vector<std::string> args;
  69. args.push_back("-p");
  70. ProcessSpawn process(getApp(), args);
  71. pid_t pid1 = 0;
  72. ASSERT_NO_THROW(pid1 = process.spawn());
  73. ASSERT_TRUE(waitForProcess(process, pid1, 2));
  74. pid_t pid2 = 0;
  75. ASSERT_NO_THROW(pid2 = process.spawn());
  76. ASSERT_TRUE(waitForProcess(process, pid2, 2));
  77. EXPECT_NE(process.getExitStatus(pid1), process.getExitStatus(pid2));
  78. // Clear the status of the first process. An attempt to get the status
  79. // for the cleared process should result in exception. But, there should
  80. // be no exception for the second process.
  81. process.clearStatus(pid1);
  82. EXPECT_THROW(process.getExitStatus(pid1), InvalidOperation);
  83. EXPECT_NO_THROW(process.getExitStatus(pid2));
  84. process.clearStatus(pid2);
  85. EXPECT_THROW(process.getExitStatus(pid2), InvalidOperation);
  86. }
  87. // This test verifies that the external application can be ran without
  88. // arguments and that the exit code is gathered.
  89. TEST(ProcessSpawn, spawnNoArgs) {
  90. std::vector<std::string> args;
  91. ProcessSpawn process(getApp());
  92. pid_t pid = 0;
  93. ASSERT_NO_THROW(pid = process.spawn());
  94. ASSERT_TRUE(waitForProcess(process, pid, 2));
  95. EXPECT_EQ(32, process.getExitStatus(pid));
  96. }
  97. // This test verifies that the EXIT_FAILURE code is returned when
  98. // application can't be executed.
  99. TEST(ProcessSpawn, invalidExecutable) {
  100. ProcessSpawn process("foo");
  101. pid_t pid = 0;
  102. ASSERT_NO_THROW(pid = process.spawn());
  103. ASSERT_TRUE(waitForProcess(process, pid, 2));
  104. EXPECT_EQ(EXIT_FAILURE, process.getExitStatus(pid));
  105. }
  106. // This test verifies that the full command line for the process is
  107. // returned.
  108. TEST(ProcessSpawn, getCommandLine) {
  109. // Note that cases below are enclosed in separate scopes to make
  110. // sure that the ProcessSpawn object is destroyed before a new
  111. // object is created. Current implementation doesn't allow for
  112. // having two ProcessSpawn objects simultaneously as they will
  113. // both try to allocate a signal handler for SIGCHLD.
  114. {
  115. // Case 1: arguments present.
  116. ProcessArgs args;
  117. args.push_back("-x");
  118. args.push_back("-y");
  119. args.push_back("foo");
  120. args.push_back("bar");
  121. ProcessSpawn process("myapp", args);
  122. EXPECT_EQ("myapp -x -y foo bar", process.getCommandLine());
  123. }
  124. {
  125. // Case 2: no arguments.
  126. ProcessSpawn process("myapp");
  127. EXPECT_EQ("myapp", process.getCommandLine());
  128. }
  129. }
  130. // This test verifies that it is possible to check if the process is
  131. // running.
  132. TEST(ProcessSpawn, isRunning) {
  133. // Run the process which sleeps for 10 seconds, so as we have
  134. // enough time to check if it is running.
  135. std::vector<std::string> args;
  136. args.push_back("-s");
  137. args.push_back("10");
  138. ProcessSpawn process(getApp(), args);
  139. pid_t pid = 0;
  140. ASSERT_NO_THROW(pid = process.spawn());
  141. EXPECT_TRUE(process.isRunning(pid));
  142. // Kill the process.
  143. ASSERT_EQ(0, kill(pid, SIGKILL));
  144. // And make sure if died.
  145. ASSERT_TRUE(waitForProcess(process, pid, 2));
  146. }
  147. } // end of anonymous namespace