[gnome-desktop-testing/wip/functional] Some work on functional testing and core dump export
- From: Colin Walters <walters src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-desktop-testing/wip/functional] Some work on functional testing and core dump export
- Date: Sun, 26 May 2013 20:29:55 +0000 (UTC)
commit e44405ad1a1ea9b5c19a209e94e9e872c628198f
Author: Colin Walters <walters verbum org>
Date: Sun May 26 21:29:33 2013 +0100
Some work on functional testing and core dump export
Makefile-tests.am | 9 ++
src/gnome-ostree-systemd-coredump-export.c | 137 ++++++++++++++++++++++++++++
tests/functional/shelleval.js | 26 +++++
tests/functional/startstopapps.js | 80 ++++++++++++++++
4 files changed, 252 insertions(+), 0 deletions(-)
---
diff --git a/Makefile-tests.am b/Makefile-tests.am
index fd246a4..0f131ea 100644
--- a/Makefile-tests.am
+++ b/Makefile-tests.am
@@ -20,3 +20,12 @@ gnome_desktop_testing_runner_SOURCES = src/gnome-desktop-testing-runner.c
gnome_desktop_testing_runner_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/libgsystem
gnome_desktop_testing_runner_CFLAGS = $(GIO_UNIX_CFLAGS)
gnome_desktop_testing_runner_LDADD = $(GIO_UNIX_LIBS) libgsystem.la
+
+if ENABLE_SYSTEMD_JOURNAL
+bin_PROGRAMS += gnome-ostree-systemd-coredump-export
+endif
+gnome_ostree_systemd_coredump_export_SOURCES = src/gnome-ostree-systemd-coredump-export.c
+gnome_ostree_systemd_coredump_export_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/libgsystem
+gnome_ostree_systemd_coredump_export_CFLAGS = $(GIO_UNIX_CFLAGS)
+gnome_ostree_systemd_coredump_export_LDADD = $(GIO_UNIX_LIBS) libgsystem.la
+
diff --git a/src/gnome-ostree-systemd-coredump-export.c b/src/gnome-ostree-systemd-coredump-export.c
new file mode 100644
index 0000000..4251310
--- /dev/null
+++ b/src/gnome-ostree-systemd-coredump-export.c
@@ -0,0 +1,137 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2013 Colin Walters <walters verbum org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gio.h>
+#include <json-glib.h>
+#include "libgsystem.h"
+
+static gboolean
+export_one_coredump (GDataOutputStream *dataout,
+ const char *coredump_pid_str,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gs_unref_object GSSubproessContext *proc_context = NULL;
+ gs_unref_object GSSubproess *proc = NULL;
+ char *coredumpctl_argv = { "systemd-coredumpctl", "dump", NULL /* pid */, NULL };
+ gs_unref_object GInputStream *dump_stdin = NULL;
+ GBytes *bytes = NULL;
+
+ coredumpctl_argv[2] = coredump_pid_str;
+ proc_context = gs_subprocess_context_new (coredumpctl_argv);
+ gs_subprocess_context_set_stdout_disposition (proc_context, GS_SUBPROCESS_STREAM_DISPOSITION_PIPE);
+
+ proc = gs_subprocess_new (proc_context, NULL, error);
+ if (!proc)
+ goto out;
+
+ dump_stdin = gs_subprocess_get_stdout (proc);
+ while ((bytes = g_data_input_stream_read_bytes (dump_stdin, 4096,
+ cancellable, error)) != NULL)
+ {
+ GVariant *
+ g_clear_pointer (&bytes, g_bytes_unref);
+ }
+
+ ret = TRUE;
+ out:
+ g_clear_pointer (&bytes, g_bytes_unref);
+ return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+ GError *local_error = NULL;
+ GError **error = &local_error;
+ gs_unref_object GCancellable *cancellable = NULL;
+ char* journal_argv[] = { "journalctl", "-o", "json", "-b", "--no-tail",
+ "_MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", NULL };
+ gs_unref_object GInputStream *journal_in = NULL;
+ gs_unref_object GFile *virtio_file = NULL;
+ gs_unref_object GUnixOutputStream *virtio = NULL;
+ gs_unref_object GDataOutputStream *dataout = NULL;
+ gs_unref_object GDataInputStream *datain = NULL;
+ const char *virtio_path = "/dev/virtio-ports/org.gnome.ostree.coredump";
+
+ virtio_file = g_file_new_for_path (virtio_path);
+ if (!g_file_query_exists (virtio_file, NULL))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Unable to find virtio channel %s", virtio_path);
+ goto out;
+ }
+ virtio = g_file_append_to (virtio_file, 0, cancellable, error);
+ dataout = g_data_output_stream_new (virtio);
+
+ if (!g_spawn_async_with_pipes (NULL, journal_argv, NULL,
+ G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL,
+ &pid, NULL,
+ &stdout_fd, NULL, error))
+ goto out;
+
+ journal_in = g_unix_input_stream_new (stdout_fd, TRUE);
+ datain = g_data_input_stream_new (journal_in);
+
+ while (TRUE)
+ {
+ gsize len;
+ GError *tmp_error = NULL;
+ gs_free char *line = g_data_input_stream_read_line_utf8 (datain, &len, NULL, &tmp_error);
+ gs_unref_object JsonParser *parser = NULL;
+ JsonNode *root;
+ JsonObject *rootobj;
+ const char *coredump_pid_str;
+ guint64 coredump_pid;
+
+ if (tmp_error != NULL)
+ {
+ g_propagate_error (error, tmp_error);
+ goto out;
+ }
+
+ parser = json_parser_new ();
+ if (!json_parser_load_from_data (parser, line, len, error))
+ goto out;
+
+ root = json_parser_get_root (parser);
+ if (json_node_get_node_type (root) != JSON_NODE_OBJECT)
+ continue;
+ rootobj = json_node_get_object (root);
+
+ coredump_pid_str = json_object_get_string_member (rootobj, "COREDUMP_PID");
+ if (coredump_pid_str == NULL)
+ continue;
+
+ coredump_pid = g_ascii_strtoull (coredump_pid_str, NULL, 10);
+ if (!export_one_coredump (dataout, coredump_pid))
+ goto out;
+ }
+
+ out:
+ if (local_error)
+ {
+ g_printerr ("%s\n", local_error->message);
+ g_clear_error (&local_error);
+ return 1;
+ }
+ return 0;
+}
diff --git a/tests/functional/shelleval.js b/tests/functional/shelleval.js
new file mode 100755
index 0000000..a178cdc
--- /dev/null
+++ b/tests/functional/shelleval.js
@@ -0,0 +1,26 @@
+#!/usr/bin/env gjs
+
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+
+const sessionBus = Gio.bus_get_sync(Gio.BusType.SESSION, null);
+
+function shellEval(shell, code, cancellable) {
+ let res = shell.call_sync("Eval", GLib.Variant.new("(s)", [code]), 0, -1,
+ cancellable).deep_unpack();
+ let [success, result] = res;
+ if (!success)
+ throw new Error("Failed to eval " + code.substr(0, 10));
+ return JSON.parse(result);
+}
+
+function main() {
+ let cancellable = null;
+ let shell = Gio.DBusProxy.new_sync(sessionBus, 0, null,
+ "org.gnome.Shell", "/org/gnome/Shell",
+ "org.gnome.Shell", cancellable);
+
+ print(shellEval(shell, ARGV[0], cancellable));
+}
+
+main();
diff --git a/tests/functional/startstopapps.js b/tests/functional/startstopapps.js
new file mode 100755
index 0000000..54c681e
--- /dev/null
+++ b/tests/functional/startstopapps.js
@@ -0,0 +1,80 @@
+#!/usr/bin/env gjs
+
+const GLib = imports.gi.GLib;
+const GObject = imports.gi.GObject;
+const Gio = imports.gi.Gio;
+
+const sessionBus = Gio.bus_get_sync(Gio.BusType.SESSION, null);
+
+const CLOSE_APPS = '%{apps}.forEach(function (id) {
Shell.AppSystem.get_default().lookup_app(id).request_quit(); });';
+const GET_APP_IDS = 'Shell.AppSystem.get_default().get_running().map(function (a) { return a.get_id(); });';
+
+const StartStopApps = new GObject.Class({
+ Name: 'StartStopApps',
+
+ _init: function(props) {
+ this._shell = Gio.DBusProxy.new_sync(sessionBus, 0, null,
+ "org.gnome.Shell", "/org/gnome/Shell",
+ "org.gnome.Shell", null);
+ },
+
+ _shellEval: function(code, cancellable) {
+ let res = this._shell.call_sync("Eval", GLib.Variant.new("(s)", [code]), 0, -1,
+ cancellable).deep_unpack();
+ let [success, result] = res;
+ if (!success)
+ throw new Error("Failed to eval " + code.substr(0, 20));
+ return result ? JSON.parse(result) : null;
+ },
+
+ _awaitRunningApp: function(appId, cancellable) {
+ let timeoutSecs = 10;
+ let i = 0;
+ for (let i = 0; i < timeoutSecs; i++) {
+ let runningApps = this._shellEval(GET_APP_IDS, cancellable);
+ for (let i = 0; i < runningApps.length; i++) {
+ if (runningApps[i] == appId)
+ return;
+ }
+ GLib.usleep(GLib.USEC_PER_SEC);
+ }
+ throw new Error("Failed to find running app " + appId + " after " + timeoutSecs + "s");
+ },
+
+ _testOneApp: function(app, cancellable) {
+ let appId = app.get_id();
+ print("testing appid=" + appId);
+ app.launch([], cancellable);
+ this._awaitRunningApp(appId, cancellable);
+ this._shellEval(CLOSE_APPS.replace('%{apps}', JSON.stringify([appId])), cancellable);
+ },
+
+ run: function(cancellable) {
+ let allApps = Gio.AppInfo.get_all();
+
+ let runningApps = this._shellEval(GET_APP_IDS, cancellable);
+ print("Closing running apps: " + runningApps);
+ this._shellEval(CLOSE_APPS.replace('%{apps}', JSON.stringify(runningApps)), cancellable);
+
+ for (let i = 0; i < allApps.length; i++) {
+ let app = allApps[i];
+ if (app.get_nodisplay())
+ continue;
+ // Ok, a gross hack; we should really be using gnome-menus
+ // to look up all apps. Or maybe fix Gio?
+ if (app.has_key('Categories') &&
+ app.get_string('Categories').indexOf('X-GNOME-Settings-Panel') >= 0)
+ continue;
+ this._testOneApp(app, cancellable);
+ }
+ }
+});
+
+function main() {
+ let cancellable = null;
+
+ let startstopapps = new StartStopApps();
+ startstopapps.run(cancellable);
+}
+
+main();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]