From: Stef Walter Date: Sun, 11 Oct 2009 17:52:54 +0000 (+0000) Subject: [egg] Add spawn with callback functionality. X-Git-Tag: split~294^2~18 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=9344ebcfc31a9d409edbbfb828d12fa83cf997ca;p=platform%2Fupstream%2Fgcr.git [egg] Add spawn with callback functionality. Allows executing an application and getting callbacks when stdin, stdout, or stderr need servicing. --- diff --git a/egg/Makefile.am b/egg/Makefile.am index a0bf0db..1fe0015 100644 --- a/egg/Makefile.am +++ b/egg/Makefile.am @@ -29,6 +29,7 @@ libegg_la_SOURCES = \ egg-openssl.c egg-openssl.h \ egg-unix-credentials.c egg-unix-credentials.h \ egg-secure-memory.c egg-secure-memory.h \ + egg-spawn.c egg-spawn.h \ egg-symkey.c egg-symkey.h \ $(BUILT_SOURCES) diff --git a/egg/tests/Makefile.am b/egg/tests/Makefile.am index f205fae..0de544c 100644 --- a/egg/tests/Makefile.am +++ b/egg/tests/Makefile.am @@ -10,7 +10,8 @@ UNIT_AUTO = \ unit-test-secmem.c \ unit-test-symkey.c \ unit-test-openssl.c \ - unit-test-dh.c + unit-test-dh.c \ + unit-test-spawn.c \ asn1-def-test.h UNIT_PROMPT = diff --git a/egg/tests/test-data/echo-script.sh b/egg/tests/test-data/echo-script.sh new file mode 100644 index 0000000..d3009fb --- /dev/null +++ b/egg/tests/test-data/echo-script.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +count=0 +output="" +while read line; do + output="$output $line" + count=`expr $count + 1` + echo "$count" >&2 +done +echo $output +exit 3 diff --git a/egg/tests/unit-test-spawn.c b/egg/tests/unit-test-spawn.c new file mode 100644 index 0000000..6b38d9b --- /dev/null +++ b/egg/tests/unit-test-spawn.c @@ -0,0 +1,274 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* unit-test-dh.c: Test egg-spawn.c + + Copyright (C) 2009 Stefan Walter + + The Gnome Keyring Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The Gnome Keyring Library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the Gnome Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + + Author: Stef Walter +*/ + +#include +#include +#include + +#include "run-auto-test.h" + +#include "egg-spawn.h" + +#include + +typedef struct _EchoData { + gint index; + gchar *output; + gchar *error; + gboolean finalized; + gboolean completed; + gboolean is_async; + pid_t parent_pid; +} EchoData; + +static gboolean +want_input (gint fd, gpointer user_data) +{ + EchoData *data = user_data; + gchar *buffer; + + g_assert (data); + if (data->index == 85) + return FALSE; + + g_assert (data->index >= 80); + g_assert (data->index < 85); + + buffer = g_strdup_printf ("%d\n", data->index); + if (egg_spawn_write_input (fd, (guchar*)buffer, strlen (buffer)) < 0) + g_assert_not_reached (); + g_free (buffer); + ++data->index; + return TRUE; +} + +static gboolean +have_output (gint fd, gpointer user_data) +{ + EchoData *data = user_data; + gchar buffer[1024]; + gssize length; + gchar *output; + + g_assert (data); + + length = egg_spawn_read_output (fd, (guchar*)buffer, 1023); + g_assert (length >= 0); + + buffer[length] = 0; + output = g_strconcat (data->output ? data->output : "", buffer, NULL); + g_free (data->output); + data->output = output; + + return (length > 0); +} + +static gboolean +have_error (gint fd, gpointer user_data) +{ + EchoData *data = user_data; + gchar buffer[1024]; + gssize length; + gchar *error; + + g_assert (data); + + length = egg_spawn_read_output (fd, (guchar*)buffer, 1023); + g_assert (length >= 0); + + buffer[length] = 0; + error = g_strconcat (data->error ? data->error : "", buffer, NULL); + g_free (data->error); + data->error = error; + + return (length > 0); +} + +static void +completed_func (gpointer user_data) +{ + EchoData *data = user_data; + g_assert (data); + g_assert (!data->finalized); + g_assert (!data->completed); + data->completed = TRUE; + if (data->is_async) + test_mainloop_quit (); +} + +static void +finalize_func (gpointer user_data) +{ + EchoData *data = user_data; + g_assert (!data->finalized); + data->finalized = 1; +} + +static void +child_setup (gpointer user_data) +{ + EchoData *data = user_data; + g_assert (data->parent_pid != getpid ()); +} + +static EggSpawnCallbacks echo_callbacks = { + want_input, + have_output, + have_error, + completed_func, + finalize_func, + child_setup, +}; + +static char* echo_argv[] = { + "/bin/sh", + "./echo-script.sh", + NULL +}; + +static char* error_argv[] = { + "/nonexistent", + NULL +}; + +static EggSpawnCallbacks null_callbacks = { + NULL, + NULL, + NULL, + completed_func, + finalize_func, + child_setup, +}; + +DEFINE_TEST(test_spawn_sync) +{ + GError *error = NULL; + gboolean ret; + gint exit_status; + EchoData data; + GPid pid = 0; + + memset (&data, 0, sizeof (data)); + data.parent_pid = getpid(); + data.index = 80; + + ret = egg_spawn_sync_with_callbacks (test_dir_testdata (), + echo_argv, NULL, 0, &pid, + &echo_callbacks, &data, + &exit_status, &error); + g_assert (ret == TRUE); + g_assert (pid != 0); + g_assert (WIFEXITED (exit_status)); + g_assert (WEXITSTATUS(exit_status) == 3); + g_assert (error == NULL); + g_assert (data.finalized); + g_assert (data.completed); + g_assert_cmpstr (data.output, ==, "80 81 82 83 84\n"); + g_assert_cmpstr (data.error, ==, "1\n2\n3\n4\n5\n"); +} + +DEFINE_TEST(test_spawn_sync_error) +{ + GError *error = NULL; + gboolean ret; + + ret = egg_spawn_sync_with_callbacks (test_dir_testdata (), + error_argv, NULL, 0, NULL, + NULL, NULL, + NULL, &error); + g_assert (ret == FALSE); + g_assert (error != NULL); + g_clear_error (&error); +} + + +DEFINE_TEST(test_spawn_async) +{ + GError *error = NULL; + EchoData data; + guint ret; + GPid pid; + + memset (&data, 0, sizeof (data)); + data.parent_pid = getpid(); + data.index = 80; + data.is_async = TRUE; + + ret = egg_spawn_async_with_callbacks (test_dir_testdata (), + echo_argv, NULL, 0, &pid, + &echo_callbacks, &data, + NULL, &error); + g_assert (ret != 0); + g_assert (error == NULL); + g_assert (!data.finalized); + g_assert (!data.output); + g_assert (!data.completed); + + test_mainloop_run (2000); + + g_assert (data.finalized); + g_assert (data.completed); + g_assert_cmpstr (data.output, ==, "80 81 82 83 84\n"); + g_assert_cmpstr (data.error, ==, "1\n2\n3\n4\n5\n"); +} + +DEFINE_TEST(test_spawn_async_none) +{ + GError *error = NULL; + EchoData data; + guint ret; + + memset (&data, 0, sizeof (data)); + data.parent_pid = getpid(); + data.is_async = TRUE; + + ret = egg_spawn_async_with_callbacks (test_dir_testdata (), + echo_argv, NULL, 0, NULL, + &null_callbacks, &data, + NULL, &error); + g_assert (ret != 0); + g_assert (error == NULL); + g_assert (!data.finalized); + g_assert (!data.completed); + g_assert (!data.output); + + test_mainloop_run (2000); + + g_assert (data.finalized); + g_assert (data.completed); + g_assert (!data.output); +} + +DEFINE_TEST(test_spawn_async_error) +{ + GError *error = NULL; + guint ret; + + ret = egg_spawn_async_with_callbacks (test_dir_testdata (), + error_argv, NULL, 0, NULL, + NULL, NULL, + NULL, &error); + g_assert (ret == 0); + g_assert (error != NULL); + g_clear_error (&error); +}