------------------------------------------------------------
revno: 1417
committer: James Hunt <[email protected]>
branch nick: upstart-setenv+getenv
timestamp: Thu 2013-01-10 17:01:56 +0000
message:
  * init/man/init.5: Define job environment table.
  * init/tests/test_job_class.c(): test_environment(): Added call
    to job_class_environment_init() which is now required to avoid
    confusing TEST_ALLOC_FAIL().
  * util/man/initctl.8:
    - Further details in list-env section.
    - Escape dashes in command names.
  * util/tests/test_initctl.c:
    - New utility macros: _WAIT_FOR_FILE(), WAIT_FOR_FILE()
      and TEST_STR_MATCH().
    - Initial tests for testing job environment table commands.
modified:
  ChangeLog
  init/man/init.5
  init/tests/test_job_class.c
  util/man/initctl.8
  util/tests/test_initctl.c


--
lp:upstart
https://code.launchpad.net/~upstart-devel/upstart/trunk

Your team Upstart Reviewers is subscribed to branch lp:upstart.
To unsubscribe from this branch go to 
https://code.launchpad.net/~upstart-devel/upstart/trunk/+edit-subscription
=== modified file 'ChangeLog'
--- ChangeLog	2013-01-09 11:13:03 +0000
+++ ChangeLog	2013-01-10 17:01:56 +0000
@@ -1,3 +1,17 @@
+2013-01-10  James Hunt  <[email protected]>
+
+	* init/man/init.5: Define job environment table.
+	* init/tests/test_job_class.c(): test_environment(): Added call
+	  to job_class_environment_init() which is now required to avoid
+	  confusing TEST_ALLOC_FAIL().
+	* util/man/initctl.8:
+	  - Further details in list-env section.
+	  - Escape dashes in command names.
+	* util/tests/test_initctl.c:
+	  - New utility macros: _WAIT_FOR_FILE(), WAIT_FOR_FILE()
+	    and TEST_STR_MATCH().
+	  - Initial tests for testing job environment table commands.
+
 2013-01-09  James Hunt  <[email protected]>
 
 	* init/man/init.5:

=== modified file 'init/man/init.5'
--- init/man/init.5	2013-01-09 10:13:36 +0000
+++ init/man/init.5	2013-01-10 17:01:56 +0000
@@ -421,7 +421,18 @@
 .IP \(bu 4
 A minimal set of standard system variables added by Upstart.
 .sp 1
-All jobs contain the \fBTERM\fP and \fBPATH\fP variables.
+All jobs contain the
+.B TERM
+and
+.B PATH
+variables.
+.\"
+.IP \(bu 4
+Variables set using the 
+.BR initctl (8)
+job environment commands (such as \fIset-env\fP).
+.sp 1
+These commands also allow unsetting of variables.
 .\"
 .IP \(bu 4
 A set of special variables added by Upstart that relate to the job itself.
@@ -487,14 +498,11 @@
 .ft
 (not just those relating to the current job).
 .RE
-.\"
-.IP \(bu 4
-Variables set using the 
-.BR initctl (8)
-job environment commands (such as \fIset-env\fP).
-.sp 1
-These commands also allow unsetting of variables.
 
+The first two categories above comprise the
+.I job environment table
+which is applied to all jobs. Note that changing the job environment
+table will only affect newly-started jobs.
 .\"
 .SS Services, tasks and respawning
 Jobs are

=== modified file 'init/tests/test_job_class.c'
--- init/tests/test_job_class.c	2012-12-14 20:48:51 +0000
+++ init/tests/test_job_class.c	2013-01-10 17:01:56 +0000
@@ -969,6 +969,11 @@
 	class = job_class_new (NULL, "test", NULL);
 	class->console = CONSOLE_NONE;
 
+	/* necessary to call this initially to avoid disrupting
+	 * TEST_ALLOC_FAIL()'s bookkeeping.
+	 */
+	job_class_environment_init ();
+
 	TEST_ALLOC_FAIL {
 		env = job_class_environment (NULL, class, &len);
 

=== modified file 'util/man/initctl.8'
--- util/man/initctl.8	2013-01-09 11:13:03 +0000
+++ util/man/initctl.8	2013-01-10 17:01:56 +0000
@@ -548,13 +548,28 @@
 .RE
 .\"
 .TP
-.B get-env
+.B list\-env
+
+Display a lexicographically sorted list of all variables and their
+values in the job environment table.
+
+Note that this table only includes the minimal set of standard system
+variables added by the
+.BR init (8)
+daemon along with any variables set using
+.BR set\-env "."
+See
+.BR init (5)
+for further details.
+.\"
+.TP
+.B get\-env
 .I VARIABLE
 
 Query the value of the specified variable in the job environment table.
 .\"
 .TP
-.B set-env
+.B set\-env
 .RI [ OPTIONS "] " VARIABLE[=VALUE]
 
 Adds or updates a variable in the job environment table. Variables set
@@ -568,20 +583,14 @@
 .RE
 .\"
 .TP
-.B unset-env
+.B unset\-env
 .I VARIABLE
 
 Remove the specified variable from the job environment table. If the
 variable does not already exist in the table, no change will be made.
 .\"
 .TP
-.B list-env
-
-Display a lexicographically sorted list of all variables and their
-values in the job environment table.
-.\"
-.TP
-.B reset-env
+.B reset\-env
 
 Discards all changes make to the job environment table, setting it back
 to its default set of variables and values.

=== modified file 'util/tests/test_initctl.c'
--- util/tests/test_initctl.c	2012-10-26 16:28:12 +0000
+++ util/tests/test_initctl.c	2013-01-10 17:01:56 +0000
@@ -21,6 +21,7 @@
  */
 
 #include <nih/test.h>
+#include <nih/file.h>
 #include <nih-dbus/test_dbus.h>
 
 #include <dbus/dbus.h>
@@ -310,6 +311,71 @@
 }
 
 /**
+ * _WAIT_FOR_FILE():
+ *
+ * @path: full path to file to look for,
+ * @sleep_secs: number of seconds to sleep per loop,
+ * @loops: number of times to check for file.
+ *
+ * Wait for a reasonable period of time for @path to be created.
+ *
+ * Abort if file does not appear within (sleep_secs * loops) seconds.
+ *
+ * XXX:WARNING: this is intrinsically racy since although the file has
+ * been _created_, it has not necessarily been fully written at the
+ * point this macro signifies success. For that we need inotify or
+ * similar.
+ **/
+#define _WAIT_FOR_FILE(path, sleep_secs, loops)                      \
+{                                                                    \
+	int              ok;                                         \
+	struct stat      statbuf;                                    \
+                                                                     \
+	assert (path[0]);                                            \
+                                                                     \
+	/* Wait for log to be created */                             \
+	ok = FALSE;                                                  \
+	for (int i = 0; i < loops; i++) {                            \
+		sleep (sleep_secs);                                  \
+		if (! stat (logfile, &statbuf)) {                    \
+			ok = TRUE;                                   \
+			break;                                       \
+		}                                                    \
+	}                                                            \
+	TEST_EQ (ok, TRUE);                                          \
+}
+
+/**
+ * WAIT_FOR_FILE():
+ *
+ * @path: full path to file to look for.
+ *
+ * Wait for a "reasonable period of time" for @path to be created.
+ *
+ * Abort if file does not appear within.
+ **/
+#define WAIT_FOR_FILE(path)                                         \
+        _WAIT_FOR_FILE (path, 1, 5)
+
+/**
+ * TEST_STR_MATCH:
+ * @_string: string to check,
+ * @_pattern: pattern to expect.
+ *
+ * Check that @_string matches the glob pattern @_pattern, which
+ * should include the terminating newline if one is expected.
+ *
+ * Notes: Analagous to TEST_FILE_MATCH().
+ **/
+#define TEST_STR_MATCH(_string, _pattern)                            \
+	do {                                                         \
+		if (fnmatch ((_pattern), _string, 0))		     \
+			TEST_FAILED ("wrong string value, "          \
+					"expected '%s' got '%s'",    \
+			     (_pattern), _string);                   \
+	} while (0)
+
+/**
  * job_to_pid:
  *
  * @job: job name.
@@ -15050,6 +15116,282 @@
 	TEST_DBUS_END (dbus_pid);
 }
 
+void
+test_default_job_env (const char *confdir, const char *logdir,
+		      pid_t upstart_pid, pid_t dbus_pid)
+{
+	nih_local char  *cmd = NULL;
+	char           **output;
+	nih_local char  *logfile = NULL;
+	size_t           line_count;
+	FILE            *fi;
+
+	assert (confdir);
+	assert (logdir);
+	assert (upstart_pid);
+	assert (dbus_pid);
+
+	/*******************************************************************/
+	TEST_FEATURE ("ensure list-env returns default environment");
+
+	cmd = nih_sprintf (NULL, "%s list-env 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+
+	TEST_STR_MATCH (output[0], "PATH=*");
+	TEST_STR_MATCH (output[1], "TERM=*");
+	TEST_EQ (line_count, 2);
+	nih_free (output);
+
+	/*******************************************************************/
+	TEST_FEATURE ("ensure get-env returns expected TERM variable");
+
+	cmd = nih_sprintf (NULL, "%s get-env TERM 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+
+	/* don't check the actual value (in case user has changed it from
+	 * default value when compiling), just see if it matches a
+	 * reasonable pattern.
+	 */
+	TEST_EQ_STR (output[0], getenv ("TERM"));
+	TEST_EQ (line_count, 1);
+	nih_free (output);
+
+	/*******************************************************************/
+	TEST_FEATURE ("ensure get-env returns expected PATH variable");
+
+	cmd = nih_sprintf (NULL, "%s get-env PATH 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+
+	/* don't check the actual value (in case user has changed it from
+	 * default value when compiling), just see if it matches a
+	 * reasonable pattern.
+	 */
+	TEST_STR_MATCH (output[0], "[a-zA-Z/:][a-zA-Z0-9/:]*");
+	TEST_EQ (line_count, 1);
+	nih_free (output);
+
+	/*******************************************************************/
+	TEST_FEATURE ("ensure job gets given default environment");
+
+	CREATE_FILE (confdir, "foo.conf", "exec env");
+
+	cmd = nih_sprintf (NULL, "%s start foo 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+	nih_free (output);
+
+	logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s",
+				logdir,
+				"foo.log"));
+
+	WAIT_FOR_FILE (logfile);
+
+	fi = fopen (logfile, "r");
+	TEST_NE_P (fi, NULL);
+	TEST_FILE_MATCH (fi, "PATH=*");
+	TEST_FILE_MATCH (fi, "TERM=*");
+
+	/* asterisk required to match '\r\n' */
+	TEST_FILE_MATCH (fi, "UPSTART_JOB=foo*");
+	TEST_FILE_MATCH (fi, "UPSTART_INSTANCE=*");
+	TEST_FILE_END (fi);
+	fclose (fi);
+
+
+	DELETE_FILE (confdir, "foo.conf");
+	TEST_EQ (unlink (logfile), 0);
+
+	/*******************************************************************/
+}
+
+/**
+ * Clear the job process table, then reset it back to defaults.
+ **/
+void
+test_clear_job_env (const char *confdir, const char *logdir,
+		      pid_t upstart_pid, pid_t dbus_pid)
+{
+	nih_local char  *cmd = NULL;
+	char           **output;
+	nih_local char  *logfile = NULL;
+	size_t           line_count;
+	size_t           i;
+	FILE            *fi;
+
+	assert (confdir);
+	assert (logdir);
+	assert (upstart_pid);
+	assert (dbus_pid);
+
+	cmd = nih_sprintf (NULL, "%s list-env 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+
+	TEST_GT (line_count, 0);
+
+	/* Remove all variables from the job environment table */
+	for (i = 0; i < line_count; i++) {
+		char    **output2;
+		size_t    line_count2;
+		char      *p;
+		nih_local char *name = NULL;
+
+		/* Every variable is expected to be returned with a
+		 * delimiter, even if one was not specified when
+		 * variable was set.
+		 */
+		p = strchr (output[i], '=');
+		TEST_NE_P (p, NULL);
+
+		name = NIH_MUST (nih_strdup (NULL, ""));
+		TEST_TRUE (nih_strncat (&name, NULL, output[i], p - output[i]));
+
+		/* Clear the variable */
+		cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", INITCTL_BINARY, name);
+		TEST_NE_P (cmd, NULL);
+		RUN_COMMAND (NULL, cmd, &output2, &line_count2);
+		TEST_EQ (line_count2, 0);
+	}
+
+	nih_free (output);
+
+	/* No variables should remain */
+	cmd = nih_sprintf (NULL, "%s list-env 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+	assert0 (line_count);
+
+	/*******************************************************************/
+	TEST_FEATURE ("ensure job runs in empty environment");
+
+	/* we have to cheat by setting PATH to allow 'env' to be found.
+	 * Add a silly entry at the end so we can check our version has
+	 * been set.
+	 */
+	CREATE_FILE (confdir, "empty-env.conf",
+			"env PATH=/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/sbin:/sbin:/bin:/wibble\n"
+			"exec env");
+
+	cmd = nih_sprintf (NULL, "%s start empty-env 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+	nih_free (output);
+
+	logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s",
+				logdir,
+				"empty-env.log"));
+
+	WAIT_FOR_FILE (logfile);
+
+	fi = fopen (logfile, "r");
+	TEST_NE_P (fi, NULL);
+
+	/* Ensure it looks like our PATH */
+	TEST_FILE_MATCH (fi, "PATH=*/wibble*");
+
+	/* Although the environment is empty (except for PATH now), we
+	 * still expect the special variables to be set.
+	 */
+	TEST_FILE_MATCH (fi, "UPSTART_JOB=empty-env*");
+	TEST_FILE_MATCH (fi, "UPSTART_INSTANCE=*");
+	TEST_FILE_END (fi);
+	fclose (fi);
+
+	DELETE_FILE (confdir, "empty-env.conf");
+	TEST_EQ (unlink (logfile), 0);
+
+	/* reset environment */
+	cmd = nih_sprintf (NULL, "%s reset-env 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+	assert0 (line_count);
+
+	/* re-check */
+	test_default_job_env (confdir, logdir, upstart_pid, dbus_pid);
+	/*******************************************************************/
+}
+
+void
+test_modified_job_env (const char *confdir, const char *logdir,
+		pid_t upstart_pid, pid_t dbus_pid)
+{
+	nih_local char  *cmd = NULL;
+	char           **output;
+	size_t           line_count;
+
+	assert (confdir);
+	assert (logdir);
+	assert (upstart_pid);
+	assert (dbus_pid);
+
+	/*******************************************************************/
+	TEST_FEATURE ("call reset-env with default environment");
+
+	cmd = nih_sprintf (NULL, "%s reset-env 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+	nih_free (output);
+
+	/* Ensure nothing changed */
+	test_default_job_env (confdir, logdir, upstart_pid, dbus_pid);
+
+	test_clear_job_env (confdir, logdir, upstart_pid, dbus_pid);
+
+	/*******************************************************************/
+	TEST_FEATURE ("set-env in name=value form");
+
+	cmd = nih_sprintf (NULL, "%s set-env foo=bar 2>&1", INITCTL_BINARY);
+	TEST_NE_P (cmd, NULL);
+	RUN_COMMAND (NULL, cmd, &output, &line_count);
+	nih_free (output);
+}
+
+/*
+ * Test all the commands which affect the job environment table together
+ * as they are so closely related.
+ */
+void
+test_job_env (void)
+{
+	char             confdir[PATH_MAX];
+	char             logdir[PATH_MAX];
+	pid_t            dbus_pid = 0;
+	pid_t            upstart_pid = 0;
+
+	TEST_GROUP ("job process table commands");
+
+        TEST_FILENAME (confdir);
+        TEST_EQ (mkdir (confdir, 0755), 0);
+
+        TEST_FILENAME (logdir);
+        TEST_EQ (mkdir (logdir, 0755), 0);
+
+	/* Use the "secret" interface */
+	TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0);
+	TEST_EQ (setenv ("UPSTART_LOGDIR", logdir, 1), 0);
+
+	TEST_DBUS (dbus_pid);
+	START_UPSTART (upstart_pid);
+
+	/*******************************************************************/
+
+	test_default_job_env (confdir, logdir, upstart_pid, dbus_pid);
+
+	test_modified_job_env (confdir, logdir, upstart_pid, dbus_pid);
+
+	/*******************************************************************/
+
+	STOP_UPSTART (upstart_pid);
+	TEST_DBUS_END (dbus_pid);
+	TEST_EQ (unsetenv ("UPSTART_CONFDIR"), 0);
+	TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0);
+        TEST_EQ (rmdir (confdir), 0);
+        TEST_EQ (rmdir (logdir), 0);
+}
+
 
 /**
  * in_chroot:
@@ -15122,6 +15464,7 @@
 	test_version_action ();
 	test_log_priority_action ();
 	test_usage ();
+	test_job_env ();
 	test_reexec ();
 
 	if (in_chroot () && !dbus_configured ()) {

-- 
upstart-devel mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/upstart-devel

Reply via email to