diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestInspectorServer.cpp | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-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.cpp | 292 |
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(); +} |