summaryrefslogtreecommitdiffstats
path: root/src/lib/util/tests/pid_file_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/util/tests/pid_file_unittest.cc')
-rw-r--r--src/lib/util/tests/pid_file_unittest.cc206
1 files changed, 206 insertions, 0 deletions
diff --git a/src/lib/util/tests/pid_file_unittest.cc b/src/lib/util/tests/pid_file_unittest.cc
new file mode 100644
index 0000000..5f00d72
--- /dev/null
+++ b/src/lib/util/tests/pid_file_unittest.cc
@@ -0,0 +1,206 @@
+// Copyright (C) 2015-2021 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <util/pid_file.h>
+#include <gtest/gtest.h>
+#include <fstream>
+#include <signal.h>
+#include <stdint.h>
+
+namespace {
+using namespace isc::util;
+
+// Filenames used for testing.
+const char* TESTNAME = "pid_file.test";
+
+class PIDFileTest : public ::testing::Test {
+public:
+
+ /// @brief Constructor
+ PIDFileTest() = default;
+
+ /// @brief Destructor
+ virtual ~PIDFileTest() = default;
+
+ /// @brief Prepends the absolute path to the file specified
+ /// as an argument.
+ ///
+ /// @param filename Name of the file.
+ /// @return Absolute path to the test file.
+ static std::string absolutePath(const std::string& filename);
+
+ /// @brief Generate a random number for use as a PID
+ ///
+ /// @param start - the start of the range we want the PID in
+ /// @param range - the size of the range for our PID
+ ///
+ /// @return returns a random value between start and start + range
+ int randomizePID(const uint32_t start, const uint32_t range) {
+ int pid;
+
+ for (pid = (random() % range) + start;
+ kill(pid, 0) == 0;
+ ++pid)
+ ;
+
+ return (pid);
+ }
+
+protected:
+ /// @brief Removes any old test files before the test
+ virtual void SetUp() {
+ removeTestFile();
+ }
+
+ /// @brief Removes any remaining test files after the test
+ virtual void TearDown() {
+ removeTestFile();
+ }
+
+private:
+ /// @brief Removes any remaining test files
+ void removeTestFile() const {
+ static_cast<void>(remove(absolutePath(TESTNAME).c_str()));
+ }
+
+};
+
+std::string
+PIDFileTest::absolutePath(const std::string& filename) {
+ std::ostringstream s;
+ s << TEST_DATA_BUILDDIR << "/" << filename;
+
+ return (s.str());
+}
+
+/// @brief Test file writing and deletion. Start by removing
+/// any leftover file. Then write a known PID to the file and
+/// attempt to read the file and verify the PID. Next write
+/// a second and verify a second PID to verify that an existing
+/// file is properly overwritten.
+
+TEST_F(PIDFileTest, writeAndDelete) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+ std::ifstream fs;
+ int pid(0);
+
+ // Write a known process id
+ pid_file.write(10);
+
+ // Read the file and compare the pid
+ fs.open(absolutePath(TESTNAME).c_str(), std::ifstream::in);
+ fs >> pid;
+ EXPECT_TRUE(fs.good());
+ EXPECT_EQ(pid, 10);
+ fs.close();
+
+ // Write a second known process id
+ pid_file.write(20);
+
+ // And compare the second pid
+ fs.open(absolutePath(TESTNAME).c_str(), std::ifstream::in);
+ fs >> pid;
+ EXPECT_TRUE(fs.good());
+ EXPECT_EQ(pid, 20);
+ fs.close();
+
+ // Delete the file
+ pid_file.deleteFile();
+
+ // And verify that it's gone
+ fs.open(absolutePath(TESTNAME).c_str(), std::ifstream::in);
+ EXPECT_FALSE(fs.good());
+ fs.close();
+}
+
+/// @brief Test checking a PID. Write the PID of the current
+/// process to the PID file then verify that check indicates
+/// the process is running.
+TEST_F(PIDFileTest, pidInUse) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+
+ // Write the current PID
+ pid_file.write();
+
+ // Check if we think the process is running
+ EXPECT_EQ(getpid(), pid_file.check());
+}
+
+/// @brief Test checking a PID. Write a PID that isn't in use
+/// to the PID file and verify that check indicates the process
+/// isn't running. The PID may get used between when we select it
+/// and write the file and when we check it. To minimize false
+/// errors if the first call to check fails we try again with a
+/// different range of values and only if both attempts fail do
+/// we declare the test to have failed.
+TEST_F(PIDFileTest, pidNotInUse) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+ int pid;
+
+ // get a pid between 10000 and 20000
+ pid = randomizePID(10000, 10000);
+
+ // write it
+ pid_file.write(pid);
+
+ // Check to see if we think the process is running
+ if (pid_file.check() == 0) {
+ return;
+ }
+
+ // get a pid between 40000 and 50000
+ pid = randomizePID(10000, 40000);
+
+ // write it
+ pid_file.write(pid);
+
+ // Check to see if we think the process is running
+ EXPECT_EQ(0, pid_file.check());
+}
+
+/// @brief Test checking a PID. Write garbage to the PID file
+/// and verify that check throws an error. In this situation
+/// the caller should probably log an error and may decide to
+/// continue or not depending on the requirements.
+TEST_F(PIDFileTest, pidGarbage) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+ std::ofstream fs;
+
+ // Open the file and write garbage to it
+ fs.open(absolutePath(TESTNAME).c_str(), std::ofstream::out);
+ fs << "text" << std::endl;
+ fs.close();
+
+ // Run the check, we expect to get an exception
+ EXPECT_THROW(pid_file.check(), PIDCantReadPID);
+}
+
+/// @brief Test failing to write a file.
+TEST_F(PIDFileTest, pidWriteFail) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+
+ // Create the test file and change it's permission bits
+ // so we can't write to it.
+ pid_file.write(10);
+ chmod(absolutePath(TESTNAME).c_str(), S_IRUSR);
+
+ // Now try a write to the file, expecting an exception
+ EXPECT_THROW(pid_file.write(10), PIDFileError);
+
+ // Don't forget to restore the write right for the next test
+ chmod(absolutePath(TESTNAME).c_str(), S_IRUSR | S_IWUSR);
+}
+
+/// @brief Test deleting a file that doesn't exist
+TEST_F(PIDFileTest, noDeleteFile) {
+ PIDFile pid_file(absolutePath(TESTNAME));
+
+ // Delete a file we haven't created
+ pid_file.deleteFile();
+}
+} // end of anonymous namespace