| /* upstart |
| * |
| * test_initctl.c - test suite for util/initctl.c |
| * |
| * Copyright © 2010 Canonical Ltd. |
| * Authors: Scott James Remnant <[email protected]>, |
| * James Hunt <[email protected]>. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License version 2, as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #include <nih/test.h> |
| #include <nih/child.h> |
| #include <nih/file.h> |
| #include <nih-dbus/test_dbus.h> |
| |
| #include <dbus/dbus.h> |
| |
| #include <stdio.h> |
| #include <signal.h> |
| #include <unistd.h> |
| #include <regex.h> |
| #include <sys/prctl.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <ctype.h> |
| |
| #include <nih-dbus/dbus_error.h> |
| #include <nih-dbus/dbus_connection.h> |
| #include <nih-dbus/dbus_proxy.h> |
| #include <nih-dbus/errors.h> |
| |
| #include <nih/macros.h> |
| #include <nih/timer.h> |
| #include <nih/signal.h> |
| #include <nih/child.h> |
| #include <nih/main.h> |
| #include <nih/command.h> |
| #include <nih/error.h> |
| #include <nih/file.h> |
| #include <nih/string.h> |
| |
| #include "dbus/upstart.h" |
| |
| #include "com.ubuntu.Upstart.h" |
| |
| #include "test_util_common.h" |
| |
| extern int use_dbus; |
| extern int user_mode; |
| extern int dbus_bus_type; |
| extern char *dest_name; |
| extern const char *dest_address; |
| extern int no_wait; |
| |
| extern NihDBusProxy *upstart_open (const void *parent) |
| __attribute__ ((warn_unused_result)); |
| extern char * job_status (const void *parent, |
| NihDBusProxy *job_class, NihDBusProxy *job) |
| __attribute__ ((warn_unused_result)); |
| |
| extern int start_action (NihCommand *command, char * const *args); |
| extern int stop_action (NihCommand *command, char * const *args); |
| extern int restart_action (NihCommand *command, char * const *args); |
| extern int reload_action (NihCommand *command, char * const *args); |
| extern int status_action (NihCommand *command, char * const *args); |
| extern int list_action (NihCommand *command, char * const *args); |
| extern int emit_action (NihCommand *command, char * const *args); |
| extern int reload_configuration_action (NihCommand *command, char * const *args); |
| extern int version_action (NihCommand *command, char * const *args); |
| extern int log_priority_action (NihCommand *command, char * const *args); |
| extern int usage_action (NihCommand *command, char * const *args); |
| |
| |
| static int my_connect_handler_called = FALSE; |
| static DBusConnection *last_connection = NULL; |
| |
| static int |
| my_connect_handler (DBusServer * server, |
| DBusConnection *connection) |
| { |
| my_connect_handler_called++; |
| |
| last_connection = connection; |
| |
| nih_main_loop_exit (0); |
| |
| return TRUE; |
| } |
| |
| static void hup_handler_empty (int signum) { _exit (0); } |
| |
| void |
| test_upstart_open (void) |
| { |
| DBusServer * server = NULL; |
| pid_t dbus_pid; |
| DBusConnection *server_conn = NULL; |
| NihDBusProxy * proxy = NULL; |
| FILE * output; |
| |
| TEST_FUNCTION ("upstart_open"); |
| output = tmpfile (); |
| |
| |
| /* Check that we can create a proxy to Upstart's private internal |
| * server, and that this is the default behaviour if we don't |
| * fiddle with the other options. The returned proxy should |
| * hold the only reference to the connection. |
| */ |
| TEST_FEATURE ("with private connection"); |
| unsetenv ("UPSTART_SESSION"); |
| |
| TEST_ALLOC_FAIL { |
| use_dbus = FALSE; |
| dest_name = NULL; |
| dest_address = "unix:abstract=/com/ubuntu/upstart/test_initctl"; |
| |
| TEST_ALLOC_SAFE { |
| server = nih_dbus_server (dest_address, |
| my_connect_handler, |
| NULL); |
| assert (server != NULL); |
| } |
| |
| my_connect_handler_called = FALSE; |
| last_connection = NULL; |
| |
| TEST_DIVERT_STDERR (output) { |
| proxy = upstart_open (NULL); |
| } |
| rewind (output); |
| |
| if (test_alloc_failed |
| && (proxy == NULL)) { |
| TEST_FILE_EQ (output, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| if (last_connection) { |
| dbus_connection_close (last_connection); |
| dbus_connection_unref (last_connection); |
| } |
| |
| dbus_server_disconnect (server); |
| dbus_server_unref (server); |
| |
| dbus_shutdown (); |
| continue; |
| } |
| |
| nih_main_loop (); |
| |
| TEST_TRUE (my_connect_handler_called); |
| TEST_NE_P (last_connection, NULL); |
| |
| TEST_NE_P (proxy, NULL); |
| TEST_ALLOC_SIZE (proxy, sizeof (NihDBusProxy)); |
| |
| TEST_NE_P (proxy->connection, NULL); |
| TEST_EQ_P (proxy->name, NULL); |
| TEST_EQ_P (proxy->owner, NULL); |
| TEST_EQ_STR (proxy->path, DBUS_PATH_UPSTART); |
| TEST_ALLOC_PARENT (proxy->path, proxy); |
| TEST_FALSE (proxy->auto_start); |
| |
| TEST_EQ_P (proxy->lost_handler, NULL); |
| TEST_EQ_P (proxy->data, NULL); |
| |
| nih_free (proxy); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| dbus_connection_close (last_connection); |
| dbus_connection_unref (last_connection); |
| |
| dbus_server_disconnect (server); |
| dbus_server_unref (server); |
| |
| dbus_shutdown (); |
| } |
| |
| /* Check that we can create a proxy to Upstart's private internal |
| * server in user mode, and that this is the default behaviour if we don't |
| * fiddle with the other options. The returned proxy should |
| * hold the only reference to the connection. |
| */ |
| TEST_FEATURE ("with user-mode"); |
| TEST_ALLOC_FAIL { |
| use_dbus = -1; |
| dbus_bus_type = -1; |
| dest_name = NULL; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| user_mode = TRUE; |
| |
| assert0 (setenv ("UPSTART_SESSION", |
| "unix:abstract=/com/ubuntu/upstart/test-session", |
| TRUE)); |
| |
| TEST_ALLOC_SAFE { |
| server = nih_dbus_server (getenv ("UPSTART_SESSION"), |
| my_connect_handler, |
| NULL); |
| assert (server != NULL); |
| } |
| |
| my_connect_handler_called = FALSE; |
| last_connection = NULL; |
| |
| TEST_DIVERT_STDERR (output) { |
| proxy = upstart_open (NULL); |
| } |
| rewind (output); |
| |
| if (test_alloc_failed |
| && (proxy == NULL)) { |
| TEST_FILE_EQ (output, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| if (last_connection) { |
| dbus_connection_close (last_connection); |
| dbus_connection_unref (last_connection); |
| } |
| |
| dbus_server_disconnect (server); |
| dbus_server_unref (server); |
| |
| dbus_shutdown (); |
| continue; |
| } |
| |
| nih_main_loop (); |
| |
| TEST_TRUE (my_connect_handler_called); |
| TEST_NE_P (last_connection, NULL); |
| |
| TEST_NE_P (proxy, NULL); |
| TEST_ALLOC_SIZE (proxy, sizeof (NihDBusProxy)); |
| |
| TEST_NE_P (proxy->connection, NULL); |
| TEST_EQ_P (proxy->name, NULL); |
| TEST_EQ_P (proxy->owner, NULL); |
| TEST_EQ_STR (proxy->path, DBUS_PATH_UPSTART); |
| TEST_ALLOC_PARENT (proxy->path, proxy); |
| TEST_FALSE (proxy->auto_start); |
| |
| TEST_EQ_P (proxy->lost_handler, NULL); |
| TEST_EQ_P (proxy->data, NULL); |
| |
| nih_free (proxy); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| dbus_connection_close (last_connection); |
| dbus_connection_unref (last_connection); |
| |
| dbus_server_disconnect (server); |
| dbus_server_unref (server); |
| |
| dbus_shutdown (); |
| |
| unsetenv ("UPSTART_SESSION"); |
| user_mode = FALSE; |
| } |
| |
| |
| /* Check that we can create a connection to Upstart via the system |
| * bus. The returned proxy should use the default name on that |
| * bus. |
| */ |
| TEST_FEATURE ("with system bus connection"); |
| TEST_ALLOC_FAIL { |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = NULL; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DIVERT_STDERR (output) { |
| proxy = upstart_open (NULL); |
| } |
| rewind (output); |
| |
| if (test_alloc_failed |
| && (proxy == NULL)) { |
| TEST_FILE_EQ (output, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| continue; |
| } |
| |
| TEST_NE_P (proxy, NULL); |
| TEST_ALLOC_SIZE (proxy, sizeof (NihDBusProxy)); |
| |
| TEST_NE_P (proxy->connection, NULL); |
| TEST_EQ_STR (proxy->name, DBUS_SERVICE_UPSTART); |
| TEST_ALLOC_PARENT (proxy->name, proxy); |
| TEST_EQ_STR (proxy->owner, dbus_bus_get_unique_name (server_conn)); |
| TEST_ALLOC_PARENT (proxy->owner, proxy); |
| TEST_EQ_STR (proxy->path, DBUS_PATH_UPSTART); |
| TEST_ALLOC_PARENT (proxy->path, proxy); |
| TEST_FALSE (proxy->auto_start); |
| |
| TEST_EQ_P (proxy->lost_handler, NULL); |
| TEST_EQ_P (proxy->data, NULL); |
| |
| nih_free (proxy); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| /* Check that we can create a connection to Upstart via the system |
| * bus and a different well known name. |
| */ |
| TEST_FEATURE ("with system bus connection and different name"); |
| TEST_ALLOC_FAIL { |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = "com.ubuntu.UpstartTest"; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, "com.ubuntu.UpstartTest", |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DIVERT_STDERR (output) { |
| proxy = upstart_open (NULL); |
| } |
| rewind (output); |
| |
| if (test_alloc_failed |
| && (proxy == NULL)) { |
| TEST_FILE_EQ (output, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| continue; |
| } |
| |
| TEST_NE_P (proxy, NULL); |
| TEST_ALLOC_SIZE (proxy, sizeof (NihDBusProxy)); |
| |
| TEST_NE_P (proxy->connection, NULL); |
| TEST_EQ_STR (proxy->name, "com.ubuntu.UpstartTest"); |
| TEST_ALLOC_PARENT (proxy->name, proxy); |
| TEST_EQ_STR (proxy->owner, dbus_bus_get_unique_name (server_conn)); |
| TEST_ALLOC_PARENT (proxy->owner, proxy); |
| TEST_EQ_STR (proxy->path, DBUS_PATH_UPSTART); |
| TEST_ALLOC_PARENT (proxy->path, proxy); |
| TEST_FALSE (proxy->auto_start); |
| |
| TEST_EQ_P (proxy->lost_handler, NULL); |
| TEST_EQ_P (proxy->data, NULL); |
| |
| nih_free (proxy); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| /* Check that when we attempt to connect to Upstart's private |
| * internal server, and it's not listening, that an appropriate |
| * error is output. |
| */ |
| TEST_FEATURE ("with non-listening private connection"); |
| TEST_ALLOC_FAIL { |
| use_dbus = FALSE; |
| dest_name = NULL; |
| dest_address = "unix:abstract=/com/ubuntu/upstart/test"; |
| |
| TEST_DIVERT_STDERR (output) { |
| proxy = upstart_open (NULL); |
| } |
| rewind (output); |
| |
| TEST_EQ_P (proxy, NULL); |
| |
| TEST_FILE_EQ (output, ("test: Unable to connect to Upstart: " |
| "Failed to connect to socket /com/ubuntu/upstart/test: " |
| "Connection refused\n")); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| /* Check that when we attempt to connect to the system bus, |
| * and it's not listening, that an appropriate error is output. |
| */ |
| TEST_FEATURE ("with non-listening system bus"); |
| TEST_ALLOC_FAIL { |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = NULL; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| assert0 (setenv ("DBUS_SYSTEM_BUS_ADDRESS", |
| "unix:abstract=/com/ubuntu/upstart/test", |
| TRUE)); |
| |
| TEST_DIVERT_STDERR (output) { |
| proxy = upstart_open (NULL); |
| } |
| rewind (output); |
| |
| TEST_EQ_P (proxy, NULL); |
| |
| TEST_FILE_EQ (output, ("test: Unable to connect to system bus: " |
| "Failed to connect to socket /com/ubuntu/upstart/test: " |
| "Connection refused\n")); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| dbus_shutdown (); |
| |
| unsetenv ("DBUS_SYSTEM_BUS_ADDRESS"); |
| } |
| |
| |
| /* Check that an error and suggestion for help is output |
| * when --dest is given without --system. |
| */ |
| TEST_FEATURE ("with --dest but without --system"); |
| TEST_ALLOC_FAIL { |
| use_dbus = FALSE; |
| dest_name = "com.ubuntu.Upstart"; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| TEST_DIVERT_STDERR (output) { |
| proxy = upstart_open (NULL); |
| } |
| rewind (output); |
| |
| TEST_EQ_P (proxy, NULL); |
| |
| TEST_FILE_EQ (output, "test: --dest given without --system\n"); |
| TEST_FILE_EQ (output, "Try `test --help' for more information.\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| /* Check that when we attempt to connect to Upstart in user mode but |
| * without UPSTART_SESSION set in the environment, an appropriate |
| * error is output. |
| */ |
| TEST_FEATURE ("with user-mode and no target"); |
| TEST_ALLOC_FAIL { |
| use_dbus = -1; |
| dbus_bus_type = -1; |
| dest_name = NULL; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| user_mode = TRUE; |
| |
| unsetenv ("UPSTART_SESSION"); |
| |
| TEST_DIVERT_STDERR (output) { |
| proxy = upstart_open (NULL); |
| } |
| rewind (output); |
| |
| TEST_EQ_P (proxy, NULL); |
| |
| TEST_FILE_EQ (output, ("test: UPSTART_SESSION isn't set in the environment. " |
| "Unable to locate the Upstart instance.\n")); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| dbus_shutdown (); |
| user_mode = FALSE; |
| } |
| |
| fclose (output); |
| } |
| |
| |
| void |
| test_job_status (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| DBusConnection *client_conn; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| const char * interface; |
| const char * property; |
| DBusMessage * reply = NULL; |
| DBusMessageIter iter; |
| DBusMessageIter arrayiter; |
| DBusMessageIter dictiter; |
| DBusMessageIter subiter; |
| DBusMessageIter prociter; |
| DBusMessageIter structiter; |
| const char * str_value; |
| int32_t int32_value; |
| NihDBusProxy * job_class = NULL; |
| NihDBusProxy * job = NULL; |
| char * str; |
| NihError * err; |
| NihDBusError * dbus_err; |
| int status; |
| |
| TEST_FUNCTION ("job_status"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| TEST_DBUS_OPEN (client_conn); |
| |
| |
| /* Check that we can generate a string for a job instance that |
| * is running with a main process. The function should request |
| * the name of the job class, and then request all of the |
| * properties of the job instance. |
| */ |
| TEST_FEATURE ("with running main process"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test start/running, process 3648"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that we can generate a string for a named job instance, |
| * the name should be placed in the returned string in brackets |
| * after the job config name. |
| */ |
| TEST_FEATURE ("with named instance"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/beetroot"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "beetroot"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/beetroot", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test (beetroot) start/running, process 3648"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that we can generate a string for a job instance in a |
| * state that doesn't come with a process, only the goal and |
| * state should be output. |
| */ |
| TEST_FEATURE ("with no process"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "stopping"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test stop/stopping"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that we can generate a string for a job instance with |
| * a running pre-start process, since this is a standard state |
| * with a process, the pid should simply follow the state. |
| */ |
| TEST_FEATURE ("with running pre-start process"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "pre-start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "pre-start"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 1014; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test start/pre-start, process 1014"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that we can generate a string for a job instance with |
| * a running post-stop process, since this is a standard state |
| * with a process, the pid should simply follow the state. |
| */ |
| TEST_FEATURE ("with running post-stop process"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "post-stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "post-stop"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 9764; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test stop/post-stop, process 9764"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that we can generate a string for a job instance with |
| * a running post-start process, but no main process. Since this |
| * is not a standard state process, the process name should be |
| * prefixed. |
| */ |
| TEST_FEATURE ("with running post-start process only"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "post-start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "post-start"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 2137; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test start/post-start, (post-start) process 2137"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that we can generate a string for a job instance with |
| * a running pre-stop process, but no main process. Since this |
| * is not a standard state process, the process name should be |
| * prefixed. |
| */ |
| TEST_FEATURE ("with running pre-stop process only"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "pre-stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "pre-stop"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 7864; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test stop/pre-stop, (pre-stop) process 7864"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| /* Check that we can generate a string for a job instance that |
| * is running with a main process and a simultaneous post-start |
| * process. The main process should be output on the first line |
| * along with the state, the pid of the post-start process should |
| * follow indented on the next line. |
| */ |
| TEST_FEATURE ("with running main and post-start processes"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "post-start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "post-start"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 2137; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, ("test start/post-start, process 3648\n" |
| "\tpost-start process 2137")); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that we can generate a string for a job instance that |
| * is running with a main process and a simultaneous pre-stop |
| * process. The main process should be output on the first line |
| * along with the state, the pid of the pre-stop process should |
| * follow indented on the next line. |
| */ |
| TEST_FEATURE ("with running main and pre-stop processes"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "pre-stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "pre-stop"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 7864; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, ("test stop/pre-stop, process 3648\n" |
| "\tpre-stop process 7864")); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that we can generate a string for a job instance that |
| * is running with a main process, but in one of the "unusual" |
| * states to catch the process in. The process should be output |
| * as normal. |
| */ |
| TEST_FEATURE ("with running main process in spawned state"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "spawned"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test start/spawned, process 3648"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that the function catches the job instance going away |
| * in the mean time (and the server returning the unknown method |
| * error), and handles that as an instance that has freshly |
| * stopped. |
| */ |
| TEST_FEATURE ("with unknown instance"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the properties, reply |
| * with the unknown method error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test stop/waiting"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that NULL can be given as the job instance, and that the |
| * function only requests the name of the job class and outputs |
| * as if there was no instance. |
| */ |
| TEST_FEATURE ("with NULL for instance"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with the |
| * name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, NULL); |
| |
| if (test_alloc_failed |
| && (str == NULL)) { |
| err = nih_error_get (); |
| TEST_EQ (err->number, ENOMEM); |
| nih_free (err); |
| |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ_STR (str, "test stop/waiting"); |
| |
| nih_free (str); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job_class); |
| } |
| |
| |
| /* Check that when the function is passed a bad job class proxy, |
| * it returns the error received from the server. |
| */ |
| TEST_FEATURE ("with bad job class"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the name, reply with an |
| * error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| TEST_ALLOC_SAFE { |
| job_class = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test", |
| NULL, NULL); |
| job = nih_dbus_proxy_new (NULL, client_conn, |
| dbus_bus_get_unique_name (server_conn), |
| DBUS_PATH_UPSTART "/jobs/test/_", |
| NULL, NULL); |
| } |
| |
| str = job_status (NULL, job_class, job); |
| |
| TEST_EQ_P (str, NULL); |
| |
| err = nih_error_get (); |
| |
| if (test_alloc_failed |
| && (err->number == ENOMEM)) { |
| nih_free (err); |
| |
| nih_free (job); |
| nih_free (job_class); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (err->number, NIH_DBUS_ERROR); |
| TEST_ALLOC_SIZE (err, sizeof (NihDBusError)); |
| dbus_err = (NihDBusError *)err; |
| |
| TEST_EQ_STR (dbus_err->name, DBUS_ERROR_UNKNOWN_METHOD); |
| nih_free (dbus_err); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| nih_free (job); |
| nih_free (job_class); |
| } |
| |
| |
| TEST_DBUS_CLOSE (client_conn); |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_start_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| DBusMessage * reply = NULL; |
| const char * name_value; |
| char ** args_value; |
| int args_elements; |
| int wait_value; |
| const char * str_value; |
| const char * interface; |
| const char * property; |
| DBusMessageIter iter; |
| DBusMessageIter subiter; |
| DBusMessageIter arrayiter; |
| DBusMessageIter dictiter; |
| DBusMessageIter prociter; |
| DBusMessageIter structiter; |
| int32_t int32_value; |
| NihCommand command; |
| char * args[4]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("start_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that the start action with a single argument given looks |
| * up a job with that name, and then calls the Start command |
| * passing a NULL array for the events and TRUE for wait. Once |
| * it receives the reply, it will then make queries to obtain the |
| * status of the command and print the output. |
| */ |
| TEST_FEATURE ("with single argument"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Start method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Start")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = start_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that additional arguments to the start action are passed |
| * as entries in the environment argument of the command. |
| */ |
| TEST_FEATURE ("with multiple arguments"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Start method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Start")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 2); |
| TEST_EQ_STR (args_value[0], "FOO=foo"); |
| TEST_EQ_STR (args_value[1], "BAR=bar"); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = "FOO=foo"; |
| args[2] = "BAR=bar"; |
| args[3] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = start_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that the --no-wait option results in the method call |
| * being made with wait as FALSE. |
| */ |
| TEST_FEATURE ("with no wait"); |
| no_wait = TRUE; |
| |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Start method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Start")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_FALSE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = start_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| no_wait = FALSE; |
| |
| |
| /* Check that the start action may be called without arguments |
| * when inside an instance process, due to the environment variables |
| * set there. The job should be stilled looked up, but then the |
| * instance should be looked up via GetInstanceByName and the Start |
| * command run directly on the instance instead in a no-wait fashion. |
| */ |
| TEST_FEATURE ("with no arguments when called from job process"); |
| setenv ("UPSTART_JOB", "test", TRUE); |
| setenv ("UPSTART_INSTANCE", "foo", TRUE); |
| |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstanceByName method call on the |
| * job object, make sure the instance name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstanceByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "foo"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/foo"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Start method call on the instance object, |
| * make the wait argument is FALSE and reply to |
| * to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_INSTANCE, |
| "Start")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/foo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_FALSE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/foo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "foo"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = start_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test (foo) start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| unsetenv ("UPSTART_JOB"); |
| unsetenv ("UPSTART_INSTANCE"); |
| |
| |
| /* Check that if an error is received from the GetJobByName call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to GetJobByName"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = start_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the Start call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to Start"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Start method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Start")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = start_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the status query, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to status query"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Start method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Start")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the job name, reply with |
| * an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = start_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that a missing argument results in an error being output |
| * to stderr along with a suggestion of help. |
| */ |
| TEST_FEATURE ("with missing argument"); |
| TEST_ALLOC_FAIL { |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = start_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: missing job name\n"); |
| TEST_FILE_EQ (errors, "Try `test --help' for more information.\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_stop_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| DBusMessage * reply = NULL; |
| const char * name_value; |
| char ** args_value; |
| int args_elements; |
| int wait_value; |
| const char * str_value; |
| const char * interface; |
| const char * property; |
| DBusMessageIter iter; |
| DBusMessageIter subiter; |
| NihCommand command; |
| char * args[4]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("stop_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that the stop action with a single argument given looks |
| * up a job with that name, then looks up the instance with a NULL |
| * arguments array (to get the path for later) and then calls the |
| * Stop command passing a NULL array for the events and TRUE for wait. |
| * Once it receives the reply, it will then make queries to obtain the |
| * status of the command and print the output. |
| */ |
| TEST_FEATURE ("with single argument"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Stop method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Stop")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with an unknown method error since |
| * there will be no instance at this point. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = stop_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test stop/waiting\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that additional arguments to the stop action are passed |
| * as entries in the environment argument of the command. |
| */ |
| TEST_FEATURE ("with multiple arguments"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 2); |
| TEST_EQ_STR (args_value[0], "FOO=foo"); |
| TEST_EQ_STR (args_value[1], "BAR=bar"); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Stop method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Stop")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 2); |
| TEST_EQ_STR (args_value[0], "FOO=foo"); |
| TEST_EQ_STR (args_value[1], "BAR=bar"); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with an unknown method error since |
| * there will be no instance at this point. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = "FOO=foo"; |
| args[2] = "BAR=bar"; |
| args[3] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = stop_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test stop/waiting\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that the --no-wait option results in the method call |
| * being made with wait as FALSE. |
| */ |
| TEST_FEATURE ("with no wait"); |
| no_wait = TRUE; |
| |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Stop method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Stop")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_FALSE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with an unknown method error since |
| * there will be no instance at this point. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = stop_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test stop/waiting\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| no_wait = FALSE; |
| |
| |
| /* Check that the stop action may be called without arguments |
| * when inside an instance process, due to the environment variables |
| * set there. The job should be still looked up, but then the |
| * instance should be looked up via GetInstanceByName and the Stop |
| * command run directly on the instance instead in a no-wait fashion. |
| */ |
| TEST_FEATURE ("with no arguments when called from job process"); |
| setenv ("UPSTART_JOB", "test", TRUE); |
| setenv ("UPSTART_INSTANCE", "foo", TRUE); |
| |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstanceByName method call on the |
| * job object, make sure the instance name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstanceByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "foo"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/foo"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Stop method call on the instance object, |
| * make the wait argument is FALSE and reply to |
| * to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_INSTANCE, |
| "Stop")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/foo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_FALSE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with an unknown method error since |
| * there will be no instance at this point. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/foo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = stop_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test stop/waiting\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| unsetenv ("UPSTART_JOB"); |
| unsetenv ("UPSTART_INSTANCE"); |
| |
| |
| /* Check that if an error is received from the GetJobByName call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to GetJobByName"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = stop_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the GetInstance call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to GetInstance"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = stop_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the Stop call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to Stop"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Stop method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Stop")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = stop_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the status query, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to status query"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Stop method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Stop")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the job name, reply with |
| * an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = stop_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that a missing argument results in an error being output |
| * to stderr along with a suggestion of help. |
| */ |
| TEST_FEATURE ("with missing argument"); |
| TEST_ALLOC_FAIL { |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = stop_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: missing job name\n"); |
| TEST_FILE_EQ (errors, "Try `test --help' for more information.\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_restart_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| DBusMessage * reply = NULL; |
| const char * name_value; |
| char ** args_value; |
| int args_elements; |
| int wait_value; |
| const char * str_value; |
| const char * interface; |
| const char * property; |
| DBusMessageIter iter; |
| DBusMessageIter subiter; |
| DBusMessageIter arrayiter; |
| DBusMessageIter dictiter; |
| DBusMessageIter prociter; |
| DBusMessageIter structiter; |
| int32_t int32_value; |
| NihCommand command; |
| char * args[4]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("restart_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that the restart action with a single argument given looks |
| * up a job with that name, and then calls the Restart command |
| * passing a NULL array for the events and TRUE for wait. Once |
| * it receives the reply, it will then make queries to obtain the |
| * status of the command and print the output. |
| */ |
| TEST_FEATURE ("with single argument"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Start method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Restart")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = restart_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that additional arguments to the restart action are passed |
| * as entries in the environment argument of the command. |
| */ |
| TEST_FEATURE ("with multiple arguments"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Restart method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Restart")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 2); |
| TEST_EQ_STR (args_value[0], "FOO=foo"); |
| TEST_EQ_STR (args_value[1], "BAR=bar"); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = "FOO=foo"; |
| args[2] = "BAR=bar"; |
| args[3] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = restart_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that the --no-wait option results in the method call |
| * being made with wait as FALSE. |
| */ |
| TEST_FEATURE ("with no wait"); |
| no_wait = TRUE; |
| |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Restart method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Restart")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_FALSE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = restart_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| no_wait = FALSE; |
| |
| |
| /* Check that the restart action may be called without arguments |
| * when inside an instance process, due to the environment variables |
| * set there. The job should be stilled looked up, but then the |
| * instance should be looked up via GetInstanceByName and the Restart |
| * command run directly on the instance instead in a no-wait fashion. |
| */ |
| TEST_FEATURE ("with no arguments when called from job process"); |
| setenv ("UPSTART_JOB", "test", TRUE); |
| setenv ("UPSTART_INSTANCE", "foo", TRUE); |
| |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstanceByName method call on the |
| * job object, make sure the instance name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstanceByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "foo"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/foo"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Restart method call on the instance |
| * object, make the wait argument is FALSE and reply to |
| * to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_INSTANCE, |
| "Restart")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/foo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_FALSE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* We allow the client to get the properties as many |
| * times as it likes, since it repeats this in out |
| * of memory cases. |
| */ |
| for (;;) { |
| signal (SIGHUP, hup_handler_empty); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/foo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "foo"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| } |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = restart_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test (foo) start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGHUP); |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| unsetenv ("UPSTART_JOB"); |
| unsetenv ("UPSTART_INSTANCE"); |
| |
| |
| /* Check that if an error is received from the GetJobByName call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to GetJobByName"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = restart_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the Restart call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to Restart"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Restart method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Restart")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = restart_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the status query, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to status query"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Restart method call on the job object, |
| * make sure the environment and wait arguments |
| * are right and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "Restart")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the job name, reply with |
| * an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = restart_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that a missing argument results in an error being output |
| * to stderr along with a suggestion of help. |
| */ |
| TEST_FEATURE ("with missing argument"); |
| TEST_ALLOC_FAIL { |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = restart_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: missing job name\n"); |
| TEST_FILE_EQ (errors, "Try `test --help' for more information.\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_reload_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| pid_t proc_pid; |
| DBusMessage * method_call; |
| DBusMessage * reply = NULL; |
| const char * name_value; |
| char ** args_value; |
| int args_elements; |
| const char * str_value; |
| const char * interface; |
| const char * property; |
| DBusMessageIter iter; |
| DBusMessageIter subiter; |
| DBusMessageIter arrayiter; |
| DBusMessageIter structiter; |
| int32_t int32_value; |
| NihCommand command; |
| char * args[4]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("reload_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that the reload action with a single argument given looks |
| * up a job with that name, then requests the list of processes |
| * sending a SIGHUP signal to the main process. |
| */ |
| TEST_FEATURE ("with single argument"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Reload call against job instance |
| * and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_INSTANCE, |
| "Reload")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = reload_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that additional arguments to the restart action are passed |
| * as entries in the environment argument of the command. |
| */ |
| TEST_FEATURE ("with multiple arguments"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 2); |
| TEST_EQ_STR (args_value[0], "FOO=foo"); |
| TEST_EQ_STR (args_value[1], "BAR=bar"); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Reload call against job instance |
| * and reply with an instance path to |
| * acknowledge |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_INSTANCE, |
| "Reload")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = "FOO=foo"; |
| args[2] = "BAR=bar"; |
| args[3] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = reload_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that the reload action may be called without arguments |
| * when inside an instance process, due to the environment variables |
| * set there. The job should be stilled looked up, but then the |
| * instance should be looked up via GetInstanceByName instead. |
| */ |
| TEST_FEATURE ("with no arguments when called from job process"); |
| setenv ("UPSTART_JOB", "test", TRUE); |
| setenv ("UPSTART_INSTANCE", "foo", TRUE); |
| |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstanceByName method call on the |
| * job object, make sure the instance name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstanceByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "foo"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/foo"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Reload call against job instance |
| * and reply with an instance path to |
| * acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_INSTANCE, |
| "Reload")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/foo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = reload_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| unsetenv ("UPSTART_JOB"); |
| unsetenv ("UPSTART_INSTANCE"); |
| |
| |
| /* Check that if an error is received from the GetJobByName call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to GetJobByName"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = reload_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the GetInstance call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to GetInstance"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = reload_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the Reload call, |
| * the fallback path is used to query main pid and SIGHUP |
| * that. |
| */ |
| TEST_FEATURE ("with error reply to Reload"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (proc_pid) { |
| pause (); |
| } |
| |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Reload method call against job |
| * instance and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_INSTANCE, |
| "Reload")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the processes, reply with |
| * a main process pid. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = proc_pid; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&arrayiter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &arrayiter); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = reload_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| kill (proc_pid, SIGTERM); |
| waitpid (proc_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| |
| kill (proc_pid, SIGTERM); |
| waitpid (proc_pid, NULL, 0); |
| continue; |
| |
| } |
| |
| |
| /* Check that a missing argument results in an error being output |
| * to stderr along with a suggestion of help. |
| */ |
| TEST_FEATURE ("with missing argument"); |
| TEST_ALLOC_FAIL { |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = reload_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: missing job name\n"); |
| TEST_FILE_EQ (errors, "Try `test --help' for more information.\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_status_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| DBusMessage * reply = NULL; |
| const char * name_value; |
| char ** args_value; |
| int args_elements; |
| const char * str_value; |
| const char * interface; |
| const char * property; |
| DBusMessageIter iter; |
| DBusMessageIter subiter; |
| DBusMessageIter arrayiter; |
| DBusMessageIter dictiter; |
| DBusMessageIter prociter; |
| DBusMessageIter structiter; |
| int32_t int32_value; |
| NihCommand command; |
| char * args[4]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("status_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| use_dbus = TRUE; |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that the status action with a single argument given looks |
| * up a job with that name, then looks up the instance with a NULL |
| * arguments array (to get the path for later) and then makes |
| * queries to obtain the status of that instance printing the |
| * output. |
| */ |
| TEST_FEATURE ("with single argument"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = status_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that additional arguments to the status action are passed |
| * as entries in the environment to GetInstance. |
| */ |
| TEST_FEATURE ("with multiple arguments"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 2); |
| TEST_EQ_STR (args_value[0], "FOO=foo"); |
| TEST_EQ_STR (args_value[1], "BAR=bar"); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = "FOO=foo"; |
| args[2] = "BAR=bar"; |
| args[3] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = status_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that the status action may be called without arguments |
| * when inside an instance process, due to the environment variables |
| * set there. The job should be still looked up, but then the |
| * instance should be looked up via GetInstanceByName and the |
| * queries run on that instance. |
| */ |
| TEST_FEATURE ("with no arguments when called from job process"); |
| setenv ("UPSTART_JOB", "test", TRUE); |
| setenv ("UPSTART_INSTANCE", "foo", TRUE); |
| |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstanceByName method call on the |
| * job object, make sure the instance name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstanceByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "foo"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/foo"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test/foo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "foo"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = status_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test (foo) start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| unsetenv ("UPSTART_JOB"); |
| unsetenv ("UPSTART_INSTANCE"); |
| |
| |
| /* Check that an unknown instance error from the GetInstance call |
| * is treated as a stopped job; the job name should still be |
| * queried but not the instance properties. |
| */ |
| TEST_FEATURE ("with unknown instance"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with an error |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_INTERFACE_UPSTART ".Error.UnknownInstance", |
| "Unknown instance"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the job name, reply with |
| * the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "test"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = status_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "test stop/waiting\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that if an error is received from the GetJobByName call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to GetJobByName"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = status_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the GetInstance command, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to GetInstance"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = status_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the status query, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to status query"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetJobByName method call on the |
| * manager object, make sure the job name is passed |
| * and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetJobByName")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "test"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetInstance method call on the |
| * job object, make sure the environment args are |
| * passed and reply with a path. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetInstance")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/test/_"; |
| |
| dbus_message_append_args (reply, |
| DBUS_TYPE_OBJECT_PATH, &str_value, |
| DBUS_TYPE_INVALID); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the job name, reply with |
| * an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/test"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "test"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = status_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that a missing argument results in an error being output |
| * to stderr along with a suggestion of help. |
| */ |
| TEST_FEATURE ("with missing argument"); |
| TEST_ALLOC_FAIL { |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = status_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: missing job name\n"); |
| TEST_FILE_EQ (errors, "Try `test --help' for more information.\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| void |
| test_list (void) |
| { |
| char dirname[PATH_MAX]; |
| nih_local char *cmd = NULL; |
| pid_t upstart_pid = 0; |
| pid_t dbus_pid = 0; |
| char **output; |
| size_t lines; |
| char expected_output[] = "foo stop/waiting"; |
| |
| TEST_GROUP ("list"); |
| |
| TEST_FILENAME (dirname); |
| TEST_EQ (mkdir (dirname, 0755), 0); |
| |
| /* Use the "secret" interface */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", dirname, 1), 0); |
| |
| TEST_DBUS (dbus_pid); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("single job"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "exec echo hello"); |
| START_UPSTART (upstart_pid, FALSE); |
| |
| cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| DELETE_FILE (dirname, "foo.conf"); |
| STOP_UPSTART (upstart_pid); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("3 jobs and re-exec"); |
| |
| CREATE_FILE (dirname, "foo.conf", "exec echo foo"); |
| CREATE_FILE (dirname, "bar.conf", "exec echo bar"); |
| CREATE_FILE (dirname, "baz.conf", "exec echo bar"); |
| START_UPSTART (upstart_pid, FALSE); |
| |
| cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| /* guarantee output ordering */ |
| qsort (output, lines, sizeof (output[0]), strcmp_compar); |
| |
| TEST_EQ_STR (output[0], "bar stop/waiting"); |
| TEST_EQ_STR (output[1], "baz stop/waiting"); |
| TEST_EQ_STR (output[2], "foo stop/waiting"); |
| TEST_EQ (lines, 3); |
| nih_free (output); |
| |
| REEXEC_UPSTART (upstart_pid, FALSE); |
| |
| /* Ensure we can still list jobs after a re-exec */ |
| cmd = nih_sprintf (NULL, "%s list 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| /* guarantee output ordering */ |
| qsort (output, lines, sizeof (output[0]), strcmp_compar); |
| |
| TEST_EQ_STR (output[0], "bar stop/waiting"); |
| TEST_EQ_STR (output[1], "baz stop/waiting"); |
| TEST_EQ_STR (output[2], "foo stop/waiting"); |
| TEST_EQ (lines, 3); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| DELETE_FILE (dirname, "bar.conf"); |
| DELETE_FILE (dirname, "baz.conf"); |
| |
| STOP_UPSTART (upstart_pid); |
| |
| /*******************************************************************/ |
| |
| TEST_EQ (unsetenv ("UPSTART_CONFDIR"), 0); |
| TEST_DBUS_END (dbus_pid); |
| TEST_EQ (rmdir (dirname), 0); |
| } |
| |
| void |
| test_reexec (void) |
| { |
| char confdir[PATH_MAX]; |
| char logdir[PATH_MAX]; |
| char flagfile[PATH_MAX]; |
| nih_local char *cmd = NULL; |
| pid_t job_pid = 0; |
| pid_t tmp = 0; |
| pid_t dbus_pid = 0; |
| pid_t upstart_pid = 0; |
| char **output; |
| size_t lines; |
| nih_local char *logfile = NULL; |
| nih_local char *out_file = NULL; |
| struct stat statbuf; |
| nih_local char *contents = NULL; |
| FILE *file; |
| int ok; |
| int ret; |
| mode_t expected_umask; |
| size_t len; |
| |
| TEST_GROUP ("re-exec support"); |
| |
| TEST_FILENAME (confdir); |
| TEST_EQ (mkdir (confdir, 0755), 0); |
| |
| TEST_FILENAME (logdir); |
| TEST_EQ (mkdir (logdir, 0755), 0); |
| |
| TEST_FILENAME (flagfile); |
| |
| /* Use the "secret" interface */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0); |
| TEST_EQ (setenv ("UPSTART_LOGDIR", logdir, 1), 0); |
| |
| TEST_DBUS (dbus_pid); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("single job producing output across a re-exec"); |
| |
| start_upstart_common (&upstart_pid, FALSE, FALSE, confdir, logdir, NULL); |
| |
| contents = nih_sprintf (NULL, |
| "console log\n" |
| "pre-start exec echo pre-start\n" |
| "script\n" |
| "\n" |
| "# Write first half of data\n" |
| "for i in 1 2 3 4 5\n" |
| "do\n" |
| " echo $i\n" |
| "done\n" |
| "\n" |
| "# hack to wait for notification that Upstart has re-exec'ed\n" |
| "while [ ! -f \"%s\" ]\n" |
| "do\n" |
| " sleep 0.1\n" |
| "done\n" |
| "\n" |
| "# remove flag file\n" |
| "rm -f \"%s\"\n" |
| "\n" |
| "# Write remaining data\n" |
| "for i in 6 7 8 9 10\n" |
| "do\n" |
| " echo $i\n" |
| "done\n" |
| "\n" |
| "# hang around until killed\n" |
| "sleep 999\n" |
| "\n" |
| "end script\n", |
| flagfile, flagfile); |
| TEST_NE_P (contents, NULL); |
| |
| CREATE_FILE (confdir, "foo.conf", contents); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| nih_free (output); |
| |
| /* check job is running */ |
| job_pid = job_to_pid ("foo"); |
| TEST_NE (job_pid, -1); |
| |
| logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "foo.log")); |
| |
| /* Wait for log to be created */ |
| ok = FALSE; |
| for (int i = 0; i < 50; i++) { |
| msleep (100); |
| if (! stat (logfile, &statbuf)) { |
| ok = TRUE; |
| break; |
| } |
| } |
| TEST_EQ (ok, TRUE); |
| |
| file = fopen (logfile, "r"); |
| TEST_NE_P (file, NULL); |
| |
| /* check contents of log file */ |
| TEST_FILE_EQ (file, "pre-start\r\n"); |
| for (int i = 1; i < 6; i++) { |
| nih_local char *line = NIH_MUST (nih_sprintf (NULL, "%d\r\n", i)); |
| TEST_FILE_EQ (file, line); |
| } |
| TEST_FILE_END (file); |
| fclose (file); |
| |
| REEXEC_UPSTART (upstart_pid, FALSE); |
| |
| /* Create flag file to allow job to proceed */ |
| { |
| FILE *f; |
| f = fopen (flagfile, "w"); |
| TEST_NE_P (f, NULL); |
| fclose (f); |
| } |
| |
| /* ensure job is still running */ |
| tmp = job_to_pid ("foo"); |
| TEST_NE (tmp, -1); |
| |
| /* ensure it hasn't changed pid */ |
| TEST_EQ (job_pid, tmp); |
| |
| /* wait for script to remove flag file */ |
| ok = FALSE; |
| for (int i = 1; i < 60; i++) { |
| ret = stat (flagfile, &statbuf); |
| |
| if (ret < 0 && errno == ENOENT) { |
| ok = TRUE; |
| break; |
| } |
| msleep (100); |
| } |
| |
| TEST_EQ (ok, TRUE); |
| |
| cmd = nih_sprintf (NULL, "%s stop %s 2>&1", |
| get_initctl (), "foo"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| nih_free (output); |
| |
| /* Wait for job to finish. We can't waitpid() for it as it's not one |
| * of our children. |
| */ |
| ok = FALSE; |
| for (int i = 0; i < 50; i++) { |
| nih_local char *path = NIH_MUST (nih_sprintf (NULL, "/proc/%d", job_pid)); |
| if (stat (path, &statbuf) < 0 && errno == ENOENT) { |
| ok = TRUE; |
| break; |
| } |
| msleep (100); |
| } |
| TEST_EQ (ok, TRUE); |
| tmp = job_to_pid ("foo"); |
| TEST_EQ (tmp, -1); |
| |
| TEST_EQ (stat (logfile, &statbuf), 0); |
| |
| file = fopen (logfile, "r"); |
| TEST_NE_P (file, NULL); |
| |
| /* check contents of log file */ |
| TEST_FILE_EQ (file, "pre-start\r\n"); |
| for (int i = 1; i < 11; i++) { |
| nih_local char *line = NIH_MUST (nih_sprintf (NULL, "%d\r\n", i)); |
| TEST_FILE_EQ (file, line); |
| } |
| TEST_FILE_END (file); |
| fclose (file); |
| |
| /* ensure script removed flagfile */ |
| TEST_LT (stat (flagfile, &statbuf), 0); |
| |
| DELETE_FILE (confdir, "foo.conf"); |
| DELETE_FILE (logdir, "foo.log"); |
| STOP_UPSTART (upstart_pid); |
| |
| TEST_EQ (unsetenv ("UPSTART_CONFDIR"), 0); |
| TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure 'set-env' persists across session-init re-exec"); |
| |
| TEST_TRUE (getenv ("XDG_RUNTIME_DIR")); |
| |
| contents = nih_sprintf (NULL, |
| "console log\n" |
| "start on startup\n" |
| "\n" |
| "pre-start script\n" |
| "%s set-env foo=bar\n" |
| "\n" |
| "# create flag file\n" |
| "touch \"%s\"\n" |
| "\n" |
| "end script\n" |
| "\n" |
| "# a minimal main process\n" |
| "exec true\n" |
| "\n" |
| "post-stop script\n" |
| "\n" |
| "# wait for upstart to notify us that it has re-execed\n" |
| "while [ -f \"%s\" ]\n" |
| "do\n" |
| " sleep 0.1\n" |
| "done\n" |
| "\n" |
| "# query value post-re-exec\n" |
| "%s get-env foo\n" |
| "\n" |
| "end script\n", |
| get_initctl_binary(), flagfile, flagfile, get_initctl_binary()); |
| TEST_NE_P (contents, NULL); |
| |
| CREATE_FILE (confdir, "foo.conf", contents); |
| |
| start_upstart_common (&upstart_pid, TRUE, TRUE, confdir, logdir, NULL); |
| |
| WAIT_FOR_FILE (flagfile); |
| |
| /* check job is running */ |
| job_pid = job_to_pid ("foo"); |
| TEST_NE (job_pid, -1); |
| |
| REEXEC_UPSTART (upstart_pid, TRUE); |
| |
| /* Notify job that upstart has re-exec'd */ |
| assert0 (unlink (flagfile)); |
| |
| logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "foo.log")); |
| |
| WAIT_FOR_FILE (logfile); |
| file = fopen (logfile, "r"); |
| TEST_NE_P (file, NULL); |
| TEST_FILE_EQ (file, "bar\r\n"); |
| fclose (file); |
| |
| STOP_UPSTART (upstart_pid); |
| assert0 (unlink (logfile)); |
| DELETE_FILE (confdir, "foo.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure 'set-env --global' persists across session-init re-exec"); |
| |
| START_UPSTART (upstart_pid, TRUE); |
| |
| /* Set variable. Use confdir as a random value */ |
| cmd = nih_sprintf (NULL, "%s set-env --global path='%s' 2>&1", get_initctl (), confdir); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| /* Check it */ |
| cmd = nih_sprintf (NULL, "%s get-env --global path 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], confdir); |
| nih_free (output); |
| |
| /* Restart */ |
| REEXEC_UPSTART (upstart_pid, TRUE); |
| |
| /* Re-check */ |
| cmd = nih_sprintf (NULL, "%s get-env --global path 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], confdir); |
| nih_free (output); |
| |
| STOP_UPSTART (upstart_pid); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure re-exec does not disrupt umask"); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "umask.out")); |
| |
| contents = nih_sprintf (NULL, "task\nexec sh -c umask >\"%s\"", |
| out_file); |
| TEST_NE_P (contents, NULL); |
| |
| CREATE_FILE (confdir, "umask.conf", contents); |
| nih_free (contents); |
| |
| start_upstart_common (&upstart_pid, TRUE, TRUE, confdir, logdir, NULL); |
| |
| cmd = nih_sprintf (NULL, "%s start umask 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| nih_free (output); |
| |
| contents = nih_file_read (NULL, out_file, &len); |
| TEST_NE_P (contents, NULL); |
| TEST_GT (len, 0); |
| |
| /* overwrite '\n' */ |
| contents[len-1] = '\0'; |
| |
| expected_umask = (mode_t)atoi (contents); |
| assert0 (unlink (out_file)); |
| nih_free (contents); |
| |
| /* Restart */ |
| REEXEC_UPSTART (upstart_pid, TRUE); |
| |
| /* Re-run job */ |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| nih_free (output); |
| |
| contents = nih_file_read (NULL, out_file, &len); |
| TEST_NE_P (contents, NULL); |
| TEST_GT (len, 0); |
| |
| /* overwrite '\n' */ |
| contents[len-1] = '\0'; |
| |
| TEST_EQ (expected_umask, (mode_t)atoi (contents)); |
| |
| STOP_UPSTART (upstart_pid); |
| |
| DELETE_FILE (confdir, "umask.conf"); |
| assert0 (unlink (out_file)); |
| |
| /*******************************************************************/ |
| |
| TEST_DBUS_END (dbus_pid); |
| |
| TEST_EQ (rmdir (confdir), 0); |
| TEST_EQ (rmdir (logdir), 0); |
| |
| /*******************************************************************/ |
| } |
| |
| void |
| test_list_sessions (void) |
| { |
| char dirname[PATH_MAX]; |
| char confdir[PATH_MAX]; |
| nih_local char *cmd = NULL; |
| pid_t upstart_pid = 0; |
| char **output; |
| size_t lines; |
| struct stat statbuf; |
| nih_local char *contents = NULL; |
| nih_local char *session_file = NULL; |
| nih_local char *path = NULL; |
| nih_local char *expected = NULL; |
| nih_local char *original_runtime = NULL; |
| size_t len; |
| char *value; |
| FILE *f = NULL; |
| |
| TEST_GROUP ("list-sessions"); |
| |
| original_runtime = nih_strdup (NULL, getenv("XDG_RUNTIME_DIR")); |
| TEST_NE_P (original_runtime, NULL); |
| |
| TEST_FILENAME (dirname); |
| TEST_EQ (mkdir (dirname, 0755), 0); |
| |
| TEST_FILENAME (confdir); |
| TEST_EQ (mkdir (confdir, 0755), 0); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("with no instances and XDG_RUNTIME_DIR unset"); |
| |
| assert0 (unsetenv ("XDG_RUNTIME_DIR")); |
| cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_EQ_STR (output[0], "initctl: Unable to query session directory"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("with no instances and XDG_RUNTIME_DIR set"); |
| |
| TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); |
| |
| cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("with no instances and an empty session file"); |
| |
| /* Use the "secret" interface */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0); |
| TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); |
| |
| /* Garbage PID; it doesn't really matter if it exists. */ |
| session_file = get_session_file (dirname, 42); |
| |
| /* Empty file */ |
| f = fopen (session_file, "w"); |
| TEST_NE_P (f, NULL); |
| fclose (f); |
| |
| cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| TEST_EQ (unlink(session_file), 0); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("with 1 running instance"); |
| |
| /* Use the "secret" interface */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0); |
| TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); |
| |
| /* Reset initctl global from previous tests */ |
| dest_name = NULL; |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, NULL, NULL, NULL); |
| |
| session_file = get_session_file (dirname, upstart_pid); |
| |
| /* session file should now have been created by Upstart */ |
| TEST_EQ (stat (session_file, &statbuf), 0); |
| |
| contents = nih_file_read (NULL, session_file, &len); |
| TEST_NE_P (contents, NULL); |
| TEST_TRUE (len); |
| |
| /* overwrite '\n' */ |
| contents[len-1] = '\0'; |
| |
| TEST_EQ_P (strstr (contents, "UPSTART_SESSION="), contents); |
| value = strchr (contents, '='); |
| TEST_NE_P (value, NULL); |
| |
| /* jump over '=' */ |
| value++; |
| TEST_NE_P (value, NULL); |
| |
| expected = nih_sprintf (NULL, "%d %s", (int)upstart_pid, value); |
| |
| cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_EQ_STR (output[0], expected); |
| nih_free (output); |
| |
| STOP_UPSTART (upstart_pid); |
| |
| /* Upstart cannot yet be instructed to shutdown cleanly, so for |
| * now we have to remove the session file manually. |
| */ |
| TEST_EQ (unlink (session_file), 0); |
| |
| /* Remove the directory tree the Session Init created */ |
| path = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions", dirname)); |
| TEST_EQ (rmdir (path), 0); |
| path = NIH_MUST (nih_sprintf (NULL, "%s/upstart", dirname)); |
| TEST_EQ (rmdir (path), 0); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("with 1 instance and an empty session file"); |
| |
| /* Use the "secret" interface */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0); |
| TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); |
| |
| /* Reset initctl global from previous tests */ |
| dest_name = NULL; |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, NULL, NULL, NULL); |
| |
| session_file = get_session_file (dirname, upstart_pid); |
| |
| /* session file should now have been created by Upstart */ |
| TEST_EQ (stat (session_file, &statbuf), 0); |
| |
| /* Rewrite with empty contents */ |
| f = fopen (session_file, "w"); |
| TEST_NE_P (f, NULL); |
| fclose (f); |
| |
| cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| STOP_UPSTART (upstart_pid); |
| |
| /* Upstart cannot yet be instructed to shutdown cleanly, so for |
| * now we have to remove the session file manually. |
| */ |
| TEST_EQ (unlink (session_file), 0); |
| |
| /* Remove the directory tree the Session Init created */ |
| path = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions", dirname)); |
| TEST_EQ (rmdir (path), 0); |
| path = NIH_MUST (nih_sprintf (NULL, "%s/upstart", dirname)); |
| TEST_EQ (rmdir (path), 0); |
| |
| /*******************************************************************/ |
| |
| assert0 (unsetenv ("UPSTART_CONFDIR")); |
| |
| TEST_EQ (rmdir (dirname), 0); |
| TEST_EQ (rmdir (confdir), 0); |
| |
| TEST_EQ (setenv ("XDG_RUNTIME_DIR", original_runtime, 1), 0); |
| |
| /*******************************************************************/ |
| } |
| |
| void |
| test_no_dbus (void) |
| { |
| nih_local char *cmd = NULL; |
| char confdir[PATH_MAX]; |
| char logdir[PATH_MAX]; |
| nih_local char *contents = NULL; |
| nih_local char *logfile = NULL; |
| char **output; |
| size_t lines; |
| pid_t upstart_pid = 0; |
| pid_t dbus_pid = 0; |
| char *extra[] = { "--no-dbus", NULL }; |
| struct stat statbuf; |
| |
| TEST_GROUP ("Test '--no-dbus'"); |
| |
| 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); |
| |
| /* We need a signaling mechanism besides D-Bus; we make an auxiliary |
| * starup job for this. |
| */ |
| contents = nih_sprintf (NULL, |
| "console log\n" |
| "start on startup\n" |
| "exec echo started\n"); |
| TEST_NE_P (contents, NULL); |
| CREATE_FILE (confdir, "startup.conf", contents); |
| |
| logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", logdir, "startup.log")); |
| |
| TEST_DBUS (dbus_pid); |
| |
| /*******************************************************************/ |
| /* First perform a sanity check */ |
| |
| TEST_FEATURE ("Ensure version can be queried normally"); |
| |
| TEST_LT (stat (logfile, &statbuf), 0); |
| TEST_EQ (errno, ENOENT); |
| |
| start_upstart_common (&upstart_pid, FALSE, FALSE, confdir, logdir, NULL); |
| |
| /* Just check we got far enough to run the startup job and (start to) |
| * write its logfile. |
| */ |
| WAIT_FOR_FILE(logfile); |
| |
| cmd = nih_sprintf (NULL, "%s version 2>/dev/null", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], "init*(upstart [0-9]*"); |
| nih_free (output); |
| |
| STOP_UPSTART (upstart_pid); |
| assert0 (unlink (logfile)); |
| |
| /*******************************************************************/ |
| /* Now, try with dbus disabled */ |
| |
| TEST_FEATURE ("Ensure '--no-dbus' disables D-Bus"); |
| |
| TEST_LT (stat (logfile, &statbuf), 0); |
| TEST_EQ (errno, ENOENT); |
| |
| start_upstart_common (&upstart_pid, FALSE, FALSE, confdir, logdir, extra); |
| |
| /* Just check we got far enough to run the startup job and (start to) |
| * write its logfile. |
| */ |
| WAIT_FOR_FILE(logfile); |
| |
| cmd = nih_sprintf (NULL, "%s version 2>/dev/null", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| /* No output on stdout expected */ |
| TEST_EQ (lines, 0); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("Ensure D-Bus still disabled on SIGUSR1"); |
| |
| assert0 (kill (upstart_pid, SIGUSR1)); |
| |
| cmd = nih_sprintf (NULL, "%s version 2>/dev/null", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| /* No output on stdout expected */ |
| TEST_EQ (lines, 0); |
| |
| STOP_UPSTART (upstart_pid); |
| assert0 (unlink (logfile)); |
| |
| /*******************************************************************/ |
| |
| TEST_DBUS_END (dbus_pid); |
| |
| DELETE_FILE (confdir, "startup.conf"); |
| TEST_EQ (rmdir (logdir), 0); |
| TEST_EQ (rmdir (confdir), 0); |
| } |
| |
| /* Quiesce does not reliably reap all children. Supply a helper for reaping the |
| * child we're testing for, as well as a best-effort pass on anything else that |
| * may have leaked. |
| */ |
| static void |
| reap_quiesced_child (pid_t pid) |
| { |
| /* Quiesce *may* have already reaped; only ensure we don't time out |
| * (ret == 0). |
| */ |
| TEST_NE (timed_waitpid (pid, 1+TEST_QUIESCE_KILL_PHASE), 0); |
| |
| /* One last pass at reaping other children. */ |
| nih_child_poll (); |
| } |
| |
| void |
| test_quiesce (void) |
| { |
| char confdir[PATH_MAX]; |
| char logdir[PATH_MAX]; |
| char pid_file[PATH_MAX]; |
| nih_local char *sessiondir; |
| nih_local char *cmd = NULL; |
| pid_t upstart_pid = 0; |
| nih_local char *logfile = NULL; |
| FILE *file; |
| char **output; |
| size_t lines; |
| nih_local NihDBusProxy *upstart = NULL; |
| nih_local char *session_file = NULL; |
| nih_local char *job = NULL; |
| pid_t job_pid; |
| |
| TEST_GROUP ("Session Init quiesce"); |
| |
| /******************************************************************* |
| * NB: quiesce features are known to be unreliable at reaping all |
| * children. To control reaping even when our children misbehave, we |
| * claim subreaper privileges. |
| */ |
| TEST_EQ (prctl (PR_SET_CHILD_SUBREAPER, 1), 0); |
| /*******************************************************************/ |
| |
| TEST_FILENAME (confdir); |
| TEST_EQ (mkdir (confdir, 0755), 0); |
| |
| TEST_FILENAME (logdir); |
| TEST_EQ (mkdir (logdir, 0755), 0); |
| |
| sessiondir = nih_strdup (NULL, getenv ("XDG_RUNTIME_DIR")); |
| TEST_NE_P (sessiondir, NULL); |
| |
| cmd = nih_sprintf (NULL, |
| "rm -f %s/upstart/sessions/*.session 2>/dev/null", |
| sessiondir); |
| assert0 (system (cmd)); |
| |
| /* Use the "secret" interface */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0); |
| TEST_EQ (setenv ("UPSTART_LOGDIR", logdir, 1), 0); |
| |
| /* Reset initctl global from previous tests */ |
| dest_name = NULL; |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("system shutdown: no jobs"); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| /* Trigger shutdown */ |
| assert0 (kill (upstart_pid, SIGTERM)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("system shutdown: one long-running job"); |
| |
| CREATE_FILE (confdir, "long-running.conf", |
| "exec sleep 999"); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
| get_initctl (), "long-running"); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| job_pid = job_to_pid ("long-running"); |
| TEST_NE (job_pid, -1); |
| |
| /* Trigger shutdown */ |
| assert0 (kill (upstart_pid, SIGTERM)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| /* Wait for longer than we expect the Session Init to take to |
| * shutdown to give it time to send SIGKILL to all job |
| * processes. This is unrealistic, but safer for the tests since |
| * the exact behaviour can be checked. |
| * |
| * In reality, the following steps either side of the markers *will* |
| * occur and those within the markers *may* occur: |
| * |
| * 1) A System Shutdown is triggered. |
| * 2) The Display Manager receives SIGTERM. |
| * 3) The Display Manager sends SIGTERM to all its clients. |
| * (including the Session Init). |
| * 4) The Session Init sends SIGTERM to all running job |
| * processes. |
| * |
| * --- :XXX: START MARKER :XXX: --- |
| * |
| * 5) The Session Init will attempt to wait for |
| * MAX(kill_timeout) seconds. |
| * 6) The Session Init will send all running job processes |
| * SIGKILL. |
| * 7) The Session Init will wait for all remaining job processes |
| * to end. |
| * 8) The Session Init will exit. |
| * |
| * --- :XXX: END MARKER :XXX: --- |
| * |
| * 9) The Display Manager sends SIGKILL to all its clients. |
| * 10) If still running, the Session Init is killed and exits. |
| * |
| * The problem is that the Session Init cannot know when the |
| * Display Manager will kill *it* so it may be that the Session |
| * Init cannot send SIGKILL to each job process instead relying |
| * on the System Init to clean up. |
| */ |
| TEST_EQ (timed_waitpid (upstart_pid, 1+TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| DELETE_FILE (confdir, "long-running.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("system shutdown: one long-running job which ignores SIGTERM"); |
| |
| CREATE_FILE (confdir, "long-running-term.conf", |
| "kill timeout 1\n" |
| "script\n" |
| " trap '' TERM\n" |
| " sleep 999\n" |
| "end script"); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
| get_initctl (), "long-running-term"); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| job_pid = job_to_pid ("long-running-term"); |
| TEST_NE (job_pid, -1); |
| |
| /* Trigger shutdown */ |
| assert0 (kill (upstart_pid, SIGTERM)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| TEST_EQ (timed_waitpid (upstart_pid, 1+TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| DELETE_FILE (confdir, "long-running-term.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("system shutdown: one job which starts on session-end"); |
| |
| TEST_FILENAME (pid_file); |
| |
| job = NIH_MUST (nih_sprintf (NULL, |
| "console log\n" |
| "start on session-end\n" |
| "\n" |
| "script\n" |
| " echo hello\n" |
| " echo $$ >\"%s\"\n" |
| " exec sleep 999\n" |
| "end script", pid_file)); |
| |
| CREATE_FILE (confdir, "session-end.conf", job); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| /* Trigger shutdown */ |
| assert0 (kill (upstart_pid, SIGTERM)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| TEST_EQ (timed_waitpid (upstart_pid, 1+TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| /* NB: on system shutdown, sessions purposely do not wait for |
| * session-end jobs (they may run, but few guarantees are given). So we |
| * can't expect a session-end.log file here. Remove it if it exists |
| * though. |
| */ |
| logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "session-end.log")); |
| unlink (logfile); |
| nih_free (logfile); |
| logfile = NULL; |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| /* Kill job pid if not already dead; per the above, the job may never |
| * have even started, so none of the following cleanup is fatal. |
| */ |
| file = fopen (pid_file, "r"); |
| if (file) { |
| if (fscanf (file, "%d", &job_pid) == 1) { |
| /* pid may still be running; kill it for completeness. */ |
| kill (job_pid, SIGKILL); |
| } |
| fclose (file); |
| |
| assert0 (unlink (pid_file)); |
| } |
| |
| DELETE_FILE (confdir, "session-end.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("system shutdown: one job which starts on session-end and ignores SIGTERM"); |
| |
| TEST_FILENAME (pid_file); |
| |
| job = NIH_MUST (nih_sprintf (NULL, |
| "console log\n" |
| "start on session-end\n" |
| "kill timeout 1\n" |
| "\n" |
| "script\n" |
| " trap '' TERM\n" |
| " echo hello\n" |
| " echo $$ >\"%s\"\n" |
| " exec sleep 999\n" |
| "end script", pid_file)); |
| |
| CREATE_FILE (confdir, "session-end-term.conf", job); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| /* Trigger shutdown */ |
| assert0 (kill (upstart_pid, SIGTERM)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| TEST_EQ (timed_waitpid (upstart_pid, 1+TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| /* NB: on system shutdown, sessions purposely do not wait for |
| * session-end jobs (they may run, but few guarantees are given). So we |
| * can't expect a session-end.log file here. |
| */ |
| logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "session-end-term.log")); |
| unlink (logfile); |
| nih_free (logfile); |
| logfile = NULL; |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| /* Kill job pid if not already dead; per the above, the job may never |
| * have even started, so none of the following cleanup is fatal. |
| */ |
| file = fopen (pid_file, "r"); |
| if (file) { |
| if (fscanf (file, "%d", &job_pid) == 1) { |
| /* pid may still be running; kill it for completeness. */ |
| kill (job_pid, SIGKILL); |
| } |
| fclose (file); |
| |
| assert0 (unlink (pid_file)); |
| |
| } |
| DELETE_FILE (confdir, "session-end-term.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("system shutdown: 2 jobs " |
| "(1 long-running job which ignores SIGTERM, " |
| "1 which starts on session-end and ignores SIGTERM)"); |
| |
| CREATE_FILE (confdir, "long-running-term.conf", |
| "console log\n" |
| "kill timeout 1\n" |
| "script\n" |
| " trap '' TERM\n" |
| " exec sleep 999\n" |
| "end script"); |
| |
| TEST_FILENAME (pid_file); |
| |
| job = NIH_MUST (nih_sprintf (NULL, |
| "console log\n" |
| "start on session-end\n" |
| "kill timeout 1\n" |
| "\n" |
| "script\n" |
| " trap '' TERM\n" |
| " echo $$ >\"%s\"\n" |
| " exec sleep 999\n" |
| "end script", pid_file)); |
| |
| CREATE_FILE (confdir, "session-end-term.conf", job); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
| get_initctl (), "long-running-term"); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| job_pid = job_to_pid ("long-running-term"); |
| TEST_NE (job_pid, -1); |
| |
| /* Trigger shutdown */ |
| assert0 (kill (upstart_pid, SIGTERM)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| TEST_EQ (timed_waitpid (upstart_pid, 1+TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* the long-running job pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| /* Kill session-end job pid if not already dead; job may never have |
| * even started, so none of the following cleanup is fatal. |
| */ |
| file = fopen (pid_file, "r"); |
| if (file) { |
| if (fscanf (file, "%d", &job_pid) == 1) { |
| /* The session-end job pid may still be running */ |
| kill (job_pid, SIGKILL); |
| } |
| fclose (file); |
| |
| assert0 (unlink (pid_file)); |
| } |
| |
| DELETE_FILE (confdir, "long-running-term.conf"); |
| DELETE_FILE (confdir, "session-end-term.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("session shutdown: no jobs"); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| /* Further required initctl global resets. Shudder. */ |
| user_mode = TRUE; |
| use_dbus = -1; |
| dbus_bus_type = DBUS_BUS_SESSION; |
| dbus_bus_type = -1; |
| |
| upstart = upstart_open (NULL); |
| TEST_NE_P (upstart, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| /* Trigger session shutdown */ |
| assert0 (upstart_end_session_sync (NULL, upstart)); |
| |
| /* no jobs, so Session Init should shutdown "immediately" */ |
| TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("session shutdown: one long-running job"); |
| |
| CREATE_FILE (confdir, "long-running.conf", |
| "exec sleep 999"); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
| get_initctl (), "long-running"); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| job_pid = job_to_pid ("long-running"); |
| TEST_NE (job_pid, -1); |
| |
| upstart = upstart_open (NULL); |
| TEST_NE_P (upstart, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| /* Trigger session shutdown */ |
| assert0 (upstart_end_session_sync (NULL, upstart)); |
| |
| TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| DELETE_FILE (confdir, "long-running.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("session shutdown: one long-running job which starts on startup"); |
| |
| CREATE_FILE (confdir, "startup.conf", |
| "start on startup\n" |
| "exec sleep 999"); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| upstart = upstart_open (NULL); |
| TEST_NE_P (upstart, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| job_pid = job_to_pid ("startup"); |
| TEST_NE (job_pid, -1); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| /* Trigger session shutdown */ |
| assert0 (upstart_end_session_sync (NULL, upstart)); |
| |
| /* Session Init should end very quickly since there will be no |
| * wait phase. |
| */ |
| TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| DELETE_FILE (confdir, "startup.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("session shutdown: one long-running job which ignores SIGTERM"); |
| |
| CREATE_FILE (confdir, "long-running-term.conf", |
| "kill timeout 1\n" |
| "script\n" |
| " trap '' TERM\n" |
| " sleep 999\n" |
| "end script"); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
| get_initctl (), "long-running-term"); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| job_pid = job_to_pid ("long-running-term"); |
| TEST_NE (job_pid, -1); |
| |
| upstart = upstart_open (NULL); |
| TEST_NE_P (upstart, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| /* Trigger session shutdown */ |
| assert0 (upstart_end_session_sync (NULL, upstart)); |
| |
| TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_KILL_PHASE), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| DELETE_FILE (confdir, "long-running-term.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("session shutdown: one job which starts on session-end"); |
| |
| TEST_FILENAME (pid_file); |
| |
| job = NIH_MUST (nih_sprintf (NULL, |
| "console log\n" |
| "start on session-end\n" |
| "kill timeout 1\n" |
| "\n" |
| "script\n" |
| " echo hello\n" |
| " echo $$ >\"%s\"\n" |
| " exec sleep 999\n" |
| "end script", pid_file)); |
| |
| CREATE_FILE (confdir, "session-end.conf", job); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| upstart = upstart_open (NULL); |
| TEST_NE_P (upstart, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| /* Trigger session shutdown */ |
| assert0 (upstart_end_session_sync (NULL, upstart)); |
| |
| TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_TOTAL_WAIT_TIME), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| |
| logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "session-end.log")); |
| |
| file = fopen (logfile, "r"); |
| TEST_NE_P (file, NULL); |
| TEST_FILE_EQ (file, "hello\r\n"); |
| TEST_FILE_END (file); |
| TEST_EQ (fclose (file), 0); |
| assert0 (unlink (logfile)); |
| |
| file = fopen (pid_file, "r"); |
| TEST_NE_P (file, NULL); |
| TEST_EQ (fscanf (file, "%d", &job_pid), 1); |
| fclose (file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| assert0 (unlink (pid_file)); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| DELETE_FILE (confdir, "session-end.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("session shutdown: one job which starts on session-end"); |
| |
| TEST_FILENAME (pid_file); |
| |
| job = NIH_MUST (nih_sprintf (NULL, |
| "console log\n" |
| "start on session-end\n" |
| "kill timeout 1\n" |
| "\n" |
| "script\n" |
| " trap '' TERM\n" |
| " echo hello\n" |
| " echo $$ >\"%s\"\n" |
| " exec sleep 999\n" |
| "end script", pid_file)); |
| |
| CREATE_FILE (confdir, "session-end-term.conf", job); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| upstart = upstart_open (NULL); |
| TEST_NE_P (upstart, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| /* Trigger session shutdown */ |
| assert0 (upstart_end_session_sync (NULL, upstart)); |
| |
| TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_TOTAL_WAIT_TIME), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| |
| logfile = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "session-end-term.log")); |
| |
| file = fopen (logfile, "r"); |
| TEST_NE_P (file, NULL); |
| TEST_FILE_EQ (file, "hello\r\n"); |
| TEST_FILE_END (file); |
| TEST_EQ (fclose (file), 0); |
| assert0 (unlink (logfile)); |
| |
| file = fopen (pid_file, "r"); |
| TEST_NE_P (file, NULL); |
| TEST_EQ (fscanf (file, "%d", &job_pid), 1); |
| fclose (file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| assert0 (unlink (pid_file)); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| DELETE_FILE (confdir, "session-end-term.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("session shutdown: 2 jobs " |
| "(1 long-running job which ignores SIGTERM, " |
| "1 which starts on session-end and ignores SIGTERM)"); |
| |
| CREATE_FILE (confdir, "long-running-term.conf", |
| "kill timeout 1\n" |
| "script\n" |
| " trap '' TERM\n" |
| " sleep 999\n" |
| "end script"); |
| |
| TEST_FILENAME (pid_file); |
| |
| job = NIH_MUST (nih_sprintf (NULL, |
| "console log\n" |
| "start on session-end\n" |
| "kill timeout 1\n" |
| "\n" |
| "script\n" |
| " trap '' TERM\n" |
| " echo $$ >\"%s\"\n" |
| " sleep 999\n" |
| "end script", pid_file)); |
| |
| CREATE_FILE (confdir, "session-end-term.conf", job); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
| get_initctl (), "long-running-term"); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| job_pid = job_to_pid ("long-running-term"); |
| TEST_NE (job_pid, -1); |
| |
| upstart = upstart_open (NULL); |
| TEST_NE_P (upstart, NULL); |
| |
| /* Should be running */ |
| assert0 (kill (upstart_pid, 0)); |
| |
| /* Force reset */ |
| test_user_mode = FALSE; |
| |
| /* Trigger session shutdown */ |
| assert0 (upstart_end_session_sync (NULL, upstart)); |
| |
| TEST_EQ (timed_waitpid (upstart_pid, TEST_QUIESCE_TOTAL_WAIT_TIME), upstart_pid); |
| |
| /* Should not now be running */ |
| TEST_EQ (kill (upstart_pid, 0), -1); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| sessiondir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| file = fopen (pid_file, "r"); |
| TEST_NE_P (file, NULL); |
| TEST_EQ (fscanf (file, "%d", &job_pid), 1); |
| fclose (file); |
| |
| reap_quiesced_child (job_pid); |
| |
| /* pid should no longer exist */ |
| TEST_EQ (kill (job_pid, 0), -1); |
| TEST_EQ (errno, ESRCH); |
| |
| assert0 (unlink (pid_file)); |
| |
| DELETE_FILE (confdir, "long-running-term.conf"); |
| DELETE_FILE (confdir, "session-end-term.conf"); |
| |
| /*******************************************************************/ |
| assert0 (unsetenv ("UPSTART_CONFDIR")); |
| assert0 (unsetenv ("UPSTART_LOGDIR")); |
| |
| TEST_EQ (rmdir (logdir), 0); |
| TEST_EQ (rmdir (confdir), 0); |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions", sessiondir)); |
| TEST_EQ (rmdir (session_file), 0); |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart", sessiondir)); |
| TEST_EQ (rmdir (session_file), 0); |
| |
| /*******************************************************************/ |
| } |
| |
| void |
| test_umask (void) |
| { |
| char confdir[PATH_MAX]; |
| char dirname[PATH_MAX]; |
| char logdir[PATH_MAX]; |
| nih_local char *path = NULL; |
| nih_local char *cmd = NULL; |
| pid_t upstart_pid = 0; |
| nih_local char *out_file = NULL; |
| nih_local char *contents = NULL; |
| nih_local char *original_runtime = NULL; |
| mode_t job_umask; |
| nih_local char *_job_umask_str = NULL; |
| nih_local char *job_umask_str = NULL; |
| size_t length; |
| int ret; |
| mode_t original_umask; |
| mode_t test_umask = 0077; |
| mode_t default_umask = 022; |
| char **output; |
| size_t lines; |
| |
| original_runtime = nih_strdup (NULL, getenv ("XDG_RUNTIME_DIR")); |
| TEST_NE_P (original_runtime, NULL); |
| |
| TEST_FILENAME (dirname); |
| TEST_EQ (mkdir (dirname, 0755), 0); |
| TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); |
| |
| TEST_FILENAME (confdir); |
| TEST_EQ (mkdir (confdir, 0755), 0); |
| TEST_EQ (setenv ("UPSTART_CONFDIR", confdir, 1), 0); |
| |
| TEST_FILENAME (logdir); |
| TEST_EQ (mkdir (logdir, 0755), 0); |
| |
| original_umask = umask (test_umask); |
| |
| TEST_GROUP ("Session Init umask value"); |
| |
| /**********************************************************************/ |
| TEST_FEATURE ("ensure Session Init inherits umask by default"); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "umask.out")); |
| |
| /* This is a script because umask is a shell built-in. This is a task |
| * so 'initctl start <job>' knows exactly when it's done. |
| */ |
| contents = NIH_MUST (nih_sprintf (NULL, |
| "task\n" |
| "script\n" |
| "umask >\"%s\"\n" |
| "end script\n", out_file)); |
| CREATE_FILE (confdir, "umask.conf", contents); |
| |
| start_upstart_common (&upstart_pid, TRUE, TRUE, confdir, logdir, NULL); |
| |
| cmd = nih_sprintf (NULL, "%s start umask 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| nih_free (output); |
| |
| _job_umask_str = nih_file_read (NULL, out_file, &length); |
| TEST_NE_P (_job_umask_str, NULL); |
| |
| job_umask_str = nih_strndup (NULL, _job_umask_str, length); |
| TEST_NE_P (job_umask_str, NULL); |
| |
| ret = sscanf (job_umask_str, "%o", (unsigned int *)&job_umask); |
| TEST_EQ (ret, 1); |
| TEST_EQ (job_umask, test_umask); |
| |
| DELETE_FILE (confdir, "umask.conf"); |
| assert0 (unlink (out_file)); |
| nih_free (out_file); |
| out_file = NULL; |
| |
| STOP_UPSTART (upstart_pid); |
| |
| nih_free(_job_umask_str); |
| _job_umask_str = NULL; |
| nih_free(job_umask_str); |
| job_umask_str = NULL; |
| |
| /**********************************************************************/ |
| TEST_FEATURE ("ensure Session Init defaults umask with '--no-inherit-env'"); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "umask.out")); |
| |
| /* This is a script because umask is a shell built-in. This is a task |
| * so 'initctl start <job>' knows exactly when it's done. |
| */ |
| contents = NIH_MUST (nih_sprintf (NULL, |
| "task\n" |
| "script\n" |
| "umask >\"%s\"\n" |
| "end script", out_file)); |
| CREATE_FILE (confdir, "umask.conf", contents); |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| cmd = nih_sprintf (NULL, "%s start umask 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| nih_free (output); |
| |
| _job_umask_str = nih_file_read (NULL, out_file, &length); |
| TEST_NE_P (_job_umask_str, NULL); |
| |
| job_umask_str = nih_strndup (NULL, _job_umask_str, length); |
| TEST_NE_P (job_umask_str, NULL); |
| |
| ret = sscanf (job_umask_str, "%o", (unsigned int *)&job_umask); |
| TEST_EQ (ret, 1); |
| TEST_EQ (job_umask, default_umask); |
| |
| DELETE_FILE (confdir, "umask.conf"); |
| assert0 (unlink (out_file)); |
| |
| STOP_UPSTART (upstart_pid); |
| |
| /**********************************************************************/ |
| |
| /* Restore */ |
| (void)umask (original_umask); |
| TEST_EQ (setenv ("XDG_RUNTIME_DIR", original_runtime, 1), 0); |
| |
| assert0 (rmdir (confdir)); |
| assert0 (rmdir (logdir)); |
| |
| path = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions", dirname)); |
| cmd = NIH_MUST (nih_sprintf (NULL, "rm -f %s/*.session 2>/dev/null", path)); |
| assert0 (system (cmd)); |
| assert0 (rmdir (path)); |
| path = NIH_MUST (nih_sprintf (NULL, "%s/upstart", dirname)); |
| assert0 (rmdir (path)); |
| assert0 (rmdir (dirname)); |
| } |
| |
| void |
| test_show_config (void) |
| { |
| char dirname[PATH_MAX]; |
| nih_local char *cmd = NULL; |
| pid_t upstart_pid = 0; |
| pid_t dbus_pid = 0; |
| char **output; |
| size_t lines; |
| char expected_output[] = "foo"; |
| |
| TEST_GROUP ("show_config"); |
| |
| TEST_FILENAME (dirname); |
| TEST_EQ (mkdir (dirname, 0755), 0); |
| |
| /* Use the "secret" interface */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", dirname, 1), 0); |
| |
| TEST_DBUS (dbus_pid); |
| START_UPSTART (upstart_pid, FALSE); |
| |
| TEST_FEATURE ("no emits, no start on, no stop on"); |
| CREATE_FILE (dirname, "foo.conf", |
| "author \"foo\"\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("1 emits, no start on, no stop on"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "author \"foo\"\n" |
| "emits \"thing\"\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits thing"); |
| TEST_EQ (lines, 2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits thing"); |
| TEST_EQ (lines, 2); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("2 emits, no start on, no stop on"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "author \"foo\"\n" |
| "emits \"thing\"\n" |
| "emits \"thong\"\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits thing"); |
| TEST_EQ_STR (output[2], " emits thong"); |
| TEST_EQ (lines, 3); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits thing"); |
| TEST_EQ_STR (output[2], " emits thong"); |
| TEST_EQ (lines, 3); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("no emits, start on, no stop on"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "author \"foo\"\n" |
| "start on (A and B)\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " start on (A and B)"); |
| TEST_EQ (lines, 2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " start on A (job:, env:)"); |
| TEST_EQ_STR (output[2], " start on B (job:, env:)"); |
| TEST_EQ (lines, 3); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("1 emits, start on, no stop on"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "author \"foo\"\n" |
| "emits \"bong\"\n" |
| "start on (A and B)\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " start on (A and B)"); |
| TEST_EQ (lines, 3); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " start on A (job:, env:)"); |
| TEST_EQ_STR (output[3], " start on B (job:, env:)"); |
| TEST_EQ (lines, 4); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("2 emits, start on, no stop on"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "emits \"bong\"\n" |
| "author \"foo\"\n" |
| "start on (A and B)\n" |
| "emits \"stime\"\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits stime"); |
| TEST_EQ_STR (output[3], " start on (A and B)"); |
| TEST_EQ (lines, 4); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits stime"); |
| TEST_EQ_STR (output[3], " start on A (job:, env:)"); |
| TEST_EQ_STR (output[4], " start on B (job:, env:)"); |
| TEST_EQ (lines, 5); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("no emits, no start on, stop on"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "author \"foo\"\n" |
| "stop on (A or B)\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " stop on (A or B)"); |
| TEST_EQ (lines, 2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " stop on A (job:, env:)"); |
| TEST_EQ_STR (output[2], " stop on B (job:, env:)"); |
| TEST_EQ (lines, 3); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("1 emits, no start on, stop on"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "author \"foo\"\n" |
| "emits \"bong\"\n" |
| "stop on (A or B)\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " stop on (A or B)"); |
| TEST_EQ (lines, 3); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " stop on A (job:, env:)"); |
| TEST_EQ_STR (output[3], " stop on B (job:, env:)"); |
| TEST_EQ (lines, 4); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("2 emits, no start on, stop on"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "emits \"bong\"\n" |
| "author \"foo\"\n" |
| "stop on (A or B)\n" |
| "emits \"stime\"\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits stime"); |
| TEST_EQ_STR (output[3], " stop on (A or B)"); |
| TEST_EQ (lines, 4); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits stime"); |
| TEST_EQ_STR (output[3], " stop on A (job:, env:)"); |
| TEST_EQ_STR (output[4], " stop on B (job:, env:)"); |
| TEST_EQ (lines, 5); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("2 emits, start on with only initial JOB, stop on with JOB at end of env"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "emits \"bong\"\n" |
| "author \"foo\"\n" |
| "stop on (A or stopping c=d e=f g=h JOB=\"bang\")\n" |
| "emits \"stime\"\n" |
| "start on (starting JOB=\"boo\" or B x=y)\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits stime"); |
| TEST_EQ_STR (output[3], " start on (starting JOB=boo or B x=y)"); |
| TEST_EQ_STR (output[4], " stop on (A or stopping c=d e=f g=h JOB=bang)"); |
| TEST_EQ (lines, 5); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits stime"); |
| TEST_EQ_STR (output[3], " start on starting (job: boo, env:)"); |
| TEST_EQ_STR (output[4], " start on B (job:, env: x=y)"); |
| TEST_EQ_STR (output[5], " stop on A (job:, env:)"); |
| TEST_EQ_STR (output[6], " stop on stopping (job: bang, env: c=d e=f g=h)"); |
| TEST_EQ (lines, 7); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("2 emits, start on with initial JOB+env, stop on with JOB at end of env"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "emits \"bong\"\n" |
| "author \"foo\"\n" |
| "stop on (A or stopping c=d e=f g=h JOB=\"bang\")\n" |
| "emits \"stime\"\n" |
| "start on (starting JOB=\"boo\" P=Q c=sea or B x=y)\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits stime"); |
| TEST_EQ_STR (output[3], " start on (starting JOB=boo P=Q c=sea or B x=y)"); |
| TEST_EQ_STR (output[4], " stop on (A or stopping c=d e=f g=h JOB=bang)"); |
| TEST_EQ (lines, 5); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits stime"); |
| TEST_EQ_STR (output[3], " start on starting (job: boo, env: P=Q c=sea)"); |
| TEST_EQ_STR (output[4], " start on B (job:, env: x=y)"); |
| TEST_EQ_STR (output[5], " stop on A (job:, env:)"); |
| TEST_EQ_STR (output[6], " stop on stopping (job: bang, env: c=d e=f g=h)"); |
| TEST_EQ (lines, 7); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("3 emits, start on (with env), stop on (with env)"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "emits \"bong\"\n" |
| "stop on starting D and (stopping E or F hello=world)\n" |
| "author \"foo\"\n" |
| "emits \"bar\"\n" |
| "emits \"stime\"\n" |
| "start on A and (B FOO=BAR or starting C x=y)\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits bar"); |
| TEST_EQ_STR (output[3], " emits stime"); |
| /* note the extra brackets! */ |
| TEST_EQ_STR (output[4], " start on (A and (B FOO=BAR or starting C x=y))"); |
| /* note the extra brackets! */ |
| TEST_EQ_STR (output[5], " stop on (starting D and (stopping E or F hello=world))"); |
| TEST_EQ (lines, 6); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits bar"); |
| TEST_EQ_STR (output[3], " emits stime"); |
| TEST_EQ_STR (output[4], " start on A (job:, env:)"); |
| TEST_EQ_STR (output[5], " start on B (job:, env: FOO=BAR)"); |
| TEST_EQ_STR (output[6], " start on starting (job: C, env: x=y)"); |
| TEST_EQ_STR (output[7], " stop on starting (job: D, env:)"); |
| TEST_EQ_STR (output[8], " stop on stopping (job: E, env:)"); |
| TEST_EQ_STR (output[9], " stop on F (job:, env: hello=world)"); |
| TEST_EQ (lines, 10); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("3 emits, complex start on (with env), complex stop on (with env)"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "emits \"bong\"\n" |
| "stop on runlevel [!2345] colour=blue or starting rocket\n" |
| "author \"foo\"\n" |
| "emits \"bar\"\n" |
| "emits \"stime\"\n" |
| "start on (starting mountall or (runlevel [016] and " |
| "(stopped gdm or stopped kdm or stopped xdm A=B or stopping lxdm)))\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits bar"); |
| TEST_EQ_STR (output[3], " emits stime"); |
| /* note the extra brackets! */ |
| TEST_EQ_STR (output[4], " start on (starting mountall or (runlevel [016] and " |
| "(((stopped gdm or stopped kdm) or stopped xdm A=B) or stopping lxdm)))"); |
| /* note the extra brackets! */ |
| TEST_EQ_STR (output[5], " stop on (runlevel [!2345] colour=blue or starting rocket)"); |
| TEST_EQ (lines, 6); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s show-config -e foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], expected_output); |
| TEST_EQ_STR (output[1], " emits bong"); |
| TEST_EQ_STR (output[2], " emits bar"); |
| TEST_EQ_STR (output[3], " emits stime"); |
| TEST_EQ_STR (output[4], " start on starting (job: mountall, env:)"); |
| TEST_EQ_STR (output[5], " start on runlevel (job:, env: [016])"); |
| TEST_EQ_STR (output[6], " start on stopped (job: gdm, env:)"); |
| TEST_EQ_STR (output[7], " start on stopped (job: kdm, env:)"); |
| TEST_EQ_STR (output[8], " start on stopped (job: xdm, env: A=B)"); |
| TEST_EQ_STR (output[9], " start on stopping (job: lxdm, env:)"); |
| TEST_EQ_STR (output[10], " stop on runlevel (job:, env: [!2345] colour=blue)"); |
| TEST_EQ_STR (output[11], " stop on starting (job: rocket, env:)"); |
| TEST_EQ (lines, 12); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| STOP_UPSTART (upstart_pid); |
| TEST_EQ (unsetenv ("UPSTART_CONFDIR"), 0); |
| TEST_DBUS_END (dbus_pid); |
| TEST_EQ (rmdir (dirname), 0); |
| } |
| |
| void |
| test_check_config (void) |
| { |
| char dirname[PATH_MAX]; |
| nih_local char *cmd = NULL; |
| pid_t upstart_pid = 0; |
| pid_t dbus_pid = 0; |
| char **output; |
| size_t lines; |
| |
| TEST_GROUP ("check_config"); |
| |
| TEST_FILENAME (dirname); |
| TEST_EQ (mkdir (dirname, 0755), 0); |
| |
| /* Use the "secret" interface */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", dirname, 1), 0); |
| |
| TEST_DBUS (dbus_pid); |
| START_UPSTART (upstart_pid, FALSE); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("no unreachable jobs/events (satisfied by job or event)"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "start on (starting bar or wibble)"); |
| |
| CREATE_FILE (dirname, "bar.conf", |
| "task\n" |
| "exec true"); |
| |
| CREATE_FILE (dirname, "baz.conf", |
| "emits wibble"); |
| |
| cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| DELETE_FILE (dirname, "bar.conf"); |
| DELETE_FILE (dirname, "baz.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("no unreachable jobs/events (satisfied by job)"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "start on (starting bar or wibble)"); |
| |
| CREATE_FILE (dirname, "bar.conf", |
| "task\n" |
| "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| DELETE_FILE (dirname, "bar.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("no unreachable jobs/events (satisfied by event)"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "start on (starting bar or wibble)"); |
| |
| CREATE_FILE (dirname, "baz.conf", |
| "emits wibble"); |
| |
| cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| DELETE_FILE (dirname, "baz.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("unreachable event"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "start on (starting bar and wibble)"); |
| |
| CREATE_FILE (dirname, "bar.conf", |
| "task\n" |
| "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], "foo"); |
| TEST_EQ_STR (output[1], " start on: unknown event wibble"); |
| TEST_EQ (lines, 2); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| DELETE_FILE (dirname, "bar.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("unreachable job"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "start on (starting bar and wibble)"); |
| |
| CREATE_FILE (dirname, "baz.conf", |
| "emits wibble"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], "foo"); |
| TEST_EQ_STR (output[1], " start on: unknown job bar"); |
| TEST_EQ (lines, 2); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| DELETE_FILE (dirname, "baz.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("unreachable event with forced ignore"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "start on (starting bar and wibble)"); |
| |
| CREATE_FILE (dirname, "bar.conf", |
| "task\n" |
| "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config --ignore-events=wibble 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| DELETE_FILE (dirname, "bar.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("unreachable events with forced ignores"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "start on (fred and wilma)"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config --ignore-events=wilma,foo,fred 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("satisfiable complex start on"); |
| |
| /* Yes folks, it's the classic */ |
| CREATE_FILE (dirname, "plymouth.conf", |
| "start on (starting mountall\n" |
| " or (runlevel [016]\n" |
| " and (stopped gdm\n" |
| " or stopped kdm\n" |
| " or stopped xdm\n" |
| " or stopped lxdm)))"); |
| |
| CREATE_FILE (dirname, "mountall.conf", "exec true"); |
| CREATE_FILE (dirname, "gdm.conf" , "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| DELETE_FILE (dirname, "plymouth.conf"); |
| DELETE_FILE (dirname, "mountall.conf"); |
| DELETE_FILE (dirname, "gdm.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("unsatisfiable complex start on"); |
| |
| CREATE_FILE (dirname, "plymouth.conf", |
| "start on (starting mountall\n" |
| " or (runlevel [016]\n" |
| " and (stopped gdm\n" |
| " or stopped kdm\n" |
| " or stopped xdm\n" |
| " or stopped lxdm)))"); |
| |
| CREATE_FILE (dirname, "mountall.conf", "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| TEST_EQ_STR (output[0], "plymouth"); |
| TEST_EQ_STR (output[1], " start on: unknown job lxdm"); |
| TEST_EQ_STR (output[2], " start on: unknown job xdm"); |
| TEST_EQ_STR (output[3], " start on: unknown job kdm"); |
| TEST_EQ_STR (output[4], " start on: unknown job gdm"); |
| TEST_EQ (lines, 5); |
| |
| DELETE_FILE (dirname, "plymouth.conf"); |
| DELETE_FILE (dirname, "mountall.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("satisfiable complex stop on"); |
| |
| /* Yes folks, it's the classic */ |
| CREATE_FILE (dirname, "plymouth.conf", |
| "stop on (starting mountall\n" |
| " or (runlevel [016]\n" |
| " and (stopped gdm\n" |
| " or stopped kdm\n" |
| " or stopped xdm\n" |
| " or stopped lxdm)))"); |
| |
| CREATE_FILE (dirname, "mountall.conf", "exec true"); |
| CREATE_FILE (dirname, "gdm.conf" , "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| DELETE_FILE (dirname, "plymouth.conf"); |
| DELETE_FILE (dirname, "mountall.conf"); |
| DELETE_FILE (dirname, "gdm.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("unsatisfiable complex stop on"); |
| |
| CREATE_FILE (dirname, "plymouth.conf", |
| "stop on (starting mountall\n" |
| " or (runlevel [016]\n" |
| " and (stopped gdm\n" |
| " or stopped kdm\n" |
| " or stopped xdm\n" |
| " or stopped lxdm)))"); |
| |
| CREATE_FILE (dirname, "mountall.conf", "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| TEST_EQ_STR (output[0], "plymouth"); |
| TEST_EQ_STR (output[1], " stop on: unknown job lxdm"); |
| TEST_EQ_STR (output[2], " stop on: unknown job xdm"); |
| TEST_EQ_STR (output[3], " stop on: unknown job kdm"); |
| TEST_EQ_STR (output[4], " stop on: unknown job gdm"); |
| TEST_EQ (lines, 5); |
| |
| DELETE_FILE (dirname, "plymouth.conf"); |
| DELETE_FILE (dirname, "mountall.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("unsatisfiable complex stop on, satisfiable complex start on"); |
| |
| CREATE_FILE (dirname, "plymouth.conf", |
| "stop on (starting mountall\n" |
| " or (runlevel [016]\n" |
| " and (stopped gdm\n" |
| " or stopped kdm\n" |
| " or stopped xdm\n" |
| " or stopped lxdm)))\n" |
| "start on (stopping portmap\n" |
| " or (runlevel [06] or starting beano))\n"); |
| |
| CREATE_FILE (dirname, "mountall.conf", "exec true"); |
| CREATE_FILE (dirname, "portmap.conf", "exec true"); |
| CREATE_FILE (dirname, "beano.conf", "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config --ignore-events=runlevel 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| TEST_EQ_STR (output[0], "plymouth"); |
| TEST_EQ_STR (output[1], " stop on: unknown job lxdm"); |
| TEST_EQ_STR (output[2], " stop on: unknown job xdm"); |
| TEST_EQ_STR (output[3], " stop on: unknown job kdm"); |
| TEST_EQ_STR (output[4], " stop on: unknown job gdm"); |
| TEST_EQ (lines, 5); |
| |
| DELETE_FILE (dirname, "plymouth.conf"); |
| DELETE_FILE (dirname, "mountall.conf"); |
| DELETE_FILE (dirname, "portmap.conf"); |
| DELETE_FILE (dirname, "beano.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("satisfiable complex start on, unsatisfiable complex stop on"); |
| |
| CREATE_FILE (dirname, "plymouth.conf", |
| "start on (starting mountall\n" |
| " or (hello\n" |
| " and (stopped gdm\n" |
| " or stopped kdm\n" |
| " or stopped xdm\n" |
| " or stopped lxdm)))\n" |
| "stop on (stopping portmap\n" |
| " or (wibble or starting beano))\n"); |
| |
| CREATE_FILE (dirname, "mountall.conf", "exec true"); |
| CREATE_FILE (dirname, "portmap.conf", |
| "exec true\n" |
| "emits hello"); |
| CREATE_FILE (dirname, "gdm.conf", "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config >&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| TEST_EQ_STR (output[0], "plymouth"); |
| TEST_EQ_STR (output[1], " stop on: unknown job beano"); |
| TEST_EQ_STR (output[2], " stop on: unknown event wibble"); |
| TEST_EQ (lines, 3); |
| |
| DELETE_FILE (dirname, "plymouth.conf"); |
| DELETE_FILE (dirname, "mountall.conf"); |
| DELETE_FILE (dirname, "portmap.conf"); |
| DELETE_FILE (dirname, "gdm.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("unsatisfiable complex start on, unsatisfiable complex stop on"); |
| |
| CREATE_FILE (dirname, "plymouth.conf", |
| "start on (starting mountall\n" |
| " or (hello\n" |
| " and (stopped gdm\n" |
| " or stopped kdm\n" |
| " or stopped xdm\n" |
| " or stopped lxdm)))\n" |
| "stop on (stopping portmap\n" |
| " or (wibble or starting beano))\n"); |
| |
| CREATE_FILE (dirname, "mountall.conf", "exec true"); |
| CREATE_FILE (dirname, "portmap.conf", "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| TEST_EQ_STR (output[0], "plymouth"); |
| TEST_EQ_STR (output[1], " start on: unknown job lxdm"); |
| TEST_EQ_STR (output[2], " start on: unknown job xdm"); |
| TEST_EQ_STR (output[3], " start on: unknown job kdm"); |
| TEST_EQ_STR (output[4], " start on: unknown job gdm"); |
| TEST_EQ_STR (output[5], " start on: unknown event hello"); |
| TEST_EQ_STR (output[6], " stop on: unknown job beano"); |
| TEST_EQ_STR (output[7], " stop on: unknown event wibble"); |
| TEST_EQ (lines, 8); |
| |
| DELETE_FILE (dirname, "plymouth.conf"); |
| DELETE_FILE (dirname, "mountall.conf"); |
| DELETE_FILE (dirname, "portmap.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("satisfiable complex start on, satisfiable complex stop on"); |
| |
| CREATE_FILE (dirname, "plymouth.conf", |
| "start on (starting mountall\n" |
| " or (hello\n" |
| " and (stopped gdm\n" |
| " or (stopped kdm\n" |
| " or (stopped xdm\n" |
| " or stopped lxdm)))))\n" |
| "stop on (stopping portmap\n" |
| " or (wibble or starting beano))\n"); |
| |
| CREATE_FILE (dirname, "mountall.conf", "exec true\n"); |
| CREATE_FILE (dirname, "portmap.conf", |
| "exec true\n" |
| "emits hello"); |
| CREATE_FILE (dirname, "lxdm.conf", "exec true"); |
| CREATE_FILE (dirname, "wibble.conf", "emits wibble"); |
| CREATE_FILE (dirname, "beano.conf", "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| TEST_EQ (lines, 0); |
| |
| DELETE_FILE (dirname, "plymouth.conf"); |
| DELETE_FILE (dirname, "mountall.conf"); |
| DELETE_FILE (dirname, "portmap.conf"); |
| DELETE_FILE (dirname, "lxdm.conf"); |
| DELETE_FILE (dirname, "beano.conf"); |
| DELETE_FILE (dirname, "wibble.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ( |
| "satisfiable complex start on, satisfiable complex stop on with warnings"); |
| |
| CREATE_FILE (dirname, "plymouth.conf", |
| "start on (starting mountall\n" |
| " or (hello\n" |
| " and (stopped gdm\n" |
| " or (stopped kdm\n" |
| " or (stopped xdm\n" |
| " or stopped lxdm)))))\n" |
| "stop on (stopping portmap\n" |
| " or (wibble or starting beano))\n"); |
| |
| CREATE_FILE (dirname, "mountall.conf", "exec true\n"); |
| CREATE_FILE (dirname, "portmap.conf", |
| "exec true\n" |
| "emits hello"); |
| CREATE_FILE (dirname, "lxdm.conf", "exec true"); |
| CREATE_FILE (dirname, "wibble.conf", "emits wibble"); |
| CREATE_FILE (dirname, "beano.conf", "exec true"); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s check-config --warn 2>&1", |
| get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| TEST_EQ_STR (output[0], "plymouth"); |
| TEST_EQ_STR (output[1], " start on: unknown job xdm"); |
| TEST_EQ_STR (output[2], " start on: unknown job kdm"); |
| TEST_EQ_STR (output[3], " start on: unknown job gdm"); |
| TEST_EQ (lines, 4); |
| |
| DELETE_FILE (dirname, "plymouth.conf"); |
| DELETE_FILE (dirname, "mountall.conf"); |
| DELETE_FILE (dirname, "portmap.conf"); |
| DELETE_FILE (dirname, "lxdm.conf"); |
| DELETE_FILE (dirname, "beano.conf"); |
| DELETE_FILE (dirname, "wibble.conf"); |
| |
| /*******************************************************************/ |
| |
| STOP_UPSTART (upstart_pid); |
| TEST_EQ (unsetenv ("UPSTART_CONFDIR"), 0); |
| TEST_DBUS_END (dbus_pid); |
| TEST_EQ (rmdir (dirname), 0); |
| } |
| |
| void |
| test_notify_disk_writeable (void) |
| { |
| char confdir_name[PATH_MAX]; |
| char logdir_name[PATH_MAX]; |
| nih_local char *logfile_name = NULL; |
| pid_t upstart_pid = 0; |
| pid_t dbus_pid; |
| nih_local char *cmd = NULL; |
| char **output; |
| size_t lines; |
| struct stat statbuf; |
| mode_t old_perms; |
| FILE *file; |
| |
| TEST_FILENAME (confdir_name); |
| TEST_EQ (mkdir (confdir_name, 0755), 0); |
| |
| TEST_FILENAME (logdir_name); |
| TEST_EQ (mkdir (logdir_name, 0755), 0); |
| |
| TEST_EQ (stat (logdir_name, &statbuf), 0); |
| old_perms = statbuf.st_mode; |
| |
| /* Make inaccessible */ |
| TEST_EQ (chmod (logdir_name, 0x0), 0); |
| |
| /* Use the "secret" interfaces */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", confdir_name, 1), 0); |
| TEST_EQ (setenv ("UPSTART_LOGDIR", logdir_name, 1), 0); |
| |
| TEST_FUNCTION ("notify-disk-writeable"); |
| |
| TEST_FEATURE ("with job ending before log disk writeable"); |
| |
| CREATE_FILE (confdir_name, "foo.conf", |
| "console log\n" |
| "exec echo hello world\n"); |
| |
| logfile_name = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir_name, |
| "foo.log")); |
| |
| TEST_DBUS (dbus_pid); |
| START_UPSTART (upstart_pid, FALSE); |
| |
| cmd = nih_sprintf (NULL, "%s start %s 2>&1", |
| get_initctl (), "foo"); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| |
| /* Give Upstart a chance to respond */ |
| { |
| int i = 0; |
| int max = 50; |
| int ret; |
| |
| for (i=0; i < max; ++i) { |
| nih_free (output); |
| cmd = nih_sprintf (NULL, "%s status %s 2>&1", |
| get_initctl (), "foo"); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| |
| ret = fnmatch ("foo stop/waiting", output[0], 0); |
| |
| if (! ret) { |
| break; |
| } |
| |
| msleep (100); |
| } |
| } |
| |
| TEST_EQ (fnmatch ("foo stop/waiting", output[0], 0), 0); |
| |
| /* Ensure no log file written */ |
| TEST_LT (stat (logfile_name, &statbuf), 0); |
| |
| /* Restore access */ |
| TEST_EQ (chmod (logdir_name, old_perms), 0); |
| |
| /* Ensure again that no log file written */ |
| TEST_LT (stat (logfile_name, &statbuf), 0); |
| |
| /* Must not be run as root */ |
| TEST_TRUE (getuid ()); |
| |
| cmd = nih_sprintf (NULL, "%s notify-disk-writeable 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| /* Ensure file written now */ |
| TEST_EQ (stat (logfile_name, &statbuf), 0); |
| |
| file = fopen (logfile_name, "r"); |
| TEST_NE_P (file, NULL); |
| TEST_FILE_EQ (file, "hello world\r\n"); |
| TEST_FILE_END (file); |
| TEST_EQ (fclose (file), 0); |
| |
| STOP_UPSTART (upstart_pid); |
| TEST_EQ (unsetenv ("UPSTART_CONFDIR"), 0); |
| TEST_EQ (unsetenv ("UPSTART_LOGDIR"), 0); |
| TEST_DBUS_END (dbus_pid); |
| |
| DELETE_FILE (confdir_name, "foo.conf"); |
| DELETE_FILE (logdir_name, "foo.log"); |
| |
| TEST_EQ (rmdir (confdir_name), 0); |
| TEST_EQ (rmdir (logdir_name), 0); |
| } |
| |
| |
| void |
| test_list_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| DBusMessage * reply = NULL; |
| const char * str_value; |
| const char * interface; |
| const char * property; |
| DBusMessageIter iter; |
| DBusMessageIter subiter; |
| DBusMessageIter arrayiter; |
| DBusMessageIter dictiter; |
| DBusMessageIter prociter; |
| DBusMessageIter structiter; |
| int32_t int32_value; |
| NihCommand command; |
| char * args[1]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("list_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that the list action makes the GetAllJobs method call |
| * to obtain a list of paths, then for each job calls the |
| * GetAllInstances method call to obtain a list of the instances. |
| * If there are instances, the job name and instance properties are |
| * requested and output; if there are not instances, only the |
| * job name is requested and output. |
| */ |
| TEST_FEATURE ("with valid reply"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetAllJobs method call on the |
| * manager object, reply with a list of interesting |
| * paths. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetAllJobs")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| DBUS_TYPE_OBJECT_PATH_AS_STRING, |
| &arrayiter); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/frodo"; |
| dbus_message_iter_append_basic (&arrayiter, |
| DBUS_TYPE_OBJECT_PATH, |
| &str_value); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/bilbo"; |
| dbus_message_iter_append_basic (&arrayiter, |
| DBUS_TYPE_OBJECT_PATH, |
| &str_value); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/drogo"; |
| dbus_message_iter_append_basic (&arrayiter, |
| DBUS_TYPE_OBJECT_PATH, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAllInstances method call on the |
| * first job object, reply with an empty list. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetAllInstances")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/frodo"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| DBUS_TYPE_OBJECT_PATH_AS_STRING, |
| &arrayiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the name of the |
| * first job, reply with the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/frodo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "frodo"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAllInstances method call on the |
| * second job object, reply with a single instance. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetAllInstances")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/bilbo"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| DBUS_TYPE_OBJECT_PATH_AS_STRING, |
| &arrayiter); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/bilbo/_"; |
| dbus_message_iter_append_basic (&arrayiter, |
| DBUS_TYPE_OBJECT_PATH, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the name of the |
| * second job, reply with the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/bilbo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "bilbo"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/bilbo/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAllInstances method call on the |
| * third job object, reply with a couple of |
| * named instances |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetAllInstances")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/drogo"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| DBUS_TYPE_OBJECT_PATH_AS_STRING, |
| &arrayiter); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/drogo/foo"; |
| dbus_message_iter_append_basic (&arrayiter, |
| DBUS_TYPE_OBJECT_PATH, |
| &str_value); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/drogo/bar"; |
| dbus_message_iter_append_basic (&arrayiter, |
| DBUS_TYPE_OBJECT_PATH, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the name of the |
| * third job, reply with the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/drogo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "drogo"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the first of its |
| * instances, reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/drogo/foo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "foo"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "pre-stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 6312; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "pre-stop"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 8609; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the name of the |
| * third job, reply with the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/drogo"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "drogo"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the second of its |
| * instances, reply with its properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/drogo/bar"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "bar"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "post-stop"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "post-stop"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 7465; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = list_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| /* May have had some output */ |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "frodo stop/waiting\n"); |
| TEST_FILE_EQ (output, "bilbo start/running, process 3648\n"); |
| TEST_FILE_EQ (output, "drogo (foo) stop/pre-stop, process 6312\n"); |
| TEST_FILE_EQ (output, "\tpre-stop process 8609\n"); |
| TEST_FILE_EQ (output, "drogo (bar) start/post-stop, process 7465\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that an error reply from the GetAllInstances command |
| * is assumed to mean that the job went away, and thus the job |
| * is simply not printed rather than causing the function to end, |
| */ |
| TEST_FEATURE ("with error reply to GetAllInstances"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetAllJobs method call on the |
| * manager object, reply with a list of interesting |
| * paths. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetAllJobs")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| DBUS_TYPE_OBJECT_PATH_AS_STRING, |
| &arrayiter); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/foo"; |
| dbus_message_iter_append_basic (&arrayiter, |
| DBUS_TYPE_OBJECT_PATH, |
| &str_value); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/bar"; |
| dbus_message_iter_append_basic (&arrayiter, |
| DBUS_TYPE_OBJECT_PATH, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAllInstances method call on the |
| * first job object, reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetAllInstances")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/foo"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAllInstances method call on the |
| * second job object, reply with a single instance. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART_JOB, |
| "GetAllInstances")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/bar"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| DBUS_TYPE_OBJECT_PATH_AS_STRING, |
| &arrayiter); |
| |
| str_value = DBUS_PATH_UPSTART "/jobs/bar/_"; |
| dbus_message_iter_append_basic (&arrayiter, |
| DBUS_TYPE_OBJECT_PATH, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the Get call for the name of the |
| * second job, reply with the name. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/bar"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_JOB); |
| TEST_EQ_STR (property, "name"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "bar"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| /* Expect the GetAll call for the instance properties, |
| * reply with the properties. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "GetAll")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART "/jobs/bar/_"); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, |
| (DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING |
| DBUS_DICT_ENTRY_END_CHAR_AS_STRING), |
| &arrayiter); |
| |
| /* Name */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "name"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = ""; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Goal */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "goal"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "start"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* State */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "state"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "running"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| /* Processes */ |
| dbus_message_iter_open_container (&arrayiter, DBUS_TYPE_DICT_ENTRY, |
| NULL, |
| &dictiter); |
| |
| str_value = "processes"; |
| dbus_message_iter_append_basic (&dictiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_open_container (&dictiter, DBUS_TYPE_VARIANT, |
| (DBUS_TYPE_ARRAY_AS_STRING |
| DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &subiter); |
| |
| dbus_message_iter_open_container (&subiter, DBUS_TYPE_ARRAY, |
| (DBUS_STRUCT_BEGIN_CHAR_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_INT32_AS_STRING |
| DBUS_STRUCT_END_CHAR_AS_STRING), |
| &prociter); |
| |
| dbus_message_iter_open_container (&prociter, DBUS_TYPE_STRUCT, |
| NULL, |
| &structiter); |
| |
| str_value = "main"; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| int32_value = 3648; |
| dbus_message_iter_append_basic (&structiter, DBUS_TYPE_INT32, |
| &int32_value); |
| |
| dbus_message_iter_close_container (&prociter, &structiter); |
| |
| dbus_message_iter_close_container (&subiter, &prociter); |
| |
| dbus_message_iter_close_container (&dictiter, &subiter); |
| |
| dbus_message_iter_close_container (&arrayiter, &dictiter); |
| |
| dbus_message_iter_close_container (&iter, &arrayiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = list_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| /* May have had some output */ |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "bar start/running, process 3648\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that if an error is received from the GetAllJobs call, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply to GetAllJobs"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the GetAllJobs method call on the |
| * manager object, reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "GetAllJobs")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = list_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_emit_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| DBusMessage * reply = NULL; |
| const char * name_value; |
| char ** args_value; |
| int args_elements; |
| int wait_value; |
| NihCommand command; |
| char * args[4]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("emit_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that the emit action passes a single argument to the |
| * server in the EmitEvent command as the name of the event, |
| * along with a NULL array for the events. Make sure that wait |
| * is TRUE by default. |
| */ |
| TEST_FEATURE ("with single argument"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the EmitEvent method call on the manager |
| * object, make sure the arguments are right and |
| * reply to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "EmitEvent")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "wibble"); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "wibble"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = emit_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that additional arguments to the emit action are passed |
| * as entries in the environment argument of the command. |
| */ |
| TEST_FEATURE ("with multiple arguments"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the EmitEvent method call on the manager |
| * object, make sure the arguments are right and |
| * reply to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "EmitEvent")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "wibble"); |
| |
| TEST_EQ (args_elements, 2); |
| TEST_EQ_STR (args_value[0], "FOO=foo"); |
| TEST_EQ_STR (args_value[1], "BAR=bar"); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "wibble"; |
| args[1] = "FOO=foo"; |
| args[2] = "BAR=bar"; |
| args[3] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = emit_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that the --no-wait option results in the method call |
| * being made with wait as FALSE. |
| */ |
| TEST_FEATURE ("with no wait"); |
| no_wait = TRUE; |
| |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the EmitEvent method call on the manager |
| * object, make sure the arguments are right and |
| * reply to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "EmitEvent")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "wibble"); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_FALSE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "wibble"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = emit_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| no_wait = FALSE; |
| |
| |
| /* Check that if an error is received from the command, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the EmitEvent method call on the manager |
| * object, make sure the arguments are right and |
| * reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "EmitEvent")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &name_value, |
| DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &args_value, &args_elements, |
| DBUS_TYPE_BOOLEAN, &wait_value, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (name_value, "wibble"); |
| |
| TEST_EQ (args_elements, 0); |
| dbus_free_string_array (args_value); |
| |
| TEST_TRUE (wait_value); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "wibble"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = emit_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that a missing argument results in an error being output |
| * to stderr along with a suggestion of help. |
| */ |
| TEST_FEATURE ("with missing argument"); |
| TEST_ALLOC_FAIL { |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = emit_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: missing event name\n"); |
| TEST_FILE_EQ (errors, "Try `test --help' for more information.\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_reload_configuration_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| DBusMessage * reply = NULL; |
| NihCommand command; |
| char * args[1]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("reload_configuration_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that the reload_configuration sends the method call to the |
| * server. |
| */ |
| TEST_FEATURE ("with command"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the ReloadConfiguration method call for |
| * the manager object, reply to acknowledge. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "ReloadConfiguration")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = reload_configuration_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that if an error is received from the command, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the ReloadConfiguration method call for |
| * the manager object, reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_UPSTART, |
| "ReloadConfiguration")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = reload_configuration_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_version_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| const char * interface; |
| const char * property; |
| DBusMessage * reply = NULL; |
| DBusMessageIter iter; |
| DBusMessageIter subiter; |
| const char * str_value; |
| NihCommand command; |
| char * args[1]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("version_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that the version action queries the server for its |
| * version property, and prints the result to standard output. |
| */ |
| TEST_FEATURE ("with valid reply"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the version property, |
| * reply with the string we want printed. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART); |
| TEST_EQ_STR (property, "version"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "init (upstart 1.0.0)"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = version_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "init (upstart 1.0.0)\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that if an error is received from the query command, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with error reply"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the version property, |
| * reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART); |
| TEST_EQ_STR (property, "version"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = version_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_log_priority_action (void) |
| { |
| pid_t dbus_pid; |
| DBusConnection *server_conn; |
| FILE * output; |
| FILE * errors; |
| pid_t server_pid; |
| DBusMessage * method_call; |
| const char * interface; |
| const char * property; |
| DBusMessage * reply = NULL; |
| DBusMessageIter iter; |
| DBusMessageIter subiter; |
| const char * str_value; |
| char * signature; |
| NihCommand command; |
| char * args[2]; |
| int ret = 0; |
| int status; |
| |
| TEST_FUNCTION ("log_priority_action"); |
| TEST_DBUS (dbus_pid); |
| TEST_DBUS_OPEN (server_conn); |
| |
| assert (dbus_bus_request_name (server_conn, DBUS_SERVICE_UPSTART, |
| 0, NULL) |
| == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); |
| |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| assert (dbus_message_is_signal (method_call, DBUS_INTERFACE_DBUS, |
| "NameAcquired")); |
| dbus_message_unref (method_call); |
| |
| dbus_bus_type = DBUS_BUS_SYSTEM; |
| dest_name = DBUS_SERVICE_UPSTART; |
| dest_address = DBUS_ADDRESS_UPSTART; |
| |
| output = tmpfile (); |
| errors = tmpfile (); |
| |
| |
| /* Check that, when called without arguments, the log_priority action |
| * queries the server for its log_priority property and prints the |
| * result to standard output. |
| */ |
| TEST_FEATURE ("with no arguments"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the log_priority property, |
| * reply with the string we want printed. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART); |
| TEST_EQ_STR (property, "log_priority"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| |
| dbus_message_iter_init_append (reply, &iter); |
| |
| dbus_message_iter_open_container (&iter, DBUS_TYPE_VARIANT, |
| DBUS_TYPE_STRING_AS_STRING, |
| &subiter); |
| |
| str_value = "message"; |
| dbus_message_iter_append_basic (&subiter, DBUS_TYPE_STRING, |
| &str_value); |
| |
| dbus_message_iter_close_container (&iter, &subiter); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = log_priority_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_EQ (output, "message\n"); |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| |
| /* Check that, when called with an argument, the log_priority action |
| * passes that to the server to set its log_priority property. |
| */ |
| TEST_FEATURE ("with argument"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Set call for the log_priority property, |
| * send an acknowledgement reply. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Set")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| TEST_EQ_STR (dbus_message_get_signature (method_call), |
| (DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING)); |
| |
| dbus_message_iter_init (method_call, &iter); |
| |
| dbus_message_iter_get_basic (&iter, &interface); |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART); |
| |
| dbus_message_iter_next (&iter); |
| |
| dbus_message_iter_get_basic (&iter, &property); |
| TEST_EQ_STR (property, "log_priority"); |
| |
| dbus_message_iter_next (&iter); |
| dbus_message_iter_recurse (&iter, &subiter); |
| |
| signature = dbus_message_iter_get_signature (&subiter); |
| TEST_EQ_STR (signature, DBUS_TYPE_STRING_AS_STRING); |
| dbus_free (signature); |
| |
| dbus_message_iter_get_basic (&subiter, &str_value); |
| TEST_EQ_STR (str_value, "info"); |
| |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_method_return (method_call); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "info"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = log_priority_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| if (test_alloc_failed |
| && (ret != 0)) { |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_EQ (errors, "test: Cannot allocate memory\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| continue; |
| } |
| |
| TEST_EQ (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| waitpid (server_pid, &status, 0); |
| TEST_TRUE (WIFEXITED (status)); |
| TEST_EQ (WEXITSTATUS (status), 0); |
| } |
| |
| |
| /* Check that if an error is received from the query command, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with no arguments and error reply"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Get call for the log_priority property, |
| * reply with an error. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Get")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| |
| TEST_TRUE (dbus_message_get_args (method_call, NULL, |
| DBUS_TYPE_STRING, &interface, |
| DBUS_TYPE_STRING, &property, |
| DBUS_TYPE_INVALID)); |
| |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART); |
| TEST_EQ_STR (property, "log_priority"); |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = log_priority_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| /* Check that if an error is received from the query command, |
| * the message attached is printed to standard error and the |
| * command exits. |
| */ |
| TEST_FEATURE ("with argument and error reply"); |
| TEST_ALLOC_FAIL { |
| TEST_CHILD (server_pid) { |
| /* Expect the Set call for the log_priority property, |
| * send an error back. |
| */ |
| TEST_DBUS_MESSAGE (server_conn, method_call); |
| |
| TEST_TRUE (dbus_message_is_method_call (method_call, |
| DBUS_INTERFACE_PROPERTIES, |
| "Set")); |
| |
| TEST_EQ_STR (dbus_message_get_path (method_call), |
| DBUS_PATH_UPSTART); |
| TEST_EQ_STR (dbus_message_get_signature (method_call), |
| (DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_STRING_AS_STRING |
| DBUS_TYPE_VARIANT_AS_STRING)); |
| |
| dbus_message_iter_init (method_call, &iter); |
| |
| dbus_message_iter_get_basic (&iter, &interface); |
| TEST_EQ_STR (interface, DBUS_INTERFACE_UPSTART); |
| |
| dbus_message_iter_next (&iter); |
| |
| dbus_message_iter_get_basic (&iter, &property); |
| TEST_EQ_STR (property, "log_priority"); |
| |
| dbus_message_iter_next (&iter); |
| dbus_message_iter_recurse (&iter, &subiter); |
| |
| signature = dbus_message_iter_get_signature (&subiter); |
| TEST_EQ_STR (signature, DBUS_TYPE_STRING_AS_STRING); |
| dbus_free (signature); |
| |
| dbus_message_iter_get_basic (&subiter, &str_value); |
| TEST_EQ_STR (str_value, "info"); |
| |
| |
| TEST_ALLOC_SAFE { |
| reply = dbus_message_new_error (method_call, |
| DBUS_ERROR_UNKNOWN_METHOD, |
| "Unknown method"); |
| } |
| |
| dbus_connection_send (server_conn, reply, NULL); |
| dbus_connection_flush (server_conn); |
| |
| dbus_message_unref (method_call); |
| dbus_message_unref (reply); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| |
| dbus_shutdown (); |
| |
| exit (0); |
| } |
| |
| memset (&command, 0, sizeof command); |
| |
| args[0] = "info"; |
| args[1] = NULL; |
| |
| TEST_DIVERT_STDOUT (output) { |
| TEST_DIVERT_STDERR (errors) { |
| ret = log_priority_action (&command, args); |
| } |
| } |
| rewind (output); |
| rewind (errors); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (output); |
| TEST_FILE_RESET (output); |
| |
| TEST_FILE_MATCH (errors, "test: *\n"); |
| TEST_FILE_END (errors); |
| TEST_FILE_RESET (errors); |
| |
| kill (server_pid, SIGTERM); |
| waitpid (server_pid, NULL, 0); |
| } |
| |
| |
| fclose (errors); |
| fclose (output); |
| |
| TEST_DBUS_CLOSE (server_conn); |
| TEST_DBUS_END (dbus_pid); |
| |
| dbus_shutdown (); |
| } |
| |
| |
| void |
| test_usage (void) |
| { |
| char dirname[PATH_MAX]; |
| nih_local char *cmd = NULL; |
| pid_t upstart_pid = 0; |
| pid_t dbus_pid = 0; |
| char **output; |
| size_t lines; |
| FILE *out; |
| FILE *err; |
| NihCommand command; |
| char *args[2]; |
| int ret = 0; |
| |
| TEST_TRUE (getenv ("XDG_RUNTIME_DIR")); |
| |
| TEST_GROUP ("usage"); |
| |
| TEST_FILENAME (dirname); |
| TEST_EQ (mkdir (dirname, 0755), 0); |
| |
| /* Use the "secret" interface */ |
| TEST_EQ (setenv ("UPSTART_CONFDIR", dirname, 1), 0); |
| |
| TEST_DBUS (dbus_pid); |
| START_UPSTART (upstart_pid, FALSE); |
| |
| TEST_FEATURE ("no usage"); |
| CREATE_FILE (dirname, "foo.conf", |
| "author \"foo\"\n" |
| "description \"wibble\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s usage foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], "Usage: "); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("with usage"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "usage \"this is usage\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s usage foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ_STR (output[0], "Usage: this is usage"); |
| TEST_EQ (lines, 1); |
| nih_free (output); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| /*******************************************************************/ |
| |
| TEST_FEATURE ("failed status with usage"); |
| |
| CREATE_FILE (dirname, "foo.conf", |
| "instance $FOO\n" |
| "usage \"this is usage\""); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| memset (&command, 0, sizeof command); |
| args[0] = "foo"; |
| args[1] = NULL; |
| |
| out = tmpfile (); |
| err = tmpfile (); |
| |
| TEST_NE_P (out, NULL); |
| TEST_NE_P (err, NULL); |
| |
| TEST_DIVERT_STDOUT (out) { |
| TEST_DIVERT_STDERR (err) { |
| ret = status_action (&command, args); |
| } |
| } |
| rewind (out); |
| rewind (err); |
| |
| TEST_GT (ret, 0); |
| |
| TEST_FILE_END (out); |
| TEST_FILE_RESET (out); |
| |
| TEST_FILE_EQ (err, "test: Unknown parameter: FOO\n"); |
| TEST_FILE_EQ (err, "Usage: this is usage\n"); |
| TEST_FILE_END (err); |
| TEST_FILE_RESET (err); |
| |
| assert0 (fclose (out)); |
| assert0 (fclose (err)); |
| |
| DELETE_FILE (dirname, "foo.conf"); |
| |
| STOP_UPSTART (upstart_pid); |
| TEST_EQ (unsetenv ("UPSTART_CONFDIR"), 0); |
| TEST_DBUS_END (dbus_pid); |
| |
| assert0 (rmdir (dirname)); |
| } |
| |
| 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 *out_file = NULL; |
| nih_local char *contents = NULL; |
| size_t line_count; |
| FILE *fi; |
| |
| assert (confdir); |
| assert (logdir); |
| assert (upstart_pid); |
| assert (dbus_pid); |
| |
| cmd = nih_sprintf (NULL, "%s reset-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| assert0 (line_count); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure list-env returns default environment"); |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_GE (line_count, 2); |
| TEST_STR_ARRAY_CONTAINS (output, "PATH=*"); |
| TEST_STR_ARRAY_CONTAINS (output, "TERM=*"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure 'list-env --global' returns default environment"); |
| |
| cmd = nih_sprintf (NULL, "%s list-env --global 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_GE (line_count, 2); |
| TEST_STR_ARRAY_CONTAINS (output, "PATH=*"); |
| TEST_STR_ARRAY_CONTAINS (output, "TERM=*"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure get-env returns expected TERM variable"); |
| |
| cmd = nih_sprintf (NULL, "%s get-env TERM 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ_STR (output[0], getenv ("TERM")); |
| TEST_EQ (line_count, 1); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure 'get-env --global' returns expected TERM variable"); |
| |
| cmd = nih_sprintf (NULL, "%s get-env --global TERM 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| 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", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], getenv ("PATH")); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure 'get-env --global' returns expected PATH variable"); |
| |
| cmd = nih_sprintf (NULL, "%s get-env --global PATH 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], getenv ("PATH")); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure job gets given default environment"); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "foo.out")); |
| |
| /* This is a task so 'initctl start <job>' knows exacly when it's done. |
| */ |
| contents = NIH_MUST (nih_sprintf (NULL, "task\n" |
| "exec env >\"%s\"\n", |
| out_file)); |
| CREATE_FILE (confdir, "foo.conf", contents); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| nih_free (output); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "foo.out")); |
| |
| cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| nih_free (output); |
| |
| fi = fopen (out_file, "r"); |
| TEST_NE_P (fi, NULL); |
| TEST_FILE_CONTAINS (fi, "PATH=*"); |
| TEST_FILE_CONTAINS (fi, "TERM=*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_JOB=foo*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_INSTANCE=*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_SESSION=*"); |
| fclose (fi); |
| |
| DELETE_FILE (confdir, "foo.conf"); |
| TEST_EQ (unlink (out_file), 0); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure invalid query shows unknown variable"); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| "foo-bar-baz"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo-bar-baz"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| } |
| |
| void |
| clear_job_env (void) |
| { |
| nih_local char *cmd = NULL; |
| char **output; |
| size_t line_count; |
| size_t i; |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| 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", get_initctl (), 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", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| assert0 (line_count); |
| } |
| |
| /** |
| * 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 *out_file = NULL; |
| nih_local char *contents = NULL; |
| size_t line_count; |
| FILE *fi; |
| |
| assert (confdir); |
| assert (logdir); |
| assert (upstart_pid); |
| assert (dbus_pid); |
| |
| clear_job_env (); |
| |
| /* ensure get-env tolerates empty environment */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| "foo"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| |
| /* ensure unset-env tolerates empty environment */ |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), "foo"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| |
| /* ensure unset-env (multiple variables) tolerates empty environment */ |
| cmd = nih_sprintf (NULL, "%s unset-env %s %s 2>&1", get_initctl (), "foo", "bar"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| /* Although 2 variables have been specified, since neither is |
| * set, we only expect 1 error for the first variable. |
| */ |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure job runs in empty environment"); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "empty-env.out")); |
| |
| /* 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. |
| */ |
| contents = NIH_MUST (nih_sprintf (NULL, |
| "task\n" |
| "env PATH=%s\n" |
| "exec env >\"%s\"", |
| TEST_INITCTL_DEFAULT_PATH, out_file)); |
| |
| CREATE_FILE (confdir, "empty-env.conf", contents); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s start empty-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| nih_free (output); |
| |
| fi = fopen (out_file, "r"); |
| TEST_NE_P (fi, NULL); |
| |
| /* Ensure it looks like our PATH */ |
| TEST_FILE_CONTAINS (fi, "PATH=*/wibble*"); |
| |
| /* Although the environment is empty (except for PATH now), we |
| * still expect the special variables to be set. |
| */ |
| TEST_FILE_CONTAINS (fi, "UPSTART_JOB=empty-env*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_INSTANCE=*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_SESSION=*"); |
| fclose (fi); |
| |
| DELETE_FILE (confdir, "empty-env.conf"); |
| TEST_EQ (unlink (out_file), 0); |
| |
| /* reset environment */ |
| cmd = nih_sprintf (NULL, "%s reset-env 2>&1", get_initctl ()); |
| 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; |
| nih_local char *name = NULL; |
| nih_local char *value = NULL; |
| nih_local char *name2 = NULL; |
| nih_local char *value2 = NULL; |
| nih_local char *name3 = NULL; |
| nih_local char *value3 = NULL; |
| nih_local char *name4 = NULL; |
| nih_local char *value4 = NULL; |
| char **output; |
| nih_local char *out_file = NULL; |
| nih_local char *contents = NULL; |
| size_t line_count; |
| FILE *fi; |
| |
| 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", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| 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"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| value = NIH_MUST (nih_strdup (NULL, "bar")); |
| name2 = NIH_MUST (nih_strdup (NULL, "baz")); |
| value2 = NIH_MUST (nih_strdup (NULL, "qux")); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s=%s 2>&1", get_initctl (), |
| name, value); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s=%s 2>&1", get_initctl (), |
| name2, value2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s %s 2>&1", get_initctl (), name, name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: baz"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("multiple set-env in 'name=value' form"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| value = NIH_MUST (nih_strdup (NULL, "bar")); |
| name2 = NIH_MUST (nih_strdup (NULL, "baz")); |
| value2 = NIH_MUST (nih_strdup (NULL, "qux")); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s=%s %s=%s 2>&1", get_initctl (), |
| name, value, name2, value2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s %s 2>&1", get_initctl (), name, name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: baz"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("set-env in 'name=' form"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s= 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ (line_count, 1); |
| |
| /* nul string value expected if none specified when set */ |
| TEST_EQ_STR (output[0], ""); |
| |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("multiple set-env in 'name=' form"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| name2 = NIH_MUST (nih_strdup (NULL, "baz")); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s= %s= 2>&1", get_initctl (), |
| name, name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| /* nul string value expected if none specified when set */ |
| TEST_EQ_STR (output[0], ""); |
| |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| /* nul string value expected if none specified when set */ |
| TEST_EQ_STR (output[0], ""); |
| |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: baz"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("set-env in 'name' form"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ (line_count, 1); |
| |
| /* nul string value expected if none specified when set */ |
| TEST_EQ_STR (output[0], ""); |
| |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("multiple set-env in 'name' form"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| name2 = NIH_MUST (nih_strdup (NULL, "baz")); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s %s 2>&1", get_initctl (), |
| name, name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ (line_count, 1); |
| |
| /* nul string value expected if none specified when set */ |
| TEST_EQ_STR (output[0], ""); |
| |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ (line_count, 1); |
| |
| /* nul string value expected if none specified when set */ |
| TEST_EQ_STR (output[0], ""); |
| |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: baz"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("set-env for already set variable"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| value = NIH_MUST (nih_strdup (NULL, "bar")); |
| |
| /* set it */ |
| cmd = nih_sprintf (NULL, "%s set-env %s=%s 2>&1", get_initctl (), |
| name, value); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check it */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| /* set it again */ |
| cmd = nih_sprintf (NULL, "%s set-env %s=%s 2>&1", get_initctl (), |
| name, value); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check it again */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("set-env for multiple already set variables"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| value = NIH_MUST (nih_strdup (NULL, "bar")); |
| name2 = NIH_MUST (nih_strdup (NULL, "baz")); |
| value2 = NIH_MUST (nih_strdup (NULL, "qux")); |
| |
| /* set them */ |
| cmd = nih_sprintf (NULL, "%s set-env %s=%s %s=%s 2>&1", get_initctl (), |
| name, value, name2, value2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check them */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value2); |
| nih_free (output); |
| |
| /* set them again */ |
| cmd = nih_sprintf (NULL, "%s set-env %s=%s %s=%s 2>&1", get_initctl (), |
| name, value, name2, value2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check again */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: baz"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("set-env with multiple variables, some already set"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| value = NIH_MUST (nih_strdup (NULL, "bar")); |
| name2 = NIH_MUST (nih_strdup (NULL, "baz")); |
| value2 = NIH_MUST (nih_strdup (NULL, "qux")); |
| name3 = NIH_MUST (nih_strdup (NULL, "hello")); |
| value3 = NIH_MUST (nih_strdup (NULL, "world")); |
| name4 = NIH_MUST (nih_strdup (NULL, "bonjour")); |
| value4 = NIH_MUST (nih_strdup (NULL, "tout le monde")); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: hello"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: bonjour"); |
| nih_free (output); |
| |
| /* set 2 variables initially */ |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' %s='%s' 2>&1", get_initctl (), |
| name3, value3, name4, value4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check them */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value3); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value4); |
| nih_free (output); |
| |
| /* set them all */ |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' %s='%s' %s='%s' %s='%s' 2>&1", get_initctl (), |
| name, value, name3, value3, name2, value2, name4, value4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check again */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value3); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value4); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: baz"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: hello"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: bonjour"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("set-env with multiple variables in different forms"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| value = NIH_MUST (nih_strdup (NULL, "bar")); |
| name2 = NIH_MUST (nih_strdup (NULL, "baz")); |
| value2 = NIH_MUST (nih_strdup (NULL, "qux")); |
| |
| name3 = NIH_MUST (nih_strdup (NULL, "name-equals")); |
| name4 = NIH_MUST (nih_strdup (NULL, "just-name")); |
| |
| /* set them all */ |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' %s= %s %s='%s' 2>&1", get_initctl (), |
| name, value, name3, name4, name2, value2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| /* nul string value expected if none specified when set */ |
| TEST_EQ_STR (output[0], ""); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| /* nul string value expected if none specified when set */ |
| TEST_EQ_STR (output[0], ""); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: baz"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: name-equals"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: just-name"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("set-env --retain"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| value = NIH_MUST (nih_strdup (NULL, "bar")); |
| |
| /* set it */ |
| cmd = nih_sprintf (NULL, "%s set-env %s=%s 2>&1", get_initctl (), |
| name, value); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check it */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s set-env --retain %s=%s 2>&1", |
| get_initctl (), name, "HELLO"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check that value did *NOT* change */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("set-env --retain with multiple variables, some already set"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| value = NIH_MUST (nih_strdup (NULL, "bar")); |
| name3 = NIH_MUST (nih_strdup (NULL, "hello")); |
| value3 = NIH_MUST (nih_strdup (NULL, "world")); |
| name4 = NIH_MUST (nih_strdup (NULL, "bonjour")); |
| value4 = NIH_MUST (nih_strdup (NULL, "tout le monde")); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: hello"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: bonjour"); |
| nih_free (output); |
| |
| /* set 2 variables initially */ |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' %s='%s' 2>&1", get_initctl (), |
| name3, value3, name4, value4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check them */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value3); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| |
| TEST_EQ_STR (output[0], value4); |
| nih_free (output); |
| |
| /* set them all */ |
| cmd = nih_sprintf (NULL, "%s set-env --retain %s='%s' %s='%s' %s='%s' %s='%s' 2>&1", |
| get_initctl (), name, value, name3, "AAAA", name2, value2, name4, "BBBB"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| /* check that the original values did *NOT* change */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value3); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value4); |
| nih_free (output); |
| |
| /* Check that the initially-not set variables were set */ |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: baz"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name3); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: hello"); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name4); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: bonjour"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("set-env with space within value and trailing tab"); |
| |
| name = NIH_MUST (nih_strdup (NULL, "foo")); |
| value = NIH_MUST (nih_sprintf (NULL, "space tab\t")); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' 2>&1", get_initctl (), |
| name, value); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], value); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s get-env %s 2>&1", get_initctl (), |
| name); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| TEST_EQ_STR (output[0], "initctl: No such variable: foo"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("list-env output order"); |
| |
| clear_job_env (); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' 2>&1", get_initctl (), |
| "zygote", "cell"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' 2>&1", get_initctl (), |
| "median", "middle"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' 2>&1", get_initctl (), |
| "aardvark", "mammal"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ_STR (output[0], "aardvark=mammal"); |
| TEST_EQ_STR (output[1], "median=middle"); |
| TEST_EQ_STR (output[2], "zygote=cell"); |
| TEST_EQ (line_count, 3); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), "aardvark"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ_STR (output[0], "median=middle"); |
| TEST_EQ_STR (output[1], "zygote=cell"); |
| TEST_EQ (line_count, 2); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env %s 2>&1", get_initctl (), "zygote"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ_STR (output[0], "median=middle"); |
| TEST_EQ (line_count, 1); |
| nih_free (output); |
| |
| /* re-add */ |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' 2>&1", get_initctl (), |
| "aardvark", "mammal"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' 2>&1", get_initctl (), |
| "zygote", "cell"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| TEST_EQ_STR (output[0], "aardvark=mammal"); |
| TEST_EQ_STR (output[1], "median=middle"); |
| TEST_EQ_STR (output[2], "zygote=cell"); |
| TEST_EQ (line_count, 3); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s reset-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| assert0 (line_count); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure job runs in modified environment"); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' 2>&1", get_initctl (), |
| "aardvark", "mammal"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' 2>&1", get_initctl (), |
| "FOO", "BAR"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| cmd = nih_sprintf (NULL, "%s set-env %s='%s' 2>&1", get_initctl (), |
| "_________", "_________"); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "modified-env.out")); |
| |
| contents = NIH_MUST (nih_sprintf (NULL, |
| "task\n" |
| "exec env >\"%s\"\n", out_file)); |
| |
| CREATE_FILE (confdir, "modified-env.conf", contents); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s start modified-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| nih_free (output); |
| |
| fi = fopen (out_file, "r"); |
| TEST_NE_P (fi, NULL); |
| |
| /* defaults */ |
| TEST_FILE_CONTAINS (fi, "PATH=*"); |
| TEST_FILE_CONTAINS (fi, "TERM=*"); |
| |
| /* variables we added */ |
| TEST_FILE_CONTAINS (fi, "aardvark=mammal*"); |
| TEST_FILE_CONTAINS (fi, "FOO=BAR*"); |
| TEST_FILE_CONTAINS (fi, "_________=_________*"); |
| |
| /* special vars */ |
| TEST_FILE_CONTAINS (fi, "UPSTART_JOB=modified-env*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_INSTANCE=*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_SESSION=*"); |
| |
| fclose (fi); |
| |
| DELETE_FILE (confdir, "modified-env.conf"); |
| TEST_EQ (unlink (out_file), 0); |
| |
| /* reset environment */ |
| cmd = nih_sprintf (NULL, "%s reset-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| assert0 (line_count); |
| |
| /*******************************************************************/ |
| } |
| |
| void |
| test_job_env_invalid_args (const char *confdir, const char *logdir, |
| pid_t upstart_pid, pid_t dbus_pid) |
| { |
| nih_local char *cmd = NULL; |
| nih_local char *name = NULL; |
| nih_local char *value = NULL; |
| char **output; |
| size_t line_count; |
| |
| assert (confdir); |
| assert (logdir); |
| assert (upstart_pid); |
| assert (dbus_pid); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("call get-env without specifying a variable"); |
| |
| cmd = nih_sprintf (NULL, "%s get-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 2); |
| TEST_EQ_STR (output[0], "initctl: missing variable name"); |
| TEST_EQ_STR (output[1], "Try `initctl --help\' for more information."); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("call set-env without specifying a variable"); |
| |
| cmd = nih_sprintf (NULL, "%s set-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 2); |
| TEST_EQ_STR (output[0], "initctl: missing variable value"); |
| TEST_EQ_STR (output[1], "Try `initctl --help\' for more information."); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("call unset-env without specifying a variable"); |
| |
| cmd = nih_sprintf (NULL, "%s unset-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 2); |
| TEST_EQ_STR (output[0], "initctl: missing variable name"); |
| TEST_EQ_STR (output[1], "Try `initctl --help\' for more information."); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| } |
| |
| void |
| test_global_and_local_job_env (const char *confdir, const char *logdir, |
| pid_t upstart_pid, pid_t dbus_pid) |
| { |
| nih_local char *cmd = NULL; |
| nih_local char *name = NULL; |
| nih_local char *value = NULL; |
| nih_local char *out_file = NULL; |
| nih_local char *contents = NULL; |
| char **output; |
| size_t line_count; |
| FILE *fi; |
| |
| assert (confdir); |
| assert (logdir); |
| assert (upstart_pid); |
| assert (dbus_pid); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure pre-start can inject variable into main process"); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "foo.out")); |
| |
| contents = nih_sprintf (NULL, |
| "task\n" |
| "pre-start exec %s set-env hello=world\n" |
| "exec %s list-env >\"%s\"\n", |
| get_initctl (), get_initctl (), out_file); |
| |
| TEST_NE_P (contents, NULL); |
| |
| CREATE_FILE (confdir, "foo.conf", contents); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| nih_free (output); |
| |
| fi = fopen (out_file, "r"); |
| TEST_FILE_CONTAINS (fi, "hello=world*"); |
| TEST_NE_P (fi, NULL); |
| |
| fclose (fi); |
| |
| TEST_EQ (unlink (out_file), 0); |
| nih_free (out_file); |
| out_file = NULL; |
| DELETE_FILE (confdir, "foo.conf"); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure 'set-env --global' can inject a variable into main process"); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "foo.out")); |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| /* ensure variable not set initially */ |
| TEST_EQ (line_count, 2); |
| TEST_STR_MATCH (output[0], "PATH=*"); |
| TEST_STR_MATCH (output[1], "TERM=*"); |
| nih_free (output); |
| |
| contents = nih_sprintf (NULL, |
| "task\n" |
| "script\n" |
| " %s set-env --global hello=world\n" |
| " %s get-env hello >\"%s\"\n" |
| "end script", |
| get_initctl (), get_initctl (), out_file); |
| TEST_NE_P (contents, NULL); |
| |
| CREATE_FILE (confdir, "foo.conf", contents); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 1); |
| nih_free (output); |
| |
| fi = fopen (out_file, "r"); |
| TEST_NE_P (fi, NULL); |
| TEST_FILE_MATCH (fi, "world*\n"); |
| TEST_FILE_END (fi); |
| fclose (fi); |
| |
| TEST_EQ (unlink (out_file), 0); |
| DELETE_FILE (confdir, "foo.conf"); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", |
| logdir, |
| "bar.out")); |
| |
| /* Create a new job */ |
| contents = nih_sprintf (NULL, "task\nexec %s list-env >\"%s\"", |
| get_initctl (), out_file); |
| TEST_NE_P (contents, NULL); |
| |
| CREATE_FILE (confdir, "bar.conf", contents); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| TEST_EQ (line_count, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s start bar 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| nih_free (output); |
| |
| fi = fopen (out_file, "r"); |
| TEST_NE_P (fi, NULL); |
| |
| /* Since foo.conf modified the global table, a subsequent job |
| * should pick up the change. |
| */ |
| TEST_FILE_CONTAINS (fi, "hello=world*"); |
| |
| fclose (fi); |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| /* ensure variable still returned by list-env */ |
| TEST_GT (line_count, 2); |
| TEST_STR_ARRAY_CONTAINS (output, "hello=world"); |
| nih_free (output); |
| |
| /* reset environment */ |
| cmd = nih_sprintf (NULL, "%s reset-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| assert0 (line_count); |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &line_count); |
| |
| /* ensure variable no longer set */ |
| TEST_GT (line_count, 0); |
| TEST_STR_ARRAY_NOT_CONTAINS (output, "hello=world"); |
| nih_free (output); |
| |
| assert0 (unlink (out_file)); |
| DELETE_FILE (confdir, "bar.conf"); |
| |
| /*******************************************************************/ |
| } |
| |
| void |
| test_no_inherit_job_env (const char *runtimedir, const char *confdir, const char *logdir) |
| { |
| nih_local char *cmd = NULL; |
| char **output; |
| size_t lines; |
| pid_t upstart_pid = 0; |
| char *extra[] = { "--no-inherit-env", NULL }; |
| nih_local char *session_file = NULL; |
| nih_local char *out_file = NULL; |
| nih_local char *contents = NULL; |
| FILE *fi; |
| struct stat statbuf; |
| |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, extra); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure list-env in '--user --no-inherit-env' environment gives expected output"); |
| |
| cmd = nih_sprintf (NULL, "%s list-env 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| |
| /* environment should comprise the default environment only */ |
| TEST_EQ (lines, 2); |
| TEST_STR_MATCH (output[0], "PATH=*"); |
| TEST_STR_MATCH (output[1], "TERM=*"); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| TEST_FEATURE ("ensure '--user --no-inherit-env' provides expected job environment"); |
| |
| out_file = NIH_MUST (nih_sprintf (NULL, "%s/%s", logdir, "foo.out")); |
| TEST_EQ (stat (out_file, &statbuf), -1); |
| TEST_EQ (errno, ENOENT); |
| |
| contents = NIH_MUST (nih_sprintf (NULL, |
| "task\n" |
| "exec env >\"%s\"\n", out_file)); |
| CREATE_FILE (confdir, "foo.conf", contents); |
| |
| cmd = nih_sprintf (NULL, "%s reload-configuration 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| nih_free (output); |
| |
| cmd = nih_sprintf (NULL, "%s start foo 2>&1", get_initctl ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| nih_free (output); |
| |
| fi = fopen (out_file, "r"); |
| TEST_NE_P (fi, NULL); |
| TEST_FILE_CONTAINS (fi, "PATH=*"); |
| TEST_FILE_CONTAINS (fi, "TERM=*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_JOB=foo*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_INSTANCE=*"); |
| TEST_FILE_CONTAINS (fi, "UPSTART_SESSION=*"); |
| fclose (fi); |
| |
| DELETE_FILE (confdir, "foo.conf"); |
| TEST_EQ (unlink (out_file), 0); |
| |
| /*******************************************************************/ |
| |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| runtimedir, (int)upstart_pid)); |
| |
| STOP_UPSTART (upstart_pid); |
| |
| unlink (session_file); |
| } |
| |
| /* |
| * 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]; |
| size_t lines; |
| pid_t dbus_pid = 0; |
| pid_t upstart_pid = 0; |
| char *value; |
| nih_local char *cmd = NULL; |
| char **output; |
| nih_local char *session_file = NULL; |
| char *xdg_runtime_dir; |
| |
| xdg_runtime_dir = getenv ("XDG_RUNTIME_DIR"); |
| TEST_TRUE (xdg_runtime_dir); |
| |
| 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); |
| |
| /*******************************************************************/ |
| /* Ensure basic variables are set in the current environment */ |
| |
| if (! getenv ("TERM")) { |
| fprintf (stderr, "WARNING: setting TERM to '%s' as not set\n", |
| TEST_INITCTL_DEFAULT_TERM); |
| assert0 (setenv ("TERM", TEST_INITCTL_DEFAULT_TERM, 1)); |
| } |
| |
| if (! getenv ("PATH")) { |
| fprintf (stderr, "WARNING: setting PATH to '%s' as not set\n", |
| TEST_INITCTL_DEFAULT_PATH); |
| assert0 (setenv ("PATH", TEST_INITCTL_DEFAULT_PATH, 1)); |
| } |
| |
| TEST_DBUS (dbus_pid); |
| start_upstart_common (&upstart_pid, TRUE, FALSE, confdir, logdir, NULL); |
| |
| cmd = nih_sprintf (NULL, "%s list-sessions 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| |
| /* look for separator between pid and value of |
| * UPSTART_SESSION. |
| */ |
| value = strstr (output[0], " "); |
| TEST_NE_P (value, NULL); |
| |
| /* jump over space */ |
| value += 1; |
| TEST_NE_P (value, NULL); |
| |
| assert0 (setenv ("UPSTART_SESSION", value, 1)); |
| nih_free (output); |
| |
| /*******************************************************************/ |
| |
| test_job_env_invalid_args (confdir, logdir, upstart_pid, dbus_pid); |
| |
| test_default_job_env (confdir, logdir, upstart_pid, dbus_pid); |
| |
| test_modified_job_env (confdir, logdir, upstart_pid, dbus_pid); |
| |
| test_global_and_local_job_env (confdir, logdir, upstart_pid, dbus_pid); |
| |
| /*******************************************************************/ |
| |
| STOP_UPSTART (upstart_pid); |
| session_file = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions/%d.session", |
| xdg_runtime_dir, (int)upstart_pid)); |
| unlink (session_file); |
| |
| /*******************************************************************/ |
| |
| test_no_inherit_job_env (xdg_runtime_dir, confdir, logdir); |
| |
| /*******************************************************************/ |
| |
| TEST_DBUS_END (dbus_pid); |
| assert0 (unsetenv ("UPSTART_CONFDIR")); |
| assert0 (unsetenv ("UPSTART_LOGDIR")); |
| assert0 (unsetenv ("UPSTART_SESSION")); |
| |
| TEST_EQ (rmdir (confdir), 0); |
| TEST_EQ (rmdir (logdir), 0); |
| } |
| |
| void |
| test_dbus_connection (void) |
| { |
| size_t lines; |
| pid_t dbus_pid = 0; |
| pid_t dbus_pid2 = 0; |
| pid_t upstart_pid = 0; |
| nih_local char *cmd = NULL; |
| char **output; |
| nih_local char *dbus_session_address = NULL; |
| nih_local char *dbus_session_address2 = NULL; |
| nih_local char *upstart_session = NULL; |
| nih_local char *original_runtime = NULL; |
| char dirname[PATH_MAX]; |
| nih_local char *path = NULL; |
| char *address; |
| |
| original_runtime = nih_strdup (NULL, getenv("XDG_RUNTIME_DIR")); |
| TEST_NE_P (original_runtime, NULL); |
| |
| TEST_FILENAME (dirname); |
| TEST_EQ (mkdir (dirname, 0755), 0); |
| |
| TEST_EQ (setenv ("XDG_RUNTIME_DIR", dirname, 1), 0); |
| |
| TEST_GROUP ("D-Bus connection"); |
| |
| /*********************************************************************/ |
| TEST_FEATURE ("ensure non-priv non-Session Init connects to D-Bus session bus on startup"); |
| |
| /* Start a dbus-daemon */ |
| TEST_DBUS (dbus_pid); |
| |
| /* Not required */ |
| assert0 (unsetenv ("DBUS_SYSTEM_BUS_ADDRESS")); |
| |
| TEST_TRUE (getenv ("DBUS_SESSION_BUS_ADDRESS")); |
| |
| START_UPSTART (upstart_pid, FALSE); |
| |
| cmd = nih_sprintf (NULL, "%s --session version 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], "init (upstart [0-9.][0-9.]*"); |
| nih_free (output); |
| |
| STOP_UPSTART (upstart_pid); |
| TEST_DBUS_END (dbus_pid); |
| |
| /*********************************************************************/ |
| TEST_FEATURE ("ensure Session Init does not connect to D-Bus session bus on startup"); |
| |
| /* Start a dbus-daemon */ |
| TEST_DBUS (dbus_pid); |
| |
| /* Not required */ |
| assert0 (unsetenv ("DBUS_SYSTEM_BUS_ADDRESS")); |
| |
| TEST_TRUE (getenv ("DBUS_SESSION_BUS_ADDRESS")); |
| |
| START_UPSTART (upstart_pid, TRUE); |
| |
| address = getenv ("DBUS_SESSION_BUS_ADDRESS"); |
| TEST_NE_P (address, NULL); |
| dbus_session_address = nih_strdup (NULL, address); |
| TEST_NE_P (dbus_session_address, NULL); |
| |
| /* Stop initctl using this route */ |
| assert0 (unsetenv ("DBUS_SESSION_BUS_ADDRESS")); |
| |
| /* Check we can query the version via the private socket */ |
| cmd = nih_sprintf (NULL, "%s version 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], "init (upstart [0-9.][0-9.]*"); |
| nih_free (output); |
| |
| /* Unset to stop initctl finding upstart via this route */ |
| assert0 (unsetenv ("UPSTART_SESSION")); |
| |
| /* Re-apply in the test environment */ |
| assert0 (setenv ("DBUS_SESSION_BUS_ADDRESS", dbus_session_address, 1)); |
| |
| /* Although there is a D-Bus session bus available, the Session |
| * Init should not connect to it. Check this by trying to query |
| * the running version via the D-Bus session bus. |
| */ |
| cmd = nih_sprintf (NULL, "%s --session version 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], "initctl: Name \"com.ubuntu.Upstart\" does not exist*"); |
| nih_free (output); |
| |
| STOP_UPSTART (upstart_pid); |
| TEST_DBUS_END (dbus_pid); |
| |
| /*********************************************************************/ |
| TEST_FEATURE ("ensure Session Init connects to D-Bus session bus when notified"); |
| |
| /* Start a dbus-daemon */ |
| TEST_DBUS (dbus_pid); |
| |
| address = getenv ("DBUS_SESSION_BUS_ADDRESS"); |
| TEST_NE_P (address, NULL); |
| dbus_session_address = nih_strdup (NULL, address); |
| TEST_NE_P (dbus_session_address, NULL); |
| |
| /* Not required */ |
| assert0 (unsetenv ("DBUS_SYSTEM_BUS_ADDRESS")); |
| assert0 (unsetenv ("DBUS_SESSION_BUS_ADDRESS")); |
| |
| nih_local char **extra = NULL; |
| extra = NIH_MUST (nih_str_array_new (NULL)); |
| NIH_MUST (nih_str_array_add (&extra, NULL, NULL,"--no-startup-event")); |
| start_upstart_common (&(upstart_pid), TRUE, FALSE, NULL, NULL, extra); |
| |
| /* Pass the D-Bus session bus address to the Session Init */ |
| cmd = nih_sprintf (NULL, "%s notify-dbus-address \"%s\" 2>&1", |
| get_initctl_binary (), dbus_session_address); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| /* Re-apply in the test environment */ |
| assert0 (setenv ("DBUS_SESSION_BUS_ADDRESS", dbus_session_address, 1)); |
| |
| /* It should now be possible to query the running version via |
| * the D-Bus session bus. |
| */ |
| cmd = nih_sprintf (NULL, "%s --session version 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], "init (upstart [0-9.][0-9.]*"); |
| nih_free (output); |
| |
| /*********************************************************************/ |
| TEST_FEATURE ("ensure Session Init retains D-Bus address across a re-exec"); |
| |
| assert0 (unsetenv ("DBUS_SESSION_BUS_ADDRESS")); |
| |
| REEXEC_UPSTART (upstart_pid, TRUE); |
| |
| /* Re-apply in the test environment */ |
| assert0 (setenv ("DBUS_SESSION_BUS_ADDRESS", dbus_session_address, 1)); |
| /* We only waited for the private control interface above; now wait for |
| * D-Bus again. |
| */ |
| wait_for_upstart (0); |
| |
| /* It should still be possible to query the running version via |
| * the D-Bus session bus since Upstart should have reconnected |
| * since it was previously notified of the D-Bus address. |
| */ |
| cmd = nih_sprintf (NULL, "%s --session version 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], "init (upstart [0-9.][0-9.]*"); |
| nih_free (output); |
| |
| STOP_UPSTART (upstart_pid); |
| TEST_DBUS_END (dbus_pid); |
| |
| /*********************************************************************/ |
| TEST_FEATURE ("ensure Session Init does not connect to another bus when notified twice"); |
| |
| /* Start first dbus-daemon */ |
| TEST_DBUS (dbus_pid); |
| |
| /* Save its address */ |
| address = getenv ("DBUS_SESSION_BUS_ADDRESS"); |
| TEST_NE_P (address, NULL); |
| dbus_session_address = nih_strdup (NULL, address); |
| TEST_NE_P (dbus_session_address, NULL); |
| |
| /* Start second dbus-daemon */ |
| TEST_DBUS (dbus_pid2); |
| |
| /* Save its address */ |
| address = getenv ("DBUS_SESSION_BUS_ADDRESS"); |
| TEST_NE_P (address, NULL); |
| dbus_session_address2 = nih_strdup (NULL, address); |
| TEST_NE_P (dbus_session_address2, NULL); |
| |
| assert0 (unsetenv ("DBUS_SYSTEM_BUS_ADDRESS")); |
| assert0 (unsetenv ("DBUS_SESSION_BUS_ADDRESS")); |
| |
| start_upstart_common (&(upstart_pid), TRUE, FALSE, NULL, NULL, extra); |
| |
| /* Pass the first D-Bus session bus address to the Session Init */ |
| cmd = nih_sprintf (NULL, "%s notify-dbus-address \"%s\" 2>&1", |
| get_initctl_binary (), dbus_session_address); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| /* Re-apply in the test environment */ |
| assert0 (setenv ("DBUS_SESSION_BUS_ADDRESS", dbus_session_address, 1)); |
| |
| /* It should now be possible to query the running version via |
| * the D-Bus session bus. |
| */ |
| cmd = nih_sprintf (NULL, "%s --session version 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], "init (upstart [0-9.][0-9.]*"); |
| nih_free (output); |
| |
| /* Pass the second D-Bus session bus address to the Session Init */ |
| cmd = nih_sprintf (NULL, "%s notify-dbus-address \"%s\" 2>&1", |
| get_initctl_binary (), dbus_session_address2); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 0); |
| |
| /* Check that the Session Init still responds on the first address */ |
| cmd = nih_sprintf (NULL, "%s --session version 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], "init (upstart [0-9.][0-9.]*"); |
| nih_free (output); |
| |
| /* Stop the 1st daemon */ |
| TEST_DBUS_END (dbus_pid); |
| |
| /* Switch to the 2nd daemon */ |
| assert0 (setenv ("DBUS_SESSION_BUS_ADDRESS", dbus_session_address2, 1)); |
| |
| /* Ensure the Session Init isn't responding on this address */ |
| cmd = nih_sprintf (NULL, "%s --session version 2>&1", get_initctl_binary ()); |
| TEST_NE_P (cmd, NULL); |
| RUN_COMMAND (NULL, cmd, &output, &lines); |
| TEST_EQ (lines, 1); |
| TEST_STR_MATCH (output[0], "initctl: Name \"com.ubuntu.Upstart\" does not exist*"); |
| nih_free (output); |
| |
| STOP_UPSTART (upstart_pid); |
| |
| /* Stop the 2nd daemon */ |
| TEST_DBUS_END (dbus_pid2); |
| |
| TEST_EQ (setenv ("XDG_RUNTIME_DIR", original_runtime, 1), 0); |
| |
| path = NIH_MUST (nih_sprintf (NULL, "%s/dbus-1/services", dirname)); |
| cmd = NIH_MUST (nih_sprintf (NULL, "rm -f %s/*.session 2>/dev/null", path)); |
| assert0 (system (cmd)); |
| assert0 (rmdir (path)); |
| path = NIH_MUST (nih_sprintf (NULL, "%s/dbus-1", dirname)); |
| assert0 (rmdir (path)); |
| |
| path = NIH_MUST (nih_sprintf (NULL, "%s/upstart/sessions", dirname)); |
| cmd = NIH_MUST (nih_sprintf (NULL, "rm -f %s/*.session 2>/dev/null", path)); |
| assert0 (system (cmd)); |
| assert0 (rmdir (path)); |
| path = NIH_MUST (nih_sprintf (NULL, "%s/upstart", dirname)); |
| assert0 (rmdir (path)); |
| |
| assert0 (rmdir (dirname)); |
| } |
| |
| int |
| main (int argc, |
| char *argv[]) |
| { |
| nih_error_init (); |
| nih_timer_init (); |
| nih_signal_init (); |
| nih_child_init (); |
| nih_main_loop_init (); |
| program_name = "test"; |
| |
| test_common_setup (); |
| |
| test_upstart_open (); |
| test_job_status (); |
| |
| test_start_action (); |
| test_stop_action (); |
| test_restart_action (); |
| test_reload_action (); |
| test_status_action (); |
| test_list_action (); |
| test_emit_action (); |
| test_reload_configuration_action (); |
| test_version_action (); |
| test_log_priority_action (); |
| test_usage (); |
| |
| test_job_env (); |
| |
| // re-exec was disabled in b/261373856. Drop its tests too. |
| // test_reexec (); |
| printf ("SKIP: re-exec feature (and tests) are disabled\n"); |
| |
| test_list_sessions (); |
| if (have_timed_waitpid ()) { |
| test_quiesce (); |
| } else { |
| fprintf (stderr, "\n\n" |
| "WARNING: not running quiesce tests, " |
| "as no precise timing information available " |
| "\n\n"); |
| } |
| |
| test_umask (); |
| test_no_dbus (); |
| |
| if (in_chroot () && !dbus_configured ()) { |
| fprintf (stderr, "\n\n" |
| "WARNING: not running show-config, " |
| "check-config & notify-disk-writeable tests within chroot " |
| "as no D-Bus, or D-Bus not configured (lp:#728988)" |
| "\n\n"); |
| } else { |
| test_list (); |
| test_show_config (); |
| test_check_config (); |
| test_notify_disk_writeable (); |
| } |
| |
| test_dbus_connection (); |
| |
| test_common_cleanup (); |
| |
| return 0; |
| } |