blob: 6f9eceb53d7eb1fb93b79f04d4a329a716fce370 [file] [log] [blame]
/* upstart
*
* test_initctl.c - test suite for util/initctl.c
*
* Copyright © 2010 Canonical Ltd.
* Author: Scott James Remnant <scott@netsplit.com>.
*
* 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-dbus/test_dbus.h>
#include <dbus/dbus.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.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/string.h>
#include "dbus/upstart.h"
/* remember we run from the 'util' directory */
#define UPSTART_BINARY "../init/init"
#define INITCTL_BINARY "./initctl --session"
#define BUFFER_SIZE 1024
/**
* START_UPSTART:
*
* @pid: pid_t that will contain pid of running instance on success.
*
* Start an instance of Upstart. Fork errors are fatal, but after
* a successful fork, waits for up to a somewhat arbitrary (but
* more than adequate!) amount of time for Upstart to initialize.
**/
#define START_UPSTART(pid) \
{ \
nih_local NihDBusProxy *upstart = NULL; \
DBusConnection *connection; \
DBusError dbus_error; \
\
/* XXX: arbitrary value */ \
int attempts = 10; \
\
\
TEST_NE (pid = fork (), -1); \
\
if (pid == 0) \
execlp (UPSTART_BINARY, UPSTART_BINARY, \
"--session", \
"--no-startup-event", NULL); \
\
while (attempts) { \
attempts--; \
sleep (1); \
dbus_error_init (&dbus_error); \
connection = dbus_bus_get (DBUS_BUS_SESSION, \
&dbus_error); \
\
if (! connection) { \
dbus_error_free (&dbus_error); \
continue; \
} \
dbus_error_free (&dbus_error); \
\
upstart = nih_dbus_proxy_new (NULL, connection, \
DBUS_SERVICE_UPSTART, \
DBUS_PATH_UPSTART, \
NULL, NULL); \
\
if (! upstart) { \
NihError *err; \
err = nih_error_get (); \
nih_free (err); \
dbus_connection_unref (connection); \
} \
else { \
break; \
} \
} \
}
/**
* STOP_UPSTART:
*
* @pid: pid of upstart to kill.
*
* Stop upstart process @pid.
**/
#define STOP_UPSTART(pid) \
{ \
assert (pid); \
\
if (kill (pid, 0) == 0) { \
kill (pid, SIGTERM); \
sleep (1); \
} \
\
if (kill (pid, 0) == 0) { \
kill (pid, SIGKILL); \
} \
}
/**
* RUN_COMMAND:
*
* @parent: pointer to parent object,
* @cmd: string representing command to run,
* @result: "char ***" pointer which will contain an array of string
* values corresponding to lines of standard output generated by @cmd,
* @len: size_t pointer which will be set to length of @result.
*
* Run a command and return its standard output. It is the callers
* responsibility to free @result. Errors from running @cmd are fatal.
**/
#define RUN_COMMAND(parent, cmd, result, len) \
{ \
FILE *f; \
char buffer[BUFFER_SIZE]; \
char **ret; \
\
assert (cmd[0]); \
\
*(result) = nih_str_array_new (parent); \
TEST_NE_P (*result, NULL); \
*(len) = 0; \
\
f = popen (cmd, "r"); \
TEST_NE_P (f, NULL); \
\
while (fgets (buffer, BUFFER_SIZE, f)) { \
size_t l = strlen (buffer)-1; \
\
if ( buffer[l] == '\n') \
buffer[l] = '\0'; \
ret = nih_str_array_add (result, parent, len, \
buffer); \
TEST_NE_P (ret, NULL); \
} \
\
TEST_NE ( pclose (f), -1); \
}
/**
* CREATE_FILE:
*
* @dirname: directory name (assumed to already exist),
* @name: name of file to create (no leading slash),
* @contents: string contents of @name.
*
* Create a file in the specified directory with the specified
* contents.
*
* Notes: A newline character is added in the case where @contents does
* not end with one.
**/
#define CREATE_FILE(dirname, name, contents) \
{ \
FILE *f; \
char filename[PATH_MAX]; \
\
assert (dirname[0]); \
assert (name[0]); \
\
strcpy (filename, dirname); \
if ( name[0] != '/' ) \
strcat (filename, "/"); \
strcat (filename, name); \
f = fopen (filename, "w"); \
TEST_NE_P (f, NULL); \
fprintf (f, contents); \
if ( contents[strlen(contents)-1] != '\n') \
fprintf (f, "\n"); \
fclose (f); \
}
/**
* DELETE_FILE:
*
* @dirname: directory in which file to delete exists,
* @name: name of file in @dirname to delete.
*
* Delete specified file.
*
**/
#define DELETE_FILE(dirname, name) \
{ \
char filename[PATH_MAX]; \
\
assert (dirname[0]); \
assert (name[0]); \
\
strcpy (filename, dirname); \
if ( name[0] != '/' ) \
strcat (filename, "/"); \
strcat (filename, name); \
\
TEST_EQ (unlink (filename), 0); \
}
extern int use_dbus;
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);
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");
TEST_ALLOC_FAIL {
use_dbus = FALSE;
dest_name = NULL;
dest_address = "unix:abstract=/com/ubuntu/upstart/test";
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 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 ();
}
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 (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 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_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE);
TEST_EQ_STR (property, "processes");
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);
waitpid (proc_pid, &status, 0);
TEST_TRUE (WIFSIGNALED (status));
TEST_EQ (WTERMSIG (status), SIGHUP);
}
/* 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 (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, 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 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_EQ_STR (interface, DBUS_INTERFACE_UPSTART_INSTANCE);
TEST_EQ_STR (property, "processes");
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] = "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);
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);
waitpid (proc_pid, &status, 0);
TEST_TRUE (WIFSIGNALED (status));
TEST_EQ (WTERMSIG (status), SIGHUP);
}
/* 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 (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 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 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/foo");
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_INSTANCE);
TEST_EQ_STR (property, "processes");
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] = 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);
waitpid (proc_pid, &status, 0);
TEST_TRUE (WIFSIGNALED (status));
TEST_EQ (WTERMSIG (status), SIGHUP);
}
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 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_show_config (void)
{
char dirname[PATH_MAX];
nih_local char *cmd;
pid_t upstart_pid;
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);
START_UPSTART (upstart_pid);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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 show-config foo 2>&1", INITCTL_BINARY);
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", INITCTL_BINARY);
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);
}
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 ();
}
/**
* in_chroot:
*
* Determine if running inside a chroot environment.
*
* Failures are fatal.
*
* Returns TRUE if within a chroot, else FALSE.
**/
int
in_chroot (void)
{
struct stat st;
int i;
char dir[] = "/";
i = stat(dir, &st);
if ( i != 0 ) {
fprintf (stderr, "ERROR: cannot stat '%s'\n", dir);
exit (EXIT_FAILURE);
}
if ( st.st_ino == 2 )
return FALSE;
return TRUE;
}
/**
* dbus_configured
*
* Determine if D-Bus has been configured (with dbus-uuidgen).
*
* Returns TRUE if D-Bus appears to have been configured,
* else FALSE.
**/
int
dbus_configured (void)
{
struct stat st;
char path[] = "/var/lib/dbus/machine-id";
return !stat (path, &st);
}
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_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 ();
if (in_chroot () && !dbus_configured ()) {
fprintf(stderr, "\n\n"
"WARNING: not running show-config "
"and check-config tests within chroot "
"as no D-Bus, or D-Bus not configured (lp:#728988)"
"\n\n");
} else {
test_show_config ();
}
return 0;
}