Browse Source

Igr: refactor; use RAII for automatic reset/teardown of env vars

Davin McCall 1 month ago
parent
commit
754f71513e
2 changed files with 67 additions and 24 deletions
  1. 6 24
      src/igr-tests/igr-runner.cc
  2. 61 0
      src/igr-tests/igr.h

+ 6 - 24
src/igr-tests/igr-runner.cc

@@ -13,7 +13,6 @@ extern char **environ;
 
 // Integration test suite runner.
 
-std::string igr_output_basedir;
 std::string igr_dinit_socket_path;
 
 void basic_test();
@@ -170,12 +169,7 @@ int main(int argc, char **argv)
 
 void basic_test()
 {
-    std::string output_dir = igr_output_basedir + "/basic";
-    if (mkdir(output_dir.c_str(), 0700) == -1 && errno != EEXIST) {
-        throw std::system_error(errno, std::generic_category(), std::string("mkdir: ") + output_dir);
-    }
-
-    setenv("IGR_OUTPUT", output_dir.c_str(), true);
+    igr_test_setup setup("basic");
 
     // Start the "basic" service. This creates an output file, "basic-ran", containing "ran\n".
     dinit_proc dinit_p;
@@ -186,28 +180,22 @@ void basic_test()
     igr_assert_eq("", dinit_p.get_stderr());
 
     check_file_contents(igr_output_basedir + "/basic/basic-ran", "ran\n");
-
-    unsetenv("IGR_OUTPUT");
 }
 
 void environ_test()
 {
-    std::string output_dir = igr_output_basedir + "/environ";
-    if (mkdir(output_dir.c_str(), 0700) == -1 && errno != EEXIST) {
-        throw std::system_error(errno, std::generic_category(), std::string("mkdir: ") + output_dir);
-    }
-
-    setenv("IGR_OUTPUT", output_dir.c_str(), true);
+    igr_test_setup setup("environ");
 
+    const std::string &output_dir = setup.get_output_dir();
     std::string output_file = output_dir + "/env-record";
     if (unlink(output_file.c_str()) == -1 && errno != ENOENT) {
         throw std::system_error(errno, std::generic_category(),
                 std::string("unlink " + output_file + ": ") + output_dir);
     }
 
-    setenv("OUTPUT", (output_dir + "/env-record").c_str(), true);
-    setenv("SOCKET", igr_dinit_socket_path.c_str(), true);
-    setenv("DINITCTL", (dinit_bindir + "/dinitctl").c_str(), true);
+    igr_env_var_setup env_output("OUTPUT", (output_dir + "/env-record").c_str());
+    igr_env_var_setup env_socket("SOCKET", igr_dinit_socket_path.c_str());
+    igr_env_var_setup env_dinitctl("DINITCTL", (dinit_bindir + "/dinitctl").c_str());
 
     dinit_proc dinit_p;
     dinit_p.start("environ", {"-u", "-d", "sd", "-p", igr_dinit_socket_path, "-q", "-e", "environment1", "checkenv"});
@@ -226,10 +214,4 @@ void environ_test()
             "gotenv2\n" +
             "goodbye\n" +
             "3\n2\n1\n");
-
-    unsetenv("DINITCTL");
-    unsetenv("SOCKET");
-    unsetenv("OUTPUT");
-
-    unsetenv("IGR_OUTPUT");
 }

+ 61 - 0
src/igr-tests/igr.h

@@ -9,6 +9,10 @@ event_loop_t event_loop;
 // directory containing built executables
 std::string dinit_bindir;
 
+// directory for all test output (each test under a named subdir)
+std::string igr_output_basedir;
+
+
 // exception to be thrown on failure
 class igr_failure_exc
 {
@@ -223,6 +227,63 @@ public:
     }
 };
 
+// perform basic setup for a test (with automatic teardown)
+class igr_test_setup
+{
+    std::string output_dir;
+
+public:
+    igr_test_setup(const std::string &test_name)
+    {
+        output_dir = igr_output_basedir + "/" + test_name;
+        if (mkdir(output_dir.c_str(), 0700) == -1 && errno != EEXIST) {
+            throw std::system_error(errno, std::generic_category(), std::string("mkdir: ") + output_dir);
+        }
+
+        setenv("IGR_OUTPUT", output_dir.c_str(), true);
+    }
+
+    ~igr_test_setup()
+    {
+        unsetenv("IGR_OUTPUT");
+    }
+
+    const std::string &get_output_dir()
+    {
+        return output_dir;
+    }
+};
+
+// set an environment variable (with automatic restore of original value at teardown)
+class igr_env_var_setup
+{
+    std::string orig_value;
+    std::string var_name;
+    bool had_value;
+
+public:
+    igr_env_var_setup(const char *var_name_p, const char *value)
+    {
+        var_name = var_name_p;
+        const char *orig_value_cp = getenv(var_name_p);
+        had_value = (orig_value_cp != nullptr);
+        if (had_value) {
+            orig_value = orig_value_cp;
+        }
+        setenv(var_name_p, value, true);
+    }
+
+    ~igr_env_var_setup()
+    {
+        if (had_value) {
+            setenv(var_name.c_str(), orig_value.c_str(), true);
+        }
+        else {
+            unsetenv(var_name.c_str());
+        }
+    }
+};
+
 // read entire file contents as a string
 inline std::string read_file_contents(const std::string &filename)
 {