/*
* This file is part of Cockpit.
*
* Copyright (C) 2017 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 "cockpitchannel.h"
#include "cockpitrouter.h"
#include "mock-channel.h"
#include "mock-transport.h"
#include "common/cockpitjson.h"
#include "common/cockpittest.h"
#include
#include
#include
/* Mock override from cockpitrouter.c */
extern guint cockpit_router_bridge_timeout;
typedef struct {
MockTransport *transport;
JsonObject *mock_match;
JsonObject *mock_config;
} TestCase;
typedef struct {
const gchar *payload;
gboolean with_env;
const gchar *problem;
const gchar *bridge;
} TestFixture;
static void
setup (TestCase *tc,
gconstpointer user_data)
{
const TestFixture *fixture = user_data;
JsonArray *argv;
gchar *argument;
const gchar *payload;
const gchar *bridge;
tc->mock_config = json_object_new ();
argv = json_array_new ();
bridge = BUILDDIR "/mock-bridge";
if (fixture && fixture->bridge)
bridge = fixture->bridge;
json_array_add_string_element (argv, bridge);
payload = "upper";
if (fixture && fixture->payload)
payload = fixture->payload;
argument = g_strdup_printf ("--%s", payload);
json_array_add_string_element (argv, argument);
g_free (argument);
json_object_set_array_member (tc->mock_config, "spawn", argv);
tc->mock_match = json_object_new ();
json_object_set_string_member (tc->mock_match, "payload", payload);
tc->transport = g_object_new (mock_transport_get_type (), NULL);
while (g_main_context_iteration (NULL, FALSE));
}
static void
setup_dynamic (TestCase *tc,
gconstpointer user_data)
{
const TestFixture *fixture = user_data;
JsonArray *argv;
JsonArray *env;
JsonObject *match;
tc->mock_config = json_object_new ();
argv = json_array_new ();
match = json_object_new ();
json_array_add_string_element (argv, BUILDDIR "/mock-bridge");
json_array_add_string_element (argv, "--${payload}");
json_array_add_string_element (argv, "--count");
json_object_set_array_member (tc->mock_config, "spawn", argv);
if (fixture && fixture->problem)
json_object_set_string_member (tc->mock_config, "problem", fixture->problem);
if (fixture && fixture->with_env)
{
env = json_array_new ();
json_array_add_string_element (env, "COCKPIT_TEST_PARAM_ENV=${payload}");
json_object_set_array_member (tc->mock_config, "environ", env);
}
json_object_set_null_member (match, "payload");
json_object_set_object_member (tc->mock_config, "match", match);
tc->transport = g_object_new (mock_transport_get_type (), NULL);
while (g_main_context_iteration (NULL, FALSE));
}
static void
teardown (TestCase *tc,
gconstpointer unused)
{
cockpit_assert_expected ();
g_object_add_weak_pointer (G_OBJECT (tc->transport), (gpointer *)&tc->transport);
g_object_unref (tc->transport);
g_assert (tc->transport == NULL);
json_object_unref (tc->mock_config);
if (tc->mock_match)
json_object_unref (tc->mock_match);
}
static void
emit_string (TestCase *tc,
const gchar *channel,
const gchar *string)
{
GBytes *bytes = g_bytes_new (string, strlen (string));
cockpit_transport_emit_recv (COCKPIT_TRANSPORT (tc->transport), channel, bytes);
g_bytes_unref (bytes);
}
static void
on_transport_closed (CockpitTransport *transport,
const gchar *problem,
gpointer user_data)
{
gchar **retval = user_data;
g_assert (*retval == NULL);
*retval = g_strdup (problem);
}
static void
test_local_channel (TestCase *tc,
gconstpointer unused)
{
CockpitRouter *router;
GBytes *sent;
static CockpitPayloadType payload_types[] = {
{ "echo", mock_echo_channel_get_type },
{ NULL },
};
router = cockpit_router_new (COCKPIT_TRANSPORT (tc->transport), payload_types, NULL);
emit_string (tc, NULL, "{\"command\": \"init\", \"version\": 1, \"host\": \"localhost\" }");
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"echo\"}");
emit_string (tc, "a", "oh marmalade");
while ((sent = mock_transport_pop_channel (tc->transport, "a")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "oh marmalade", -1);
g_object_unref (router);
}
static void
test_external_bridge (TestCase *tc,
gconstpointer unused)
{
CockpitRouter *router;
GBytes *sent;
JsonObject *control;
CockpitTransport *shim_transport = NULL;
gchar *problem = NULL;
CockpitPeer *peer;
/* Same argv as used by mock_shim */
router = cockpit_router_new (COCKPIT_TRANSPORT (tc->transport), NULL, NULL);
peer = cockpit_peer_new (COCKPIT_TRANSPORT (tc->transport), tc->mock_config);
cockpit_router_add_peer (router, tc->mock_match, peer);
emit_string (tc, NULL, "{\"command\": \"init\", \"version\": 1, \"host\": \"localhost\" }");
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"upper\"}");
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"b\", \"payload\": \"upper\"}");
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"c\", \"payload\": \"upper\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"ready\",\"channel\":\"a\"}");
control = NULL;
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"ready\",\"channel\":\"b\"}");
control = NULL;
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"ready\",\"channel\":\"c\"}");
control = NULL;
emit_string (tc, "a", "oh marmalade a");
while ((sent = mock_transport_pop_channel (tc->transport, "a")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "OH MARMALADE A", -1);
sent = NULL;
/* Get a ref of the shim transport */
shim_transport = cockpit_peer_ensure (peer);
g_object_ref (shim_transport);
g_signal_connect (shim_transport, "closed", G_CALLBACK (on_transport_closed), &problem);
emit_string (tc, NULL, "{\"command\": \"close\", \"channel\": \"a\" }");
emit_string (tc, "b", "oh marmalade b");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"close\",\"channel\":\"a\"}");
control = NULL;
while ((sent = mock_transport_pop_channel (tc->transport, "b")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "OH MARMALADE B", -1);
g_assert_null (problem);
sent = NULL;
emit_string (tc, NULL, "{\"command\": \"close-later\", \"channel\": \"b\" }");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"close\",\"channel\":\"b\",\"problem\":\"closed\"}");
control = NULL;
g_object_unref (peer);
g_object_unref (router);
g_object_unref (shim_transport);
}
static const TestFixture fixture_fail = {
.payload = "bad"
};
static void
test_external_fail (TestCase *tc,
gconstpointer user_data)
{
CockpitRouter *router;
JsonObject *received;
CockpitPeer *peer;
g_assert (user_data == &fixture_fail);
router = cockpit_router_new (COCKPIT_TRANSPORT (tc->transport), NULL, NULL);
peer = cockpit_peer_new (COCKPIT_TRANSPORT (tc->transport), tc->mock_config);
cockpit_router_add_peer (router, tc->mock_match, peer);
g_object_unref (peer);
emit_string (tc, NULL, "{\"command\": \"init\", \"version\": 1, \"host\": \"localhost\" }");
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"bad\"}");
emit_string (tc, "a", "oh marmalade");
while ((received = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (received, "{\"command\": \"close\", \"channel\": \"a\", \"problem\": \"not-supported\"}");
g_object_unref (router);
}
static const TestFixture fixture_dyn_fail = {
.problem = "bad"
};
static void
test_dynamic_fail (TestCase *tc,
gconstpointer user_data)
{
CockpitRouter *router;
JsonObject *received;
g_assert (user_data == &fixture_dyn_fail);
router = cockpit_router_new (COCKPIT_TRANSPORT (tc->transport), NULL, NULL);
cockpit_router_add_bridge (router, tc->mock_config);
emit_string (tc, NULL, "{\"command\": \"init\", \"version\": 1, \"host\": \"localhost\" }");
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"bad\"}");
emit_string (tc, "a", "oh marmalade");
while ((received = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (received, "{\"command\": \"close\", \"channel\": \"a\", \"problem\": \"bad\"}");
g_object_unref (router);
}
static const TestFixture fixture_env = {
.with_env = TRUE
};
static void
check_ready (JsonObject *control,
const gchar *channel,
const gchar *payload,
gint count,
gboolean with_env)
{
g_assert_cmpstr (json_object_get_string_member (control, "channel"), ==, channel);
g_assert_cmpstr (json_object_get_string_member (control, "command"), ==, "ready");
g_assert_cmpint (json_object_get_int_member (control, "count"), ==, count);
if (with_env)
g_assert_cmpstr (json_object_get_string_member (control, "test-env"), ==, payload);
}
static void
test_dynamic_bridge (TestCase *tc,
gconstpointer user_data)
{
const TestFixture *fixture = user_data;
CockpitRouter *router;
GBytes *sent;
JsonObject *control;
router = cockpit_router_new (COCKPIT_TRANSPORT (tc->transport), NULL, NULL);
cockpit_router_add_bridge (router, tc->mock_config);
emit_string (tc, NULL, "{\"command\": \"init\", \"version\": 1, \"host\": \"localhost\" }");
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"upper\"}");
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"b\", \"payload\": \"upper\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
check_ready (control, "a", "upper", 0, fixture ? fixture->with_env : FALSE);
control = NULL;
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
check_ready (control, "b", "upper", 1, fixture ? fixture->with_env : FALSE);
control = NULL;
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"c\", \"payload\": \"lower\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
check_ready (control, "c", "lower", 0, fixture ? fixture->with_env : FALSE);
control = NULL;
emit_string (tc, "a", "oh marmalade a");
while ((sent = mock_transport_pop_channel (tc->transport, "a")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "OH MARMALADE A", -1);
sent = NULL;
emit_string (tc, NULL, "{\"command\": \"close\", \"channel\": \"a\" }");
emit_string (tc, "b", "oh marmalade b");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"close\",\"channel\":\"a\"}");
control = NULL;
while ((sent = mock_transport_pop_channel (tc->transport, "b")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "OH MARMALADE B", -1);
sent = NULL;
emit_string (tc, NULL, "{\"command\": \"close\", \"channel\": \"b\" }");
emit_string (tc, "c", "OH MARMALADE C");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"close\",\"channel\":\"b\"}");
control = NULL;
while ((sent = mock_transport_pop_channel (tc->transport, "c")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "oh marmalade c", -1);
sent = NULL;
emit_string (tc, NULL, "{\"command\": \"close-later\", \"channel\": \"c\" }");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"close\",\"channel\":\"c\",\"problem\":\"closed\"}");
control = NULL;
g_object_unref (router);
}
static const TestFixture fixture_host = {
.payload = "host",
.bridge = BUILDDIR "/mock-echo"
};
static void
check_unchanged_host (TestCase *tc,
const gchar *host)
{
JsonObject *control;
gchar *msg = g_strdup_printf ("{\"command\": \"open\", \"channel\": \"a%s\", \"payload\": \"host\", \"host\": \"%s\"}", host, host);
emit_string (tc, NULL, msg);
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, msg);
control = NULL;
g_free (msg);
}
static void
test_host_processing (TestCase *tc,
gconstpointer user_data)
{
JsonObject *control;
CockpitRouter *router;
CockpitPeer *peer;
g_assert (user_data == &fixture_host);
router = cockpit_router_new (COCKPIT_TRANSPORT (tc->transport), NULL, NULL);
peer = cockpit_peer_new (COCKPIT_TRANSPORT (tc->transport), tc->mock_config);
cockpit_router_add_peer (router, tc->mock_match, peer);
g_object_unref (peer);
emit_string (tc, NULL, "{\"command\": \"init\", \"version\": 1, \"host\": \"localhost\" }");
check_unchanged_host (tc, "host");
check_unchanged_host (tc, "host+");
check_unchanged_host (tc, "host+key");
check_unchanged_host (tc, "host+key+");
/* Test localhost is removed */
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host\":\"localhost\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\"}");
control = NULL;
/* Test host-key1 is set to value */
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host\":\"host+key1+value\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"open\",\"channel\":\"a\",\"payload\":\"host\",\"host\":\"host\",\"host-key1\":\"value\"}");
control = NULL;
/* Test with + in value */
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host\":\"host+key1+value+value\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"open\",\"channel\":\"a\",\"payload\":\"host\",\"host\":\"host\",\"host-key1\":\"value+value\"}");
control = NULL;
/* Test localhost is removed but host-key1 present */
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host\":\"localhost+key1+value\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"open\",\"channel\":\"a\",\"payload\":\"host\",\"host-key1\":\"value\"}");
control = NULL;
/* Test doesn't replace host-key1 */
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host\":\"localhost+key1+value\",\"host-key1\":\"extra\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\":\"open\",\"channel\":\"a\",\"payload\":\"host\",\"host\":\"localhost+key1+value\",\"host-key1\":\"extra\"}");
control = NULL;
g_object_unref (router);
}
static void
test_sharable_processing (TestCase *tc,
gconstpointer user_data)
{
JsonObject *control;
CockpitRouter *router;
CockpitPeer *peer;
g_assert (user_data == &fixture_host);
router = cockpit_router_new (COCKPIT_TRANSPORT (tc->transport), NULL, NULL);
peer = cockpit_peer_new (COCKPIT_TRANSPORT (tc->transport), tc->mock_config);
cockpit_router_add_peer (router, tc->mock_match, peer);
g_object_unref (peer);
emit_string (tc, NULL, "{\"command\": \"init\", \"version\": 1, \"host\": \"localhost\" }");
/* Test host-key is private */
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host\":\"localhost\", \"host-key\": \"host-key\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host-key\": \"host-key\", \"session\": \"private\"}");
control = NULL;
/* Test user is private */
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host\":\"localhost\", \"user\": \"user\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"user\": \"user\", \"session\": \"private\"}");
control = NULL;
/* Test user with temp-session false is not private */
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host\":\"localhost\", \"user\": \"user\", \"temp-session\": false}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"user\": \"user\"}");
control = NULL;
/* Test user with sharable is not touched */
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"host\":\"localhost\", \"user\": \"user\", \"session\": \"other\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_json_eq (control, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"host\", \"user\": \"user\", \"session\": \"other\"}");
control = NULL;
g_object_unref (router);
}
static GList *
make_bridge_configs (const gchar *payload, ...)
{
GList *configs = NULL;
va_list ap;
va_start (ap, payload);
while (payload)
{
const gchar *arg = va_arg (ap, const gchar *);
JsonObject *match = json_object_new ();
json_object_set_string_member (match, "payload", payload);
JsonArray *spawn = json_array_new ();
json_array_add_string_element (spawn, BUILDDIR "/mock-bridge");
while (arg)
{
json_array_add_string_element (spawn, arg);
arg = va_arg (ap, const gchar *);
}
JsonObject *config = json_object_new ();
json_object_set_object_member (config, "match", match);
json_object_set_array_member (config, "spawn", spawn);
configs = g_list_prepend (configs, config);
payload = va_arg (ap, const gchar *);
}
va_end (ap);
return g_list_reverse (configs);
}
static void
free_bridge_configs (GList *configs)
{
g_list_free_full (configs, (GDestroyNotify)json_object_unref);
}
static void
test_reload_add (TestCase *tc,
gconstpointer user_data)
{
CockpitRouter *router;
GList *configs;
JsonObject *control;
GBytes *sent;
router = cockpit_router_new (COCKPIT_TRANSPORT (tc->transport), NULL, NULL);
emit_string (tc, NULL, "{\"command\": \"init\", \"version\": 1, \"host\": \"localhost\" }");
// Configure only the "upper" payload
configs = make_bridge_configs ("upper", "--upper", NULL,
NULL);
cockpit_router_set_bridges (router, configs);
free_bridge_configs (configs);
// Open a "upper" channel
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"upper\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpstr (json_object_get_string_member (control, "channel"), ==, "a");
g_assert_cmpstr (json_object_get_string_member (control, "command"), ==, "ready");
control = NULL;
// And check that it works
emit_string (tc, "a", "before reload");
while ((sent = mock_transport_pop_channel (tc->transport, "a")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "BEFORE RELOAD", -1);
sent = NULL;
// Try to open a "lower" channel and check that this is rejected
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"b\", \"payload\": \"lower\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpstr (json_object_get_string_member (control, "channel"), ==, "b");
g_assert_cmpstr (json_object_get_string_member (control, "command"), ==, "close");
g_assert_cmpstr (json_object_get_string_member (control, "problem"), ==, "not-supported");
control = NULL;
// Reconfigure and add the "lower" payload
configs = make_bridge_configs ("upper", "--upper", NULL,
"lower", "--lower", NULL,
NULL);
cockpit_router_set_bridges (router, configs);
free_bridge_configs (configs);
// Check that the "upper" channel still works
emit_string (tc, "a", "after reload");
while ((sent = mock_transport_pop_channel (tc->transport, "a")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "AFTER RELOAD", -1);
sent = NULL;
// Open a "lower" channel
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"c\", \"payload\": \"lower\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpstr (json_object_get_string_member (control, "channel"), ==, "c");
g_assert_cmpstr (json_object_get_string_member (control, "command"), ==, "ready");
control = NULL;
// And check that it now works
emit_string (tc, "c", "NEW PAYLOAD");
while ((sent = mock_transport_pop_channel (tc->transport, "c")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "new payload", -1);
sent = NULL;
g_object_unref (router);
}
static void
test_reload_remove (TestCase *tc,
gconstpointer user_data)
{
CockpitRouter *router;
GList *configs;
JsonObject *control;
GBytes *sent;
router = cockpit_router_new (COCKPIT_TRANSPORT (tc->transport), NULL, NULL);
emit_string (tc, NULL, "{\"command\": \"init\", \"version\": 1, \"host\": \"localhost\" }");
// Configure the "upper" payload
configs = make_bridge_configs ("upper", "--upper", NULL,
NULL);
cockpit_router_set_bridges (router, configs);
free_bridge_configs (configs);
// Open a "upper" channel
emit_string (tc, NULL, "{\"command\": \"open\", \"channel\": \"a\", \"payload\": \"upper\"}");
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpstr (json_object_get_string_member (control, "channel"), ==, "a");
g_assert_cmpstr (json_object_get_string_member (control, "command"), ==, "ready");
control = NULL;
// And check that it works
emit_string (tc, "a", "before reload");
while ((sent = mock_transport_pop_channel (tc->transport, "a")) == NULL)
g_main_context_iteration (NULL, TRUE);
cockpit_assert_bytes_eq (sent, "BEFORE RELOAD", -1);
sent = NULL;
// Reconfigure and remove the "upper" payload
configs = make_bridge_configs (NULL);
cockpit_router_set_bridges (router, configs);
free_bridge_configs (configs);
// Check that the "upper" channel has been closed
while ((control = mock_transport_pop_control (tc->transport)) == NULL)
g_main_context_iteration (NULL, TRUE);
g_assert_cmpstr (json_object_get_string_member (control, "channel"), ==, "a");
g_assert_cmpstr (json_object_get_string_member (control, "command"), ==, "close");
g_assert_cmpstr (json_object_get_string_member (control, "problem"), ==, "terminated");
control = NULL;
g_object_unref (router);
}
int
main (int argc,
char *argv[])
{
cockpit_test_init (&argc, &argv);
g_test_add ("/router/local-channel", TestCase, NULL,
setup, test_local_channel, teardown);
g_test_add ("/router/external-bridge", TestCase, NULL,
setup, test_external_bridge, teardown);
g_test_add ("/router/external-fail", TestCase, &fixture_fail,
setup, test_external_fail, teardown);
g_test_add ("/router/dynamic-bridge-fail", TestCase, &fixture_dyn_fail,
setup_dynamic, test_dynamic_fail, teardown);
g_test_add ("/router/dynamic-bridge", TestCase, NULL,
setup_dynamic, test_dynamic_bridge, teardown);
g_test_add ("/router/dynamic-bridge-env", TestCase, &fixture_env,
setup_dynamic, test_dynamic_bridge, teardown);
g_test_add ("/router/host-processing", TestCase, &fixture_host,
setup, test_host_processing, teardown);
g_test_add ("/router/sharable-processing", TestCase, &fixture_host,
setup, test_sharable_processing, teardown);
g_test_add ("/router/reload/add", TestCase, NULL,
setup, test_reload_add, teardown);
g_test_add ("/router/reload/remove", TestCase, NULL,
setup, test_reload_remove, teardown);
return g_test_run ();
}