summaryrefslogtreecommitdiff
path: root/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp
diff options
context:
space:
mode:
authorKonstantin Tokarev <annulen@yandex.ru>2016-08-25 19:20:41 +0300
committerKonstantin Tokarev <annulen@yandex.ru>2017-02-02 12:30:55 +0000
commit6882a04fb36642862b11efe514251d32070c3d65 (patch)
treeb7959826000b061fd5ccc7512035c7478742f7b0 /Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp
parentab6df191029eeeb0b0f16f127d553265659f739e (diff)
downloadqtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp')
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp292
1 files changed, 292 insertions, 0 deletions
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp
new file mode 100644
index 000000000..bbdd104c5
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2012 Samsung Electronics Ltd. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "WebViewTest.h"
+#include <wtf/glib/GRefPtr.h>
+#include <wtf/text/WTFString.h>
+
+// Name of the test server application creating the webView object.
+static const char* gTestServerAppName = "InspectorTestServer";
+
+// Max seconds to wait for the test server before inspecting it.
+static const int gMaxWaitForChild = 5;
+
+// The PID for the test server running, so we can kill it if needed.
+static GPid gChildProcessPid = 0;
+
+// Whether the child has replied and it's ready.
+static bool gChildIsReady = false;
+
+static void stopTestServer()
+{
+ // Do nothing if there's no server running.
+ if (!gChildProcessPid)
+ return;
+
+ g_spawn_close_pid(gChildProcessPid);
+ kill(gChildProcessPid, SIGTERM);
+ gChildProcessPid = 0;
+}
+
+static void sigAbortHandler(int sigNum)
+{
+ // Just stop the test server if SIGABRT was received.
+ stopTestServer();
+}
+
+static gpointer testServerMonitorThreadFunc(gpointer)
+{
+ // Wait for the specified timeout to happen.
+ g_usleep(gMaxWaitForChild * G_USEC_PER_SEC);
+
+ // Kill the child process if not ready yet.
+ if (!gChildIsReady)
+ stopTestServer();
+
+ g_thread_exit(0);
+ return 0;
+}
+
+static void startTestServerMonitor()
+{
+ gChildIsReady = false;
+ g_thread_new("TestServerMonitor", testServerMonitorThreadFunc, 0);
+}
+
+static void startTestServer()
+{
+ // Prepare argv[] for spawning the server process.
+ GUniquePtr<char> testServerPath(g_build_filename(WEBKIT_EXEC_PATH, "TestWebKitAPI", "WebKit2Gtk", gTestServerAppName, NULL));
+
+ // We install a handler to ensure that we kill the child process
+ // if the parent dies because of whatever the reason is.
+ signal(SIGABRT, sigAbortHandler);
+
+ char* testServerArgv[2];
+ testServerArgv[0] = testServerPath.get();
+ testServerArgv[1] = 0;
+
+ // Spawn the server, getting its stdout file descriptor to set a
+ // communication channel, so we know when it's ready.
+ int childStdout = 0;
+ g_assert(g_spawn_async_with_pipes(0, testServerArgv, 0, static_cast<GSpawnFlags>(0), 0, 0,
+ &gChildProcessPid, 0, &childStdout, 0, 0));
+
+ // Start monitoring the test server (in a separate thread) to
+ // ensure we don't block on the child process more than a timeout.
+ startTestServerMonitor();
+
+ char msg[2];
+ GIOChannel* ioChannel = g_io_channel_unix_new(childStdout);
+ if (g_io_channel_read_chars(ioChannel, msg, 2, 0, 0) == G_IO_STATUS_NORMAL) {
+ // Check whether the server sent a message saying it's ready
+ // and store the result globally, so the monitor can see it.
+ gChildIsReady = msg[0] == 'O' && msg[1] == 'K';
+ }
+ g_io_channel_unref(ioChannel);
+ close(childStdout);
+
+ // The timeout was reached and the server is not ready yet, so
+ // stop it inmediately, and let the unit tests fail.
+ if (!gChildIsReady)
+ stopTestServer();
+}
+
+class InspectorServerTest: public WebViewTest {
+public:
+ MAKE_GLIB_TEST_FIXTURE(InspectorServerTest);
+
+ InspectorServerTest()
+ : WebViewTest()
+ {
+ }
+
+ bool getPageList()
+ {
+ loadHtml("<script type=\"text/javascript\">\n"
+ "var pages;\n"
+ "var xhr = new XMLHttpRequest;\n"
+ "xhr.open(\"GET\", \"/pagelist.json\");\n"
+ "xhr.onload = function(e) {\n"
+ "if (xhr.status == 200) {\n"
+ "pages = JSON.parse(xhr.responseText);\n"
+ "document.title = \"OK\";\n"
+ "} else \n"
+ "document.title = \"FAIL\";\n"
+ "}\n"
+ "xhr.send();\n"
+ "</script>\n",
+ "http://127.0.0.1:2999/");
+
+ waitUntilTitleChanged();
+
+ if (!strcmp(webkit_web_view_get_title(m_webView), "OK"))
+ return true;
+
+ return false;
+ }
+
+ ~InspectorServerTest()
+ {
+ }
+};
+
+// Test to get inspector server page list from the test server.
+// Should contain only one entry pointing to http://127.0.0.1:2999/webinspector/Main.html?page=1
+static void testInspectorServerPageList(InspectorServerTest* test, gconstpointer)
+{
+ GUniqueOutPtr<GError> error;
+
+ test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
+ g_assert(test->getPageList());
+
+ WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("pages.length;", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+ g_assert_cmpint(WebViewTest::javascriptResultToNumber(javascriptResult), ==, 1);
+
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("pages[0].id;", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+ int pageId = WebViewTest::javascriptResultToNumber(javascriptResult);
+
+ GUniquePtr<char> valueString;
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("pages[0].url;", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+ valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ g_assert_cmpstr(valueString.get(), ==, "http://127.0.0.1:2999/");
+
+ javascriptResult = test->runJavaScriptAndWaitUntilFinished("pages[0].inspectorUrl;", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+ valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult));
+ String validInspectorURL = String("/Main.html?page=") + String::number(pageId);
+ ASSERT_CMP_CSTRING(valueString.get(), ==, validInspectorURL.utf8());
+}
+
+// Test sending a raw remote debugging message through our web socket server.
+// For this specific message see: http://code.google.com/chrome/devtools/docs/protocol/tot/runtime.html#command-evaluate
+static void testRemoteDebuggingMessage(InspectorServerTest* test, gconstpointer)
+{
+ test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
+
+ test->loadHtml("<script type=\"text/javascript\">\n"
+ "var socket = new WebSocket('ws://127.0.0.1:2999/devtools/page/1');\n"
+ "socket.onmessage = function(message) {\n"
+ "var response = JSON.parse(message.data);\n"
+ "if (response.id === 1)\n"
+ "document.title = response.result.result.value;\n"
+ "else\n"
+ "document.title = \"FAIL\";\n"
+ "}\n"
+ "socket.onopen = function() {\n"
+ "socket.send('{\"id\": 1, \"method\": \"Runtime.evaluate\", \"params\": {\"expression\": \"2 + 2\" } }');\n"
+ "}\n"
+ "</script>",
+ "http://127.0.0.1:2999/");
+ test->waitUntilTitleChanged();
+
+ g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, "4");
+}
+
+static void openRemoteDebuggingSession(InspectorServerTest* test, gconstpointer)
+{
+ // To test the whole pipeline this exploits a behavior of the inspector front-end which won't provide the page address as title unless the
+ // debugging session was established correctly through web socket.
+ // In our case page URL should be http://127.0.0.1:2999/
+ // So this test case will fail if:
+ // - The page list didn't return a valid inspector URL
+ // - Or the front-end couldn't be loaded through the inspector HTTP server
+ // - Or the web socket connection couldn't be established between the front-end and the page through the inspector server
+ // Let's see if this test isn't raising too many false positives, in which case we should use a better predicate if available.
+
+ test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL);
+
+ g_assert(test->getPageList());
+
+ GUniqueOutPtr<GError> error;
+ WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("pages[0].inspectorUrl;", &error.outPtr());
+ g_assert(javascriptResult);
+ g_assert(!error.get());
+
+ String resolvedURL = String("http://127.0.0.1:2999") + String::fromUTF8(WebViewTest::javascriptResultToCString(javascriptResult));
+ test->loadURI(resolvedURL.utf8().data());
+ test->waitUntilLoadFinished();
+
+ const char* title = webkit_web_view_get_title(test->m_webView);
+ if (!title || !*title)
+ test->waitUntilTitleChanged();
+ g_assert_cmpstr(webkit_web_view_get_title(test->m_webView), ==, "127.0.0.1");
+}
+
+static void sendIncompleteRequest(InspectorServerTest* test, gconstpointer)
+{
+ GUniqueOutPtr<GError> error;
+
+ // Connect to the inspector server.
+ GRefPtr<GSocketClient> client = adoptGRef(g_socket_client_new());
+ GRefPtr<GSocketConnection> connection = adoptGRef(g_socket_client_connect_to_host(client.get(), "127.0.0.1", 2999, 0, &error.outPtr()));
+ g_assert_no_error(error.get());
+
+ // Send incomplete request (missing blank line after headers) and check if inspector server
+ // replies. The server should not reply to an incomplete request and the test should timeout
+ // on read.
+ GOutputStream* ostream = g_io_stream_get_output_stream(G_IO_STREAM(connection.get()));
+ // Request missing blank line after headers.
+ const gchar* incompleteRequest = "GET /devtools/page/1 HTTP/1.1\r\nHost: Localhost\r\n";
+ g_output_stream_write(ostream, incompleteRequest, strlen(incompleteRequest), 0, &error.outPtr());
+ g_assert_no_error(error.get());
+
+ GInputStream* istream = g_io_stream_get_input_stream(G_IO_STREAM(connection.get()));
+ char response[16];
+ memset(response, 0, sizeof(response));
+ GRefPtr<GCancellable> cancel = adoptGRef(g_cancellable_new());
+ g_input_stream_read_async(istream, response, sizeof(response) - 1, G_PRIORITY_DEFAULT, cancel.get(), 0, 0);
+ // Give a chance for the server to reply.
+ test->wait(1);
+ g_cancellable_cancel(cancel.get());
+ // If we got any answer it means the server replied to an incomplete request, lets fail.
+ g_assert(response[0] == '\0');
+}
+
+void beforeAll()
+{
+ // Overwrite WEBKIT_INSPECTOR_SERVER variable with default IP address but different port to avoid conflict with the test inspector server page.
+ g_setenv("WEBKIT_INSPECTOR_SERVER", "127.0.0.1:2998", TRUE);
+
+ startTestServer();
+ InspectorServerTest::add("WebKitWebInspectorServer", "test-page-list", testInspectorServerPageList);
+ InspectorServerTest::add("WebKitWebInspectorServer", "test-remote-debugging-message", testRemoteDebuggingMessage);
+ InspectorServerTest::add("WebKitWebInspectorServer", "test-open-debugging-session", openRemoteDebuggingSession);
+ InspectorServerTest::add("WebKitWebInspectorServer", "test-incomplete-request", sendIncompleteRequest);
+
+}
+
+void afterAll()
+{
+ stopTestServer();
+}