Back to index

dbus-test-runner  12.10.0
process.c
Go to the documentation of this file.
00001 /*
00002 Copyright 2012 Canonical Ltd.
00003 
00004 Authors:
00005     Ted Gould <ted@canonical.com>
00006 
00007 This program is free software: you can redistribute it and/or modify it 
00008 under the terms of the GNU General Public License version 3, as published 
00009 by the Free Software Foundation.
00010 
00011 This program is distributed in the hope that it will be useful, but 
00012 WITHOUT ANY WARRANTY; without even the implied warranties of 
00013 MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
00014 PURPOSE.  See the GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License along 
00017 with this program.  If not, see <http://www.gnu.org/licenses/>.
00018 */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 #include "config.h"
00022 #endif
00023 
00024 #include "dbus-test.h"
00025 
00026 struct _DbusTestProcessPrivate {
00027        gchar * executable;
00028        GList * parameters;
00029 
00030        GPid pid;
00031        guint io_watch;
00032        guint watcher;
00033 
00034        gboolean complete;
00035        gint status;
00036 };
00037 
00038 #define DBUS_TEST_PROCESS_GET_PRIVATE(o) \
00039 (G_TYPE_INSTANCE_GET_PRIVATE ((o), DBUS_TEST_TYPE_PROCESS, DbusTestProcessPrivate))
00040 
00041 static void dbus_test_process_class_init (DbusTestProcessClass *klass);
00042 static void dbus_test_process_init       (DbusTestProcess *self);
00043 static void dbus_test_process_dispose    (GObject *object);
00044 static void dbus_test_process_finalize   (GObject *object);
00045 static void process_run                  (DbusTestTask * task);
00046 static DbusTestTaskState get_state       (DbusTestTask * task);
00047 static gboolean get_passed               (DbusTestTask * task);
00048 
00049 G_DEFINE_TYPE (DbusTestProcess, dbus_test_process, DBUS_TEST_TYPE_TASK);
00050 
00051 static void
00052 dbus_test_process_class_init (DbusTestProcessClass *klass)
00053 {
00054        GObjectClass *object_class = G_OBJECT_CLASS (klass);
00055 
00056        g_type_class_add_private (klass, sizeof (DbusTestProcessPrivate));
00057 
00058        object_class->dispose = dbus_test_process_dispose;
00059        object_class->finalize = dbus_test_process_finalize;
00060 
00061        DbusTestTaskClass * task_class = DBUS_TEST_TASK_CLASS(klass);
00062 
00063        task_class->run = process_run;
00064        task_class->get_state = get_state;
00065        task_class->get_passed = get_passed;
00066 
00067        return;
00068 }
00069 
00070 static void
00071 dbus_test_process_init (DbusTestProcess *self)
00072 {
00073        self->priv = DBUS_TEST_PROCESS_GET_PRIVATE(self);
00074 
00075        self->priv->executable = NULL;
00076        self->priv->parameters = NULL;
00077 
00078        return;
00079 }
00080 
00081 static void
00082 dbus_test_process_dispose (GObject *object)
00083 {
00084        g_return_if_fail(DBUS_TEST_IS_PROCESS(object));
00085        DbusTestProcess * process = DBUS_TEST_PROCESS(object);
00086 
00087        if (process->priv->io_watch != 0) {
00088               g_source_remove(process->priv->io_watch);
00089               process->priv->io_watch = 0;
00090        }
00091 
00092        if (process->priv->watcher != 0) {
00093               g_source_remove(process->priv->watcher);
00094               process->priv->watcher = 0;
00095        }
00096 
00097        if (process->priv->pid != 0) {
00098               gchar * killstr = g_strdup_printf("kill -9 %d", process->priv->pid);
00099               g_spawn_command_line_async(killstr, NULL);
00100               g_free(killstr);
00101 
00102               g_spawn_close_pid(process->priv->pid);
00103               process->priv->pid = 0;
00104        }
00105 
00106        G_OBJECT_CLASS (dbus_test_process_parent_class)->dispose (object);
00107        return;
00108 }
00109 
00110 static void
00111 dbus_test_process_finalize (GObject *object)
00112 {
00113        g_return_if_fail(DBUS_TEST_IS_PROCESS(object));
00114        DbusTestProcess * process = DBUS_TEST_PROCESS(object);
00115 
00116        g_free(process->priv->executable);
00117        process->priv->executable = NULL;
00118 
00119        g_list_free_full(process->priv->parameters, g_free);
00120        process->priv->parameters = NULL;
00121 
00122        G_OBJECT_CLASS (dbus_test_process_parent_class)->finalize (object);
00123        return;
00124 }
00125 
00126 static void
00127 proc_watcher (GPid pid, gint status, gpointer data)
00128 {
00129        g_return_if_fail(DBUS_TEST_IS_PROCESS(data));
00130        DbusTestProcess * process = DBUS_TEST_PROCESS(data);
00131 
00132        if (pid != 0) {
00133               g_spawn_close_pid(pid);
00134               process->priv->pid = 0;
00135        }
00136 
00137        process->priv->complete = TRUE;
00138        process->priv->status = status;
00139 
00140        g_signal_emit_by_name(G_OBJECT(process), DBUS_TEST_TASK_SIGNAL_STATE_CHANGED, DBUS_TEST_TASK_STATE_FINISHED, NULL);
00141 
00142        return;
00143 }
00144 
00145 static gboolean
00146 proc_writes (GIOChannel * channel, GIOCondition condition, gpointer data)
00147 {
00148        g_return_val_if_fail(DBUS_TEST_IS_PROCESS(data), FALSE);
00149        DbusTestProcess * process = DBUS_TEST_PROCESS(data);
00150 
00151        gchar * line;
00152        gsize termloc;
00153        gboolean done = FALSE;
00154 
00155        do {
00156               GIOStatus status = g_io_channel_read_line (channel, &line, NULL, &termloc, NULL);
00157 
00158               if (status == G_IO_STATUS_EOF) {
00159                      done = TRUE;
00160                      continue;
00161               }
00162 
00163               if (status != G_IO_STATUS_NORMAL) {
00164                      continue;
00165               }
00166 
00167               line[termloc] = '\0';
00168 
00169               dbus_test_task_print(DBUS_TEST_TASK(process), line);
00170               g_free(line);
00171        } while (G_IO_IN & g_io_channel_get_buffer_condition(channel));
00172 
00173        if (done) {
00174               process->priv->complete = TRUE;
00175               process->priv->status = -1;
00176 
00177               g_signal_emit_by_name(G_OBJECT(process), DBUS_TEST_TASK_SIGNAL_STATE_CHANGED, DBUS_TEST_TASK_STATE_FINISHED, NULL);
00178        }
00179 
00180        return TRUE;
00181 }
00182 
00183 static void
00184 process_run (DbusTestTask * task)
00185 {
00186        g_return_if_fail(DBUS_TEST_IS_PROCESS(task));
00187        DbusTestProcess * process = DBUS_TEST_PROCESS(task);
00188 
00189        gchar ** argv;
00190        argv = g_new0(gchar *, g_list_length(process->priv->parameters) + 2);
00191 
00192        argv[0] = process->priv->executable;
00193        int i;
00194        for (i = 0; i < g_list_length(process->priv->parameters); i++) {
00195               argv[i + 1] = (gchar *)g_list_nth(process->priv->parameters, i)->data;
00196        }
00197 
00198        GError * error = NULL;
00199        gint proc_stdout;
00200        g_spawn_async_with_pipes(g_get_current_dir(),
00201                                 argv, /* argv */
00202                                 NULL, /* envp */
00203                                 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, /* flags */
00204                                 NULL, /* child setup func */
00205                                 NULL, /* child setup data */
00206                                                   &(process->priv->pid), /* PID */
00207                                 NULL, /* stdin */
00208                                 &proc_stdout, /* stdout */
00209                                 NULL, /* stderr */
00210                                 &error); /* error */
00211        g_free(argv);
00212 
00213        if (error != NULL) {
00214               g_warning("Unable to start process '%s': %s", process->priv->executable, error->message);
00215               process->priv->complete = TRUE;
00216               process->priv->status = -1;
00217               g_signal_emit_by_name(G_OBJECT(process), DBUS_TEST_TASK_SIGNAL_STATE_CHANGED, DBUS_TEST_TASK_STATE_FINISHED, NULL);
00218               return;
00219        }
00220 
00221        if (TRUE) {
00222               gchar * message = g_strdup_printf("Started with PID: %d", process->priv->pid);
00223               dbus_test_task_print(task, message);
00224               g_free(message);
00225        }
00226 
00227        GIOChannel * iochan = g_io_channel_unix_new(proc_stdout);
00228        g_io_channel_set_buffer_size(iochan, 10 * 1024 * 1024); /* 10 MB should be enough for anyone */
00229        process->priv->io_watch = g_io_add_watch(iochan,
00230                                                 G_IO_IN, /* conditions */
00231                                                 proc_writes, /* func */
00232                                                 process); /* func data */
00233        g_io_channel_unref(iochan);
00234 
00235        process->priv->watcher = g_child_watch_add(process->priv->pid, proc_watcher, process);
00236 
00237        g_signal_emit_by_name(G_OBJECT(process), DBUS_TEST_TASK_SIGNAL_STATE_CHANGED, DBUS_TEST_TASK_STATE_RUNNING, NULL);
00238 
00239        return;
00240 }
00241 
00242 DbusTestProcess *
00243 dbus_test_process_new (const gchar * executable)
00244 {
00245        g_return_val_if_fail(executable != NULL, NULL);
00246 
00247        DbusTestProcess * proc = g_object_new(DBUS_TEST_TYPE_PROCESS,
00248                                              NULL);
00249 
00250        proc->priv->executable = g_strdup(executable);
00251 
00252        return proc;
00253 }
00254 
00255 void
00256 dbus_test_process_append_param (DbusTestProcess * process, const gchar * parameter)
00257 {
00258        g_return_if_fail(DBUS_TEST_IS_PROCESS(process));
00259        g_return_if_fail(parameter != NULL);
00260 
00261        process->priv->parameters = g_list_append(process->priv->parameters, g_strdup(parameter));
00262 
00263        return;
00264 }
00265 
00266 static DbusTestTaskState
00267 get_state (DbusTestTask * task)
00268 {
00269        g_return_val_if_fail(DBUS_TEST_IS_PROCESS(task), DBUS_TEST_TASK_STATE_FINISHED);
00270        DbusTestProcess * process = DBUS_TEST_PROCESS(task);
00271 
00272        if (process->priv->complete) {
00273               return DBUS_TEST_TASK_STATE_FINISHED;
00274        }
00275 
00276        if (process->priv->pid != 0) {
00277               return DBUS_TEST_TASK_STATE_RUNNING;
00278        }
00279 
00280        return DBUS_TEST_TASK_STATE_INIT;
00281 }
00282 
00283 static gboolean
00284 get_passed (DbusTestTask * task)
00285 {
00286        g_return_val_if_fail(DBUS_TEST_IS_PROCESS(task), FALSE);
00287        DbusTestProcess * process = DBUS_TEST_PROCESS(task);
00288 
00289        if (!process->priv->complete) {
00290               return FALSE;
00291        }
00292 
00293        if (process->priv->status == 0) {
00294               return TRUE;
00295        }
00296 
00297        return FALSE;
00298 }