summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtests/autobahn/autobahn-server.sh14
-rw-r--r--tests/autobahn/fuzzingserver.json8
-rw-r--r--tests/autobahn/meson.build6
-rw-r--r--tests/autobahn/soup-autobahn-test-client.c216
4 files changed, 244 insertions, 0 deletions
diff --git a/tests/autobahn/autobahn-server.sh b/tests/autobahn/autobahn-server.sh
new file mode 100755
index 00000000..b634a767
--- /dev/null
+++ b/tests/autobahn/autobahn-server.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+REPORTS_DIR="${PWD}/reports"
+
+cd "$(dirname "$0")"
+
+[ ! -d "${REPORTS_DIR}" ] && mkdir "${REPORTS_DIR}"
+
+docker run -it --rm \
+ -v "${PWD}:/config" \
+ -v "${REPORTS_DIR}:/reports" \
+ -p 9001:9001 \
+ --name fuzzingserver \
+ crossbario/autobahn-testsuite
diff --git a/tests/autobahn/fuzzingserver.json b/tests/autobahn/fuzzingserver.json
new file mode 100644
index 00000000..4b7fe3bd
--- /dev/null
+++ b/tests/autobahn/fuzzingserver.json
@@ -0,0 +1,8 @@
+{
+ "url": "ws://127.0.0.1:9001",
+ "outdir": "./reports/clients",
+ "cases": ["*"],
+ "exclude-cases": [],
+ "exclude-agent-cases": {}
+}
+
diff --git a/tests/autobahn/meson.build b/tests/autobahn/meson.build
new file mode 100644
index 00000000..20370b0b
--- /dev/null
+++ b/tests/autobahn/meson.build
@@ -0,0 +1,6 @@
+deps = [
+ glib_deps,
+ libsoup_dep
+]
+
+executable('soup-autobahn-test-client', 'soup-autobahn-test-client.c', dependencies: deps)
diff --git a/tests/autobahn/soup-autobahn-test-client.c b/tests/autobahn/soup-autobahn-test-client.c
new file mode 100644
index 00000000..4aa0c58b
--- /dev/null
+++ b/tests/autobahn/soup-autobahn-test-client.c
@@ -0,0 +1,216 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2019 Igalia S.L.
+ */
+
+#include <stdio.h>
+#include <libsoup/soup.h>
+
+GMainLoop *loop;
+static char *address = "ws://localhost:9001";
+static char *agent = "libsoup";
+static unsigned int total_num_cases = 0;
+gboolean running_tests = FALSE;
+
+typedef void (*ConnectionFunc) (SoupWebsocketConnection *socket_connection,
+ gint type,
+ GBytes *message,
+ gpointer data);
+
+typedef struct {
+ ConnectionFunc method;
+ gpointer data;
+} ConnectionContext;
+
+static void run_case (SoupSession *session, const unsigned int test_case);
+
+static gboolean option_run_all = FALSE;
+static int option_run_test = -1;
+static gboolean option_number_of_tests = FALSE;
+static gboolean option_update_report = FALSE;
+static gboolean option_debug = FALSE;
+
+static GOptionEntry entries[] =
+{
+ { "run-all", 'a', 0, G_OPTION_ARG_NONE, &option_run_all, "Run all tests", NULL },
+ { "test", 't', 0, G_OPTION_ARG_INT, &option_run_test, "Run TEST only", "TEST" },
+ { "number-of-tests", 'n', 0, G_OPTION_ARG_NONE, &option_number_of_tests, "Queries the Autobahn server for the number of test cases", NULL },
+ { "update-report", 'r', 0, G_OPTION_ARG_NONE, &option_update_report, "Requests the Autobahn server to update the report for tests", NULL },
+ { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug, "Enables extra debug output", NULL },
+ { NULL }
+};
+
+static void
+on_message_received (SoupWebsocketConnection *socket_connection,
+ gint type, GBytes *message,
+ gpointer data)
+{
+ ConnectionContext *ctx = (ConnectionContext*) data;
+
+ if (option_debug)
+ fprintf (stderr, "<- ");
+
+ if (ctx && ctx->method)
+ ctx->method (socket_connection, type, message, ctx->data);
+}
+
+static void
+on_connection_closed (SoupWebsocketConnection *socket_connection,
+ gpointer data)
+{
+ ConnectionContext *ctx = (ConnectionContext*) data;
+
+ if (option_debug)
+ fprintf (stderr, "\nConnection closed\n");
+
+ if (running_tests)
+ fprintf (stderr, " DONE\n");
+
+ g_free (ctx);
+
+ g_object_unref (socket_connection);
+ g_main_loop_quit (loop);
+}
+
+static void
+on_connect (GObject *session,
+ GAsyncResult *res,
+ gpointer ctx)
+{
+ SoupWebsocketConnection *socket_connection = soup_session_websocket_connect_finish (SOUP_SESSION(session), res, NULL);
+ if (!socket_connection) {
+ g_free (ctx);
+ return;
+ }
+
+ /* The performance tests increase the size of the payload up to 16 MB, let's disable
+ the limit to see what happens. */
+ soup_websocket_connection_set_max_incoming_payload_size (socket_connection, 0);
+
+ g_signal_connect (socket_connection, "message", G_CALLBACK(on_message_received), ctx);
+ g_signal_connect (socket_connection, "closed", G_CALLBACK(on_connection_closed), ctx);
+}
+
+static void
+connect_and_run (SoupSession *session, char *path, ConnectionFunc method, gpointer data)
+{
+ char *uri = g_strconcat (address, path, NULL);
+ SoupMessage *message = soup_message_new (SOUP_METHOD_GET, uri);
+ ConnectionContext *ctx = g_new0 (ConnectionContext, 1);
+
+ ctx->method = method;
+ ctx->data = data;
+
+ if (option_debug)
+ fprintf (stderr, "About to connect to %s\n", uri);
+ soup_session_websocket_connect_async (session, message, NULL, NULL, NULL, on_connect, ctx);
+
+ g_object_unref (message);
+ g_free (uri);
+
+ g_main_loop_run (loop);
+}
+
+static void
+test_case_message_received (SoupWebsocketConnection *socket_connection,
+ gint type,
+ GBytes *message,
+ gpointer data)
+{
+ /* Cannot send messages if we're not in an open state. */
+ if (soup_websocket_connection_get_state (socket_connection) != SOUP_WEBSOCKET_STATE_OPEN)
+ return;
+
+ if (option_debug)
+ fprintf (stderr, "-> ");
+
+ soup_websocket_connection_send_message (socket_connection, type, message);
+}
+
+static void
+run_case (SoupSession *session, const unsigned int test_case)
+{
+ char *path = g_strdup_printf ("/runCase?case=%u&agent=%s", test_case, agent);
+
+ running_tests = TRUE;
+ fprintf (stderr, "Running test case %u:", test_case);
+ connect_and_run (session, path, test_case_message_received, GUINT_TO_POINTER (test_case));
+ g_free (path);
+}
+
+static void
+run_all_cases (SoupSession *session)
+{
+ int i;
+ for (i = 0; i < total_num_cases; i++)
+ run_case (session, i + 1);
+}
+
+static void
+got_case_count (SoupWebsocketConnection *socket_connection,
+ gint type,
+ GBytes *message,
+ gpointer data)
+{
+ total_num_cases = g_ascii_strtoull (g_bytes_get_data (message, NULL), NULL, 10);
+
+ fprintf (stderr, "Total number of cases: %u\n", total_num_cases);
+}
+
+static void
+get_case_count (SoupSession *session)
+{
+ connect_and_run (session, "/getCaseCount", got_case_count, NULL);
+}
+
+static void
+update_reports (SoupSession *session)
+{
+ char *path = g_strdup_printf ("/updateReports?agent=%s", agent);
+ fprintf (stderr, "Updating reports..\n");
+ connect_and_run (session, path, NULL, NULL);
+ g_free (path);
+}
+
+int main (int argc, char* argv[])
+{
+ GOptionContext *context;
+ GError *error = NULL;
+ SoupSession *session;
+
+ context = g_option_context_new ("- libsoup test runner for Autobahn WebSocket client tests.");
+ g_option_context_add_main_entries (context, entries, NULL);
+
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_warning ("Option parsing failed: %s\n", error->message);
+ g_error_free (error);
+ g_option_context_free (context);
+ exit (1);
+ }
+ g_option_context_free (context);
+
+ if (option_run_test >= 0 || option_number_of_tests)
+ option_run_all = FALSE;
+
+ session = soup_session_new ();
+ soup_session_add_feature_by_type (session, SOUP_TYPE_WEBSOCKET_EXTENSION_MANAGER);
+ loop = g_main_loop_new (g_main_context_default (), FALSE);
+
+ if (!(option_run_all || option_number_of_tests || option_update_report || option_run_test > 0))
+ option_run_all = TRUE;
+
+ if (option_run_all || option_number_of_tests)
+ get_case_count (session);
+
+ if (option_run_test >= 0)
+ run_case (session, option_run_test);
+ else if (option_run_all)
+ run_all_cases (session);
+
+ if (option_update_report)
+ update_reports (session);
+
+ g_object_unref (session);
+
+ return 0;
+}