1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/bindings/core/v8/script_streamer.h"
6
7 #include <memory>
8 #include <utility>
9
10 #include "base/single_thread_task_runner.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
13 #include "third_party/blink/public/platform/platform.h"
14 #include "third_party/blink/public/platform/scheduler/test/renderer_scheduler_test_support.h"
15 #include "third_party/blink/public/platform/web_url_loader.h"
16 #include "third_party/blink/public/platform/web_url_loader_mock_factory.h"
17 #include "third_party/blink/public/platform/web_url_request_extra_data.h"
18 #include "third_party/blink/renderer/bindings/core/v8/referrer_script_info.h"
19 #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
20 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
21 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
22 #include "third_party/blink/renderer/bindings/core/v8/v8_code_cache.h"
23 #include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
24 #include "third_party/blink/renderer/core/frame/settings.h"
25 #include "third_party/blink/renderer/core/script/classic_pending_script.h"
26 #include "third_party/blink/renderer/core/script/classic_script.h"
27 #include "third_party/blink/renderer/core/script/mock_script_element_base.h"
28 #include "third_party/blink/renderer/core/testing/dummy_page_holder.h"
29 #include "third_party/blink/renderer/platform/exported/wrapped_resource_response.h"
30 #include "third_party/blink/renderer/platform/heap/handle.h"
31 #include "third_party/blink/renderer/platform/loader/fetch/cross_origin_attribute_value.h"
32 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
33 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader.h"
34 #include "third_party/blink/renderer/platform/loader/fetch/response_body_loader.h"
35 #include "third_party/blink/renderer/platform/loader/fetch/script_fetch_options.h"
36 #include "third_party/blink/renderer/platform/loader/testing/mock_fetch_context.h"
37 #include "third_party/blink/renderer/platform/loader/testing/test_resource_fetcher_properties.h"
38 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
39 #include "third_party/blink/renderer/platform/testing/mock_context_lifecycle_notifier.h"
40 #include "third_party/blink/renderer/platform/testing/testing_platform_support_with_mock_scheduler.h"
41 #include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
42 #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
43 #include "v8/include/v8.h"
44
45 namespace blink {
46
47 namespace {
48
49 class TestResourceClient final : public GarbageCollected<TestResourceClient>,
50 public ResourceClient {
51
52 public:
TestResourceClient()53 TestResourceClient() : finished_(false) {}
Finished() const54 bool Finished() const { return finished_; }
55
DataReceived(Resource *,const char *,size_t)56 void DataReceived(Resource*,
57 const char* /* data */,
58 size_t /* length */) override {}
NotifyFinished(Resource *)59 void NotifyFinished(Resource*) override { finished_ = true; }
60
61 // Name for debugging, e.g. shown in memory-infra.
DebugName() const62 String DebugName() const override { return "TestResourceClient"; }
63
64 private:
65 bool finished_;
66 };
67
68 // TODO(leszeks): This class has a similar class in resource_loader_test.cc,
69 // the two should probably share the same class.
70 class NoopLoaderFactory final : public ResourceFetcher::LoaderFactory {
CreateURLLoader(const ResourceRequest & request,const ResourceLoaderOptions & options,scoped_refptr<base::SingleThreadTaskRunner>,scoped_refptr<base::SingleThreadTaskRunner>)71 std::unique_ptr<WebURLLoader> CreateURLLoader(
72 const ResourceRequest& request,
73 const ResourceLoaderOptions& options,
74 scoped_refptr<base::SingleThreadTaskRunner>,
75 scoped_refptr<base::SingleThreadTaskRunner>) override {
76 return std::make_unique<NoopWebURLLoader>();
77 }
CreateCodeCacheLoader()78 std::unique_ptr<WebCodeCacheLoader> CreateCodeCacheLoader() override {
79 return Platform::Current()->CreateCodeCacheLoader();
80 }
81
82 class NoopWebURLLoader final : public WebURLLoader {
83 public:
84 ~NoopWebURLLoader() override = default;
LoadSynchronously(std::unique_ptr<network::ResourceRequest> request,scoped_refptr<WebURLRequestExtraData> url_request_extra_data,int requestor_id,bool pass_response_pipe_to_client,bool no_mime_sniffing,base::TimeDelta timeout_interval,WebURLLoaderClient *,WebURLResponse &,base::Optional<WebURLError> &,WebData &,int64_t & encoded_data_length,int64_t & encoded_body_length,WebBlobInfo & downloaded_blob,std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> resource_load_info_notifier_wrapper)85 void LoadSynchronously(
86 std::unique_ptr<network::ResourceRequest> request,
87 scoped_refptr<WebURLRequestExtraData> url_request_extra_data,
88 int requestor_id,
89 bool pass_response_pipe_to_client,
90 bool no_mime_sniffing,
91 base::TimeDelta timeout_interval,
92 WebURLLoaderClient*,
93 WebURLResponse&,
94 base::Optional<WebURLError>&,
95 WebData&,
96 int64_t& encoded_data_length,
97 int64_t& encoded_body_length,
98 WebBlobInfo& downloaded_blob,
99 std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
100 resource_load_info_notifier_wrapper) override {
101 NOTREACHED();
102 }
LoadAsynchronously(std::unique_ptr<network::ResourceRequest> request,scoped_refptr<WebURLRequestExtraData> url_request_extra_data,int requestor_id,bool no_mime_sniffing,std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper> resource_load_info_notifier_wrapper,WebURLLoaderClient *)103 void LoadAsynchronously(
104 std::unique_ptr<network::ResourceRequest> request,
105 scoped_refptr<WebURLRequestExtraData> url_request_extra_data,
106 int requestor_id,
107 bool no_mime_sniffing,
108 std::unique_ptr<blink::ResourceLoadInfoNotifierWrapper>
109 resource_load_info_notifier_wrapper,
110 WebURLLoaderClient*) override {}
SetDefersLoading(WebURLLoader::DeferType)111 void SetDefersLoading(WebURLLoader::DeferType) override {}
DidChangePriority(WebURLRequest::Priority,int)112 void DidChangePriority(WebURLRequest::Priority, int) override {
113 NOTREACHED();
114 }
GetTaskRunnerForBodyLoader()115 scoped_refptr<base::SingleThreadTaskRunner> GetTaskRunnerForBodyLoader()
116 override {
117 return base::MakeRefCounted<scheduler::FakeTaskRunner>();
118 }
119 };
120 };
121
122 class ScriptStreamingTest : public testing::Test {
123 public:
ScriptStreamingTest()124 ScriptStreamingTest()
125 : url_("http://www.streaming-test.com/"),
126 freezable_task_runner_(platform_->test_task_runner()),
127 unfreezable_task_runner_(platform_->test_task_runner()) {
128 auto* properties = MakeGarbageCollected<TestResourceFetcherProperties>();
129 FetchContext* context = MakeGarbageCollected<MockFetchContext>();
130 auto* fetcher = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
131 properties->MakeDetachable(), context, freezable_task_runner_,
132 unfreezable_task_runner_, MakeGarbageCollected<NoopLoaderFactory>(),
133 MakeGarbageCollected<MockContextLifecycleNotifier>()));
134
135 ResourceRequest request(url_);
136 request.SetRequestContext(mojom::blink::RequestContextType::SCRIPT);
137
138 resource_client_ = MakeGarbageCollected<TestResourceClient>();
139 FetchParameters params = FetchParameters::CreateForTest(std::move(request));
140 resource_ = ScriptResource::Fetch(params, fetcher, resource_client_,
141 ScriptResource::kAllowStreaming);
142 resource_->AddClient(resource_client_, freezable_task_runner_.get());
143
144 ScriptStreamer::SetSmallScriptThresholdForTesting(0);
145
146 ResourceResponse response(url_);
147 response.SetHttpStatusCode(200);
148 resource_->SetResponse(response);
149
150 resource_->Loader()->DidReceiveResponse(WrappedResourceResponse(response));
151 resource_->Loader()->DidStartLoadingResponseBody(
152 std::move(data_pipe_.consumer_handle));
153 }
154
GetScriptSourceCode() const155 ScriptSourceCode GetScriptSourceCode() const {
156 ScriptStreamer* streamer = resource_->TakeStreamer();
157 if (streamer) {
158 if (streamer->IsStreamingSuppressed()) {
159 return ScriptSourceCode(nullptr, resource_,
160 streamer->StreamingSuppressedReason());
161 }
162 return ScriptSourceCode(streamer, resource_,
163 ScriptStreamer::NotStreamingReason::kInvalid);
164 }
165 return ScriptSourceCode(nullptr, resource_, resource_->NoStreamerReason());
166 }
167
GetSettings() const168 Settings* GetSettings() const {
169 return &dummy_page_holder_->GetPage().GetSettings();
170 }
171
172 protected:
AppendData(const char * data)173 void AppendData(const char* data) {
174 uint32_t data_len = strlen(data);
175 MojoResult result = data_pipe_.producer_handle->WriteData(
176 data, &data_len, MOJO_WRITE_DATA_FLAG_ALL_OR_NONE);
177 EXPECT_EQ(result, MOJO_RESULT_OK);
178
179 // Yield control to the background thread, so that V8 gets a chance to
180 // process the data before the main thread adds more. Note that we
181 // cannot fully control in what kind of chunks the data is passed to V8
182 // (if V8 is not requesting more data between two appendData calls, it
183 // will get both chunks together).
184 test::YieldCurrentThread();
185 }
186
AppendPadding()187 void AppendPadding() {
188 for (int i = 0; i < 10; ++i) {
189 AppendData(
190 " /* this is padding to make the script long enough, so "
191 "that V8's buffer gets filled and it starts processing "
192 "the data */ ");
193 }
194 }
195
Finish()196 void Finish() {
197 resource_->Loader()->DidFinishLoading(base::TimeTicks(), 0, 0, 0, false);
198 data_pipe_.producer_handle.reset();
199 resource_->SetStatus(ResourceStatus::kCached);
200 }
201
ProcessTasksUntilStreamingComplete()202 void ProcessTasksUntilStreamingComplete() { platform_->RunUntilIdle(); }
203
204 ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler>
205 platform_;
206
207 KURL url_;
208 scoped_refptr<base::SingleThreadTaskRunner> freezable_task_runner_;
209 scoped_refptr<base::SingleThreadTaskRunner> unfreezable_task_runner_;
210
211 Persistent<TestResourceClient> resource_client_;
212 Persistent<ScriptResource> resource_;
213 mojo::DataPipe data_pipe_;
214
215 std::unique_ptr<DummyPageHolder> dummy_page_holder_;
216 };
217
218 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
219 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_CompilingStreamedScript)220 TEST_F(ScriptStreamingTest, DISABLED_CompilingStreamedScript) {
221 // Test that we can successfully compile a streamed script.
222 V8TestingScope scope;
223
224 AppendData("function foo() {");
225 AppendPadding();
226 AppendData("return 5; }");
227 AppendPadding();
228 AppendData("foo();");
229 EXPECT_FALSE(resource_client_->Finished());
230 Finish();
231
232 // Process tasks on the main thread until the streaming background thread
233 // has completed its tasks.
234 ProcessTasksUntilStreamingComplete();
235 EXPECT_TRUE(resource_client_->Finished());
236 ScriptSourceCode source_code = GetScriptSourceCode();
237 EXPECT_TRUE(source_code.Streamer());
238 v8::TryCatch try_catch(scope.GetIsolate());
239 v8::Local<v8::Script> script;
240 v8::ScriptCompiler::CompileOptions compile_options;
241 V8CodeCache::ProduceCacheOptions produce_cache_options;
242 v8::ScriptCompiler::NoCacheReason no_cache_reason;
243 std::tie(compile_options, produce_cache_options, no_cache_reason) =
244 V8CodeCache::GetCompileOptions(mojom::blink::V8CacheOptions::kDefault,
245 source_code);
246 EXPECT_TRUE(V8ScriptRunner::CompileScript(
247 scope.GetScriptState(), source_code,
248 SanitizeScriptErrors::kDoNotSanitize, compile_options,
249 no_cache_reason, ReferrerScriptInfo())
250 .ToLocal(&script));
251 EXPECT_FALSE(try_catch.HasCaught());
252 }
253
254 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
255 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_CompilingStreamedScriptWithParseError)256 TEST_F(ScriptStreamingTest, DISABLED_CompilingStreamedScriptWithParseError) {
257 // Test that scripts with parse errors are handled properly. In those cases,
258 // V8 stops reading the network stream: make sure we handle it gracefully.
259 V8TestingScope scope;
260 AppendData("function foo() {");
261 AppendData("this is the part which will be a parse error");
262 // V8 won't realize the parse error until it actually starts parsing the
263 // script, and this happens only when its buffer is filled.
264 AppendPadding();
265
266 EXPECT_FALSE(resource_client_->Finished());
267 Finish();
268
269 // Process tasks on the main thread until the streaming background thread
270 // has completed its tasks.
271 ProcessTasksUntilStreamingComplete();
272 EXPECT_TRUE(resource_client_->Finished());
273 ScriptSourceCode source_code = GetScriptSourceCode();
274 EXPECT_TRUE(source_code.Streamer());
275 v8::TryCatch try_catch(scope.GetIsolate());
276 v8::Local<v8::Script> script;
277 v8::ScriptCompiler::CompileOptions compile_options;
278 V8CodeCache::ProduceCacheOptions produce_cache_options;
279 v8::ScriptCompiler::NoCacheReason no_cache_reason;
280 std::tie(compile_options, produce_cache_options, no_cache_reason) =
281 V8CodeCache::GetCompileOptions(mojom::blink::V8CacheOptions::kDefault,
282 source_code);
283 EXPECT_FALSE(V8ScriptRunner::CompileScript(
284 scope.GetScriptState(), source_code,
285 SanitizeScriptErrors::kDoNotSanitize, compile_options,
286 no_cache_reason, ReferrerScriptInfo())
287 .ToLocal(&script));
288 EXPECT_TRUE(try_catch.HasCaught());
289 }
290
291 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
292 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_CancellingStreaming)293 TEST_F(ScriptStreamingTest, DISABLED_CancellingStreaming) {
294 // Test that the upper layers (PendingScript and up) can be ramped down
295 // while streaming is ongoing, and ScriptStreamer handles it gracefully.
296 V8TestingScope scope;
297 AppendData("function foo() {");
298
299 // In general, we cannot control what the background thread is doing
300 // (whether it's parsing or waiting for more data). In this test, we have
301 // given it so little data that it's surely waiting for more.
302
303 // Simulate cancelling the network load (e.g., because the user navigated
304 // away).
305 EXPECT_FALSE(resource_client_->Finished());
306 resource_ = nullptr;
307
308 // The V8 side will complete too. This should not crash. We don't receive
309 // any results from the streaming and the client doesn't get notified.
310 ProcessTasksUntilStreamingComplete();
311 EXPECT_FALSE(resource_client_->Finished());
312 }
313
314 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
315 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_DataAfterDisposingPendingScript)316 TEST_F(ScriptStreamingTest, DISABLED_DataAfterDisposingPendingScript) {
317 // Test that the upper layers (PendingScript and up) can be ramped down
318 // before streaming is started, and ScriptStreamer handles it gracefully.
319 V8TestingScope scope;
320
321 // In general, we cannot control what the background thread is doing
322 // (whether it's parsing or waiting for more data). In this test, we have
323 // given it so little data that it's surely waiting for more.
324
325 EXPECT_FALSE(resource_client_->Finished());
326
327 // Keep the resource alive
328 Persistent<ScriptResource> resource = resource_;
329
330 // Simulate cancelling the network load (e.g., because the user navigated
331 // away).
332 resource_ = nullptr;
333
334 // Make sure the streaming starts.
335 AppendData("function foo() {");
336 AppendPadding();
337 resource.Clear();
338
339 // The V8 side will complete too. This should not crash. We don't receive
340 // any results from the streaming and the client doesn't get notified.
341 ProcessTasksUntilStreamingComplete();
342 EXPECT_FALSE(resource_client_->Finished());
343 }
344
345 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
346 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_SuppressingStreaming)347 TEST_F(ScriptStreamingTest, DISABLED_SuppressingStreaming) {
348 // If we notice before streaming that there is a code cache, streaming
349 // is suppressed (V8 doesn't parse while the script is loading), and the
350 // upper layer (ScriptResourceClient) should get a notification when the
351 // script is loaded.
352 V8TestingScope scope;
353
354 SingleCachedMetadataHandler* cache_handler = resource_->CacheHandler();
355 EXPECT_TRUE(cache_handler);
356 cache_handler->DisableSendToPlatformForTesting();
357 cache_handler->SetCachedMetadata(V8CodeCache::TagForCodeCache(cache_handler),
358 reinterpret_cast<const uint8_t*>("X"), 1);
359
360 AppendData("function foo() {");
361 AppendPadding();
362 Finish();
363 ProcessTasksUntilStreamingComplete();
364 EXPECT_TRUE(resource_client_->Finished());
365
366 ScriptSourceCode source_code = GetScriptSourceCode();
367 // ScriptSourceCode doesn't refer to the streamer, since we have suppressed
368 // the streaming and resumed the non-streaming code path for script
369 // compilation.
370 EXPECT_FALSE(source_code.Streamer());
371 }
372
373 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
374 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_EmptyScripts)375 TEST_F(ScriptStreamingTest, DISABLED_EmptyScripts) {
376 // Empty scripts should also be streamed properly, that is, the upper layer
377 // (ScriptResourceClient) should be notified when an empty script has been
378 // loaded.
379 V8TestingScope scope;
380
381 // Finish the script without sending any data.
382 Finish();
383 ProcessTasksUntilStreamingComplete();
384 EXPECT_TRUE(resource_client_->Finished());
385
386 ScriptSourceCode source_code = GetScriptSourceCode();
387 EXPECT_FALSE(source_code.Streamer());
388 }
389
390 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
391 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_SmallScripts)392 TEST_F(ScriptStreamingTest, DISABLED_SmallScripts) {
393 // Small scripts shouldn't be streamed.
394 V8TestingScope scope;
395 ScriptStreamer::SetSmallScriptThresholdForTesting(100);
396
397 AppendData("function foo() { }");
398
399 Finish();
400 ProcessTasksUntilStreamingComplete();
401 EXPECT_TRUE(resource_client_->Finished());
402
403 ScriptSourceCode source_code = GetScriptSourceCode();
404 EXPECT_FALSE(source_code.Streamer());
405 }
406
407 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
408 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_ScriptsWithSmallFirstChunk)409 TEST_F(ScriptStreamingTest, DISABLED_ScriptsWithSmallFirstChunk) {
410 // If a script is long enough, if should be streamed, even if the first data
411 // chunk is small.
412 V8TestingScope scope;
413 ScriptStreamer::SetSmallScriptThresholdForTesting(100);
414
415 // This is the first data chunk which is small.
416 AppendData("function foo() { }");
417 AppendPadding();
418 AppendPadding();
419 AppendPadding();
420
421 Finish();
422
423 ProcessTasksUntilStreamingComplete();
424 EXPECT_TRUE(resource_client_->Finished());
425 ScriptSourceCode source_code = GetScriptSourceCode();
426 EXPECT_TRUE(source_code.Streamer());
427 v8::TryCatch try_catch(scope.GetIsolate());
428 v8::Local<v8::Script> script;
429 v8::ScriptCompiler::CompileOptions compile_options;
430 V8CodeCache::ProduceCacheOptions produce_cache_options;
431 v8::ScriptCompiler::NoCacheReason no_cache_reason;
432 std::tie(compile_options, produce_cache_options, no_cache_reason) =
433 V8CodeCache::GetCompileOptions(mojom::blink::V8CacheOptions::kDefault,
434 source_code);
435 EXPECT_TRUE(V8ScriptRunner::CompileScript(
436 scope.GetScriptState(), source_code,
437 SanitizeScriptErrors::kDoNotSanitize, compile_options,
438 no_cache_reason, ReferrerScriptInfo())
439 .ToLocal(&script));
440 EXPECT_FALSE(try_catch.HasCaught());
441 }
442
443 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
444 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_EncodingChanges)445 TEST_F(ScriptStreamingTest, DISABLED_EncodingChanges) {
446 // It's possible that the encoding of the Resource changes after we start
447 // loading it.
448 V8TestingScope scope;
449 resource_->SetEncodingForTest("windows-1252");
450
451 resource_->SetEncodingForTest("UTF-8");
452 // \xec\x92\x81 are the raw bytes for \uc481.
453 AppendData(
454 "function foo() { var foob\xec\x92\x81r = 13; return foob\xec\x92\x81r; "
455 "} foo();");
456
457 Finish();
458
459 ProcessTasksUntilStreamingComplete();
460 EXPECT_TRUE(resource_client_->Finished());
461 ScriptSourceCode source_code = GetScriptSourceCode();
462 EXPECT_TRUE(source_code.Streamer());
463 v8::TryCatch try_catch(scope.GetIsolate());
464 v8::Local<v8::Script> script;
465 v8::ScriptCompiler::CompileOptions compile_options;
466 V8CodeCache::ProduceCacheOptions produce_cache_options;
467 v8::ScriptCompiler::NoCacheReason no_cache_reason;
468 std::tie(compile_options, produce_cache_options, no_cache_reason) =
469 V8CodeCache::GetCompileOptions(mojom::blink::V8CacheOptions::kDefault,
470 source_code);
471 EXPECT_TRUE(V8ScriptRunner::CompileScript(
472 scope.GetScriptState(), source_code,
473 SanitizeScriptErrors::kDoNotSanitize, compile_options,
474 no_cache_reason, ReferrerScriptInfo())
475 .ToLocal(&script));
476 EXPECT_FALSE(try_catch.HasCaught());
477 }
478
479 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
480 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_EncodingFromBOM)481 TEST_F(ScriptStreamingTest, DISABLED_EncodingFromBOM) {
482 // Byte order marks should be removed before giving the data to V8. They
483 // will also affect encoding detection.
484 V8TestingScope scope;
485
486 // This encoding is wrong on purpose.
487 resource_->SetEncodingForTest("windows-1252");
488
489 // \xef\xbb\xbf is the UTF-8 byte order mark. \xec\x92\x81 are the raw bytes
490 // for \uc481.
491 AppendData(
492 "\xef\xbb\xbf function foo() { var foob\xec\x92\x81r = 13; return "
493 "foob\xec\x92\x81r; } foo();");
494
495 Finish();
496 ProcessTasksUntilStreamingComplete();
497 EXPECT_TRUE(resource_client_->Finished());
498 ScriptSourceCode source_code = GetScriptSourceCode();
499 EXPECT_TRUE(source_code.Streamer());
500 v8::TryCatch try_catch(scope.GetIsolate());
501 v8::Local<v8::Script> script;
502 v8::ScriptCompiler::CompileOptions compile_options;
503 V8CodeCache::ProduceCacheOptions produce_cache_options;
504 v8::ScriptCompiler::NoCacheReason no_cache_reason;
505 std::tie(compile_options, produce_cache_options, no_cache_reason) =
506 V8CodeCache::GetCompileOptions(mojom::blink::V8CacheOptions::kDefault,
507 source_code);
508 EXPECT_TRUE(V8ScriptRunner::CompileScript(
509 scope.GetScriptState(), source_code,
510 SanitizeScriptErrors::kDoNotSanitize, compile_options,
511 no_cache_reason, ReferrerScriptInfo())
512 .ToLocal(&script));
513 EXPECT_FALSE(try_catch.HasCaught());
514 }
515
516 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
517 // currently unable to block and wait for the script streaming thread.
518 // A test for crbug.com/711703. Should not crash.
TEST_F(ScriptStreamingTest,DISABLED_GarbageCollectDuringStreaming)519 TEST_F(ScriptStreamingTest, DISABLED_GarbageCollectDuringStreaming) {
520 V8TestingScope scope;
521
522 EXPECT_FALSE(resource_client_->Finished());
523
524 resource_ = nullptr;
525 ThreadState::Current()->CollectAllGarbageForTesting(
526 BlinkGC::kNoHeapPointersOnStack);
527 }
528
529 // TODO(crbug.com/939054): Tests are disabled due to flakiness caused by being
530 // currently unable to block and wait for the script streaming thread.
TEST_F(ScriptStreamingTest,DISABLED_ResourceSetRevalidatingRequest)531 TEST_F(ScriptStreamingTest, DISABLED_ResourceSetRevalidatingRequest) {
532 V8TestingScope scope;
533
534 // Kick the streaming off.
535 AppendData("function foo() {");
536 AppendPadding();
537 AppendData("}");
538 Finish();
539 ProcessTasksUntilStreamingComplete();
540
541 // Should be done streaming by now.
542 EXPECT_TRUE(resource_->HasStreamer());
543 EXPECT_FALSE(resource_->HasRunningStreamer());
544
545 ResourceRequest request(resource_->Url());
546 resource_->SetRevalidatingRequest(request);
547
548 // Now there shouldn't be a streamer at all, and the reason should be
549 // "kRevalidate".
550 EXPECT_FALSE(resource_->HasStreamer());
551 EXPECT_EQ(resource_->NoStreamerReason(),
552 ScriptStreamer::NotStreamingReason::kRevalidate);
553 }
554
555 } // namespace
556
557 } // namespace blink
558