Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(339)

Unified Diff: Source/bindings/core/v8/ScriptStreamerTest.cpp

Issue 368283002: Stream scripts to V8 as they load - Blink side. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: removed untrue assert Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/bindings/core/v8/ScriptStreamer.cpp ('k') | Source/bindings/core/v8/ScriptStreamerThread.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/bindings/core/v8/ScriptStreamerTest.cpp
diff --git a/Source/bindings/core/v8/ScriptStreamerTest.cpp b/Source/bindings/core/v8/ScriptStreamerTest.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c48ad384b179cb9955f7d5193158d6276887bd14
--- /dev/null
+++ b/Source/bindings/core/v8/ScriptStreamerTest.cpp
@@ -0,0 +1,221 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+#include "config.h"
+#include "bindings/core/v8/ScriptStreamer.h"
+
+#include "bindings/core/v8/ScriptStreamerThread.h"
+#include "bindings/core/v8/V8Binding.h"
+#include "bindings/core/v8/V8ScriptRunner.h"
+#include "core/dom/PendingScript.h"
+#include "core/frame/Settings.h"
+#include "platform/Task.h"
+#include "public/platform/Platform.h"
+
+#include <gtest/gtest.h>
+#include <v8.h>
+
+namespace blink {
+
+namespace {
+
+class ScriptStreamingTest : public testing::Test {
+public:
+ ScriptStreamingTest()
+ : m_scope(v8::Isolate::GetCurrent())
+ , m_settings(Settings::create())
+ , m_resourceRequest("http://www.streaming-test.com/")
+ , m_resource(new ScriptResource(m_resourceRequest, "text/utf-8"))
+ , m_pendingScript(0, m_resource) // Takes ownership of m_resource.
+ {
+ m_settings->setV8ScriptStreamingEnabled(true);
+ m_resource->setLoading(true);
+ }
+
+ ScriptState* scriptState() const { return m_scope.scriptState(); }
+ v8::Isolate* isolate() const { return m_scope.isolate(); }
+
+protected:
+ void appendData(const char* data)
+ {
+ m_resource->appendData(data, strlen(data));
+ // Yield control to the background thread, so that V8 gets a change to
+ // process the data before the main thread adds more. Note that we
+ // cannot fully control in what kind of chunks the data is passed to V8
+ // (if the V8 is not requesting more data between two appendData calls,
+ // V8 will get both chunks together).
+ WTF::yield();
+ }
+
+ void appendPadding()
+ {
+ for (int i = 0; i < 10; ++i) {
+ appendData(" /* this is padding to make the script long enough, so "
+ "that V8's buffer gets filled and it starts processing "
+ "the data */ ");
+ }
+ }
+
+ void finish()
+ {
+ m_resource->finish();
+ m_resource->setLoading(false);
+ }
+
+ void processTasksUntilStreamingComplete()
+ {
+ while (ScriptStreamerThread::shared()->isRunningTask()) {
+ WebThread* currentThread = blink::Platform::current()->currentThread();
+ currentThread->postTask(new Task(WTF::bind(&WebThread::exitRunLoop, currentThread)));
+ currentThread->enterRunLoop();
+ }
+ }
+
+ V8TestingScope m_scope;
+ OwnPtr<Settings> m_settings;
+ // The Resource and PendingScript where we stream from. These don't really
+ // fetch any data outside the test; the test controls the data by calling
+ // ScriptResource::appendData.
+ ResourceRequest m_resourceRequest;
+ ScriptResource* m_resource;
+ PendingScript m_pendingScript;
+};
+
+class TestScriptResourceClient : public ScriptResourceClient {
+public:
+ TestScriptResourceClient()
+ : m_finished(false) { }
+
+ virtual void notifyFinished(Resource*) OVERRIDE { m_finished = true; }
+
+ bool finished() const { return m_finished; }
+
+private:
+ bool m_finished;
+};
+
+TEST_F(ScriptStreamingTest, CompilingStreamedScript)
+{
+ // Test that we can successfully compile a streamed script.
+ bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.get(), m_scope.scriptState());
+ TestScriptResourceClient client;
+ m_pendingScript.watchForLoad(&client);
+ EXPECT_TRUE(started);
+
+ appendData("function foo() {");
+ appendPadding();
+ appendData("return 5; }");
+ appendPadding();
+ appendData("foo();");
+ EXPECT_FALSE(client.finished());
+ finish();
+
+ // Process tasks on the main thread until the streaming background thread
+ // has completed its tasks.
+ processTasksUntilStreamingComplete();
+ EXPECT_TRUE(client.finished());
+ bool errorOccurred = false;
+ ScriptSourceCode sourceCode = m_pendingScript.getSource(KURL(), errorOccurred);
+ EXPECT_FALSE(errorOccurred);
+ EXPECT_TRUE(sourceCode.streamer());
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, isolate());
+ EXPECT_FALSE(script.IsEmpty());
+ EXPECT_FALSE(tryCatch.HasCaught());
+}
+
+TEST_F(ScriptStreamingTest, CompilingStreamedScriptWithParseError)
+{
+ // Test that scripts with parse errors are handled properly. In those cases,
+ // the V8 side typically finished before loading finishes: make sure we
+ // handle it gracefully.
+ bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.get(), m_scope.scriptState());
+ TestScriptResourceClient client;
+ m_pendingScript.watchForLoad(&client);
+ EXPECT_TRUE(started);
+ appendData("function foo() {");
+ appendData("this is the part which will be a parse error");
+ // V8 won't realize the parse error until it actually starts parsing the
+ // script, and this happens only when its buffer is filled.
+ appendPadding();
+
+ EXPECT_FALSE(client.finished());
+
+ // Force the V8 side to finish before the loading.
+ processTasksUntilStreamingComplete();
+ EXPECT_FALSE(client.finished());
+
+ finish();
+ EXPECT_TRUE(client.finished());
+
+ bool errorOccurred = false;
+ ScriptSourceCode sourceCode = m_pendingScript.getSource(KURL(), errorOccurred);
+ EXPECT_FALSE(errorOccurred);
+ EXPECT_TRUE(sourceCode.streamer());
+ v8::TryCatch tryCatch;
+ v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(sourceCode, isolate());
+ EXPECT_TRUE(script.IsEmpty());
+ EXPECT_TRUE(tryCatch.HasCaught());
+}
+
+TEST_F(ScriptStreamingTest, CancellingStreaming)
+{
+ // Test that the upper layers (PendingScript and up) can be ramped down
+ // while streaming is ongoing, and ScriptStreamer handles it gracefully.
+ bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.get(), m_scope.scriptState());
+ TestScriptResourceClient client;
+ m_pendingScript.watchForLoad(&client);
+ EXPECT_TRUE(started);
+ appendData("function foo() {");
+
+ // In general, we cannot control what the background thread is doing
+ // (whether it's parsing or waiting for more data). In this test, we have
+ // given it so little data that it's surely waiting for more.
+
+ // Simulate cancelling the network load (e.g., because the user navigated
+ // away).
+ EXPECT_FALSE(client.finished());
+ m_pendingScript.stopWatchingForLoad(&client);
+ m_pendingScript = PendingScript(); // This will destroy m_resource.
+ m_resource = 0;
+
+ // The V8 side will complete too. This should not crash. We don't receive
+ // any results from the streaming and the client doesn't get notified.
+ processTasksUntilStreamingComplete();
+ EXPECT_FALSE(client.finished());
+}
+
+TEST_F(ScriptStreamingTest, SuppressingStreaming)
+{
+ // If we notice during streaming that there is a code cache, streaming
+ // is suppressed (V8 doesn't parse while the script is loading), and the
+ // upper layer (ScriptResourceClient) should get a notification when the
+ // script is loaded.
+ bool started = ScriptStreamer::startStreaming(m_pendingScript, m_settings.get(), m_scope.scriptState());
+ TestScriptResourceClient client;
+ m_pendingScript.watchForLoad(&client);
+ EXPECT_TRUE(started);
+ appendData("function foo() {");
+ appendPadding();
+
+ m_resource->setCachedMetadata(V8ScriptRunner::tagForCodeCache(), "X", 1, Resource::CacheLocally);
+
+ appendPadding();
+ finish();
+ processTasksUntilStreamingComplete();
+ EXPECT_TRUE(client.finished());
+
+ bool errorOccurred = false;
+ ScriptSourceCode sourceCode = m_pendingScript.getSource(KURL(), errorOccurred);
+ EXPECT_FALSE(errorOccurred);
+ // ScriptSourceCode doesn't refer to the streamer, since we have suppressed
+ // the streaming and resumed the non-streaming code path for script
+ // compilation.
+ EXPECT_FALSE(sourceCode.streamer());
+}
+
+} // namespace
+
+} // namespace blink
« no previous file with comments | « Source/bindings/core/v8/ScriptStreamer.cpp ('k') | Source/bindings/core/v8/ScriptStreamerThread.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698