/* * This file is part of Cockpit. * * Copyright (C) 2014 Red Hat, Inc. * * Cockpit 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.1 of the License, or * (at your option) any later version. * * Cockpit 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 Cockpit; If not, see . */ #include "config.h" #include "mock-transport.h" #include "common/cockpitjson.h" #include typedef CockpitTransportClass MockTransportClass; typedef struct { gpointer data; GDestroyNotify func; } Trash; G_DEFINE_TYPE (MockTransport, mock_transport, COCKPIT_TYPE_TRANSPORT); static void trash_free (gpointer data) { Trash *trash = data; (trash->func) (trash->data); g_free (trash); } static void trash_push (MockTransport *self, gpointer data, GDestroyNotify func) { Trash *trash = g_new0 (Trash, 1); g_assert (func != NULL); trash->data = data; trash->func = func; self->trash = g_list_prepend (self->trash, trash); } static void mock_transport_init (MockTransport *self) { self->channels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)g_queue_free); self->control = g_queue_new (); } static void mock_transport_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { switch (prop_id) { case 1: g_value_set_string (value, "mock-name"); break; default: g_assert_not_reached (); break; } } static void mock_transport_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { case 1: break; default: g_assert_not_reached (); break; } } static void mock_transport_finalize (GObject *object) { MockTransport *self = (MockTransport *)object; g_free (self->problem); g_queue_free (self->control); g_list_free_full (self->trash, trash_free); g_hash_table_destroy (self->channels); G_OBJECT_CLASS (mock_transport_parent_class)->finalize (object); } static void mock_transport_send (CockpitTransport *transport, const gchar *channel_id, GBytes *data) { MockTransport *self = (MockTransport *)transport; JsonObject *object; GError *error = NULL; GQueue *queue; if (!channel_id) { object = cockpit_json_parse_bytes (data, &error); g_assert_no_error (error); g_queue_push_tail (self->control, object); trash_push (self, object, (GDestroyNotify)json_object_unref); } else { queue = g_hash_table_lookup (self->channels, channel_id); if (!queue) { queue = g_queue_new (); g_hash_table_insert (self->channels, g_strdup (channel_id), queue); } g_queue_push_tail (queue, g_bytes_ref (data)); trash_push (self, data, (GDestroyNotify)g_bytes_unref); } self->count++; } static void mock_transport_close (CockpitTransport *transport, const gchar *problem) { MockTransport *self = (MockTransport *)transport; g_assert (!self->closed); self->problem = g_strdup (problem); self->closed = TRUE; cockpit_transport_emit_closed (transport, problem); } static void mock_transport_class_init (MockTransportClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); CockpitTransportClass *transport_class = COCKPIT_TRANSPORT_CLASS (klass); object_class->finalize = mock_transport_finalize; object_class->get_property = mock_transport_get_property; object_class->set_property = mock_transport_set_property; g_object_class_override_property (object_class, 1, "name"); transport_class->send = mock_transport_send; transport_class->close = mock_transport_close; } MockTransport * mock_transport_new (void) { return g_object_new (MOCK_TYPE_TRANSPORT, NULL); } GBytes * mock_transport_pop_channel (MockTransport *mock, const gchar *channel_id) { GQueue *queue; g_assert (channel_id != NULL); queue = g_hash_table_lookup (mock->channels, channel_id); if (queue) return g_queue_pop_head (queue); return NULL; } JsonObject * mock_transport_pop_control (MockTransport *mock) { return g_queue_pop_head (mock->control); } guint mock_transport_count_sent (MockTransport *mock) { return mock->count; } GBytes * mock_transport_combine_output (MockTransport *transport, const gchar *channel_id, guint *count) { GByteArray *combined; GBytes *block; if (count) *count = 0; combined = g_byte_array_new (); for (;;) { block = mock_transport_pop_channel (transport, channel_id); if (!block) break; g_byte_array_append (combined, g_bytes_get_data (block, NULL), g_bytes_get_size (block)); if (count) (*count)++; } return g_byte_array_free_to_bytes (combined); }