OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 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 "core/dom/ModuleMap.h" |
| 6 |
| 7 #include "core/dom/Document.h" |
| 8 #include "core/dom/Modulator.h" |
| 9 #include "core/dom/ModuleScript.h" |
| 10 #include "core/dom/ScriptModuleResolver.h" |
| 11 #include "core/loader/modulescript/ModuleScriptFetchRequest.h" |
| 12 #include "core/loader/modulescript/ModuleScriptLoaderClient.h" |
| 13 #include "core/testing/DummyModulator.h" |
| 14 #include "core/testing/DummyPageHolder.h" |
| 15 #include "platform/heap/Handle.h" |
| 16 #include "platform/testing/TestingPlatformSupport.h" |
| 17 #include "public/platform/Platform.h" |
| 18 #include "testing/gtest/include/gtest/gtest.h" |
| 19 |
| 20 namespace blink { |
| 21 |
| 22 namespace { |
| 23 |
| 24 class TestSingleModuleClient |
| 25 : public GarbageCollectedFinalized<TestSingleModuleClient>, |
| 26 public SingleModuleClient { |
| 27 USING_GARBAGE_COLLECTED_MIXIN(TestSingleModuleClient); |
| 28 |
| 29 public: |
| 30 TestSingleModuleClient() = default; |
| 31 virtual ~TestSingleModuleClient() {} |
| 32 |
| 33 DEFINE_INLINE_TRACE() { visitor->trace(m_moduleScript); } |
| 34 |
| 35 void notifyModuleLoadFinished(ModuleScript* moduleScript) override { |
| 36 m_wasNotifyFinished = true; |
| 37 m_moduleScript = moduleScript; |
| 38 } |
| 39 |
| 40 bool wasNotifyFinished() const { return m_wasNotifyFinished; } |
| 41 ModuleScript* moduleScript() { return m_moduleScript; } |
| 42 |
| 43 private: |
| 44 bool m_wasNotifyFinished = false; |
| 45 Member<ModuleScript> m_moduleScript; |
| 46 }; |
| 47 |
| 48 class TestScriptModuleResolver final : public ScriptModuleResolver { |
| 49 public: |
| 50 TestScriptModuleResolver() {} |
| 51 |
| 52 int registerModuleScriptCallCount() const { |
| 53 return m_registerModuleScriptCallCount; |
| 54 } |
| 55 |
| 56 void registerModuleScript(ModuleScript*) override { |
| 57 m_registerModuleScriptCallCount++; |
| 58 } |
| 59 |
| 60 ScriptModule resolve(const String& specifier, |
| 61 ScriptModuleIdentifier referrer, |
| 62 ExceptionState&) override { |
| 63 return ScriptModule(); |
| 64 } |
| 65 |
| 66 private: |
| 67 int m_registerModuleScriptCallCount = 0; |
| 68 }; |
| 69 |
| 70 } // namespace |
| 71 |
| 72 class ModuleMapTestModulator final : public DummyModulator { |
| 73 public: |
| 74 ModuleMapTestModulator(); |
| 75 ~ModuleMapTestModulator() override {} |
| 76 |
| 77 DECLARE_TRACE(); |
| 78 |
| 79 TestScriptModuleResolver* testScriptModuleResolver() { |
| 80 return m_resolver.get(); |
| 81 } |
| 82 void resolveFetches(); |
| 83 |
| 84 private: |
| 85 // Implements Modulator: |
| 86 |
| 87 ScriptModuleResolver* scriptModuleResolver() override { |
| 88 return m_resolver.get(); |
| 89 } |
| 90 |
| 91 WebTaskRunner* taskRunner() override { |
| 92 return Platform::current()->currentThread()->getWebTaskRunner(); |
| 93 }; |
| 94 |
| 95 void fetchNewSingleModule(const ModuleScriptFetchRequest&, |
| 96 ModuleGraphLevel, |
| 97 ModuleScriptLoaderClient*) override; |
| 98 |
| 99 struct TestRequest : public GarbageCollectedFinalized<TestRequest> { |
| 100 KURL url; |
| 101 String nonce; |
| 102 Member<ModuleScriptLoaderClient> client; |
| 103 |
| 104 DEFINE_INLINE_TRACE() { visitor->trace(client); } |
| 105 }; |
| 106 HeapVector<Member<TestRequest>> m_testRequests; |
| 107 |
| 108 Member<TestScriptModuleResolver> m_resolver; |
| 109 }; |
| 110 |
| 111 ModuleMapTestModulator::ModuleMapTestModulator() |
| 112 : m_resolver(new TestScriptModuleResolver) {} |
| 113 |
| 114 DEFINE_TRACE(ModuleMapTestModulator) { |
| 115 visitor->trace(m_testRequests); |
| 116 visitor->trace(m_resolver); |
| 117 DummyModulator::trace(visitor); |
| 118 } |
| 119 |
| 120 void ModuleMapTestModulator::fetchNewSingleModule( |
| 121 const ModuleScriptFetchRequest& request, |
| 122 ModuleGraphLevel, |
| 123 ModuleScriptLoaderClient* client) { |
| 124 TestRequest* testRequest = new TestRequest; |
| 125 testRequest->url = request.url(); |
| 126 testRequest->nonce = request.nonce(); |
| 127 testRequest->client = client; |
| 128 m_testRequests.push_back(testRequest); |
| 129 } |
| 130 |
| 131 void ModuleMapTestModulator::resolveFetches() { |
| 132 for (const auto& testRequest : m_testRequests) { |
| 133 ModuleScript* moduleScript = ModuleScript::create( |
| 134 ScriptModule(), testRequest->url, testRequest->nonce, ParserInserted, |
| 135 WebURLRequest::FetchCredentialsModeOmit); |
| 136 taskRunner()->postTask( |
| 137 BLINK_FROM_HERE, |
| 138 WTF::bind(&ModuleScriptLoaderClient::notifyNewSingleModuleFinished, |
| 139 wrapPersistent(testRequest->client.get()), |
| 140 wrapPersistent(moduleScript))); |
| 141 } |
| 142 m_testRequests.clear(); |
| 143 } |
| 144 |
| 145 class ModuleMapTest : public testing::Test { |
| 146 public: |
| 147 void SetUp() override; |
| 148 |
| 149 ModuleMapTestModulator* modulator() { return m_modulator.get(); } |
| 150 ModuleMap* map() { return m_map; } |
| 151 |
| 152 protected: |
| 153 Persistent<ModuleMapTestModulator> m_modulator; |
| 154 Persistent<ModuleMap> m_map; |
| 155 }; |
| 156 |
| 157 void ModuleMapTest::SetUp() { |
| 158 m_modulator = new ModuleMapTestModulator(); |
| 159 m_map = ModuleMap::create(m_modulator.get()); |
| 160 } |
| 161 |
| 162 TEST_F(ModuleMapTest, sequentialRequests) { |
| 163 ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler> |
| 164 platform; |
| 165 platform->advanceClockSeconds(1.); // For non-zero DocumentParserTimings |
| 166 |
| 167 KURL url(KURL(), "https://example.com/foo.js"); |
| 168 ModuleScriptFetchRequest moduleRequest( |
| 169 url, String(), ParserInserted, WebURLRequest::FetchCredentialsModeOmit); |
| 170 |
| 171 // First request |
| 172 TestSingleModuleClient* client = new TestSingleModuleClient; |
| 173 map()->retrieveAndFetchIfNeeded( |
| 174 moduleRequest, ModuleGraphLevel::TopLevelModuleFetch, client); |
| 175 modulator()->resolveFetches(); |
| 176 platform->runUntilIdle(); |
| 177 |
| 178 EXPECT_EQ( |
| 179 modulator()->testScriptModuleResolver()->registerModuleScriptCallCount(), |
| 180 1); |
| 181 EXPECT_TRUE(client->wasNotifyFinished()); |
| 182 EXPECT_TRUE(client->moduleScript()); |
| 183 EXPECT_EQ(client->moduleScript()->instantiationState(), |
| 184 ModuleInstantiationState::Uninstantiated); |
| 185 |
| 186 // Secondary request |
| 187 TestSingleModuleClient* client2 = new TestSingleModuleClient; |
| 188 map()->retrieveAndFetchIfNeeded( |
| 189 moduleRequest, ModuleGraphLevel::TopLevelModuleFetch, client2); |
| 190 modulator()->resolveFetches(); |
| 191 platform->runUntilIdle(); |
| 192 |
| 193 EXPECT_EQ( |
| 194 modulator()->testScriptModuleResolver()->registerModuleScriptCallCount(), |
| 195 1) |
| 196 << "registerModuleScript sholudn't be called in secondary request."; |
| 197 EXPECT_TRUE(client2->wasNotifyFinished()); |
| 198 EXPECT_TRUE(client2->moduleScript()); |
| 199 EXPECT_EQ(client2->moduleScript()->instantiationState(), |
| 200 ModuleInstantiationState::Uninstantiated); |
| 201 } |
| 202 |
| 203 TEST_F(ModuleMapTest, concurrentRequestsShouldJoin) { |
| 204 ScopedTestingPlatformSupport<TestingPlatformSupportWithMockScheduler> |
| 205 platform; |
| 206 platform->advanceClockSeconds(1.); // For non-zero DocumentParserTimings |
| 207 |
| 208 KURL url(KURL(), "https://example.com/foo.js"); |
| 209 ModuleScriptFetchRequest moduleRequest( |
| 210 url, String(), ParserInserted, WebURLRequest::FetchCredentialsModeOmit); |
| 211 |
| 212 // First request |
| 213 TestSingleModuleClient* client = new TestSingleModuleClient; |
| 214 map()->retrieveAndFetchIfNeeded( |
| 215 moduleRequest, ModuleGraphLevel::TopLevelModuleFetch, client); |
| 216 |
| 217 // Secondary request (which should join the first request) |
| 218 TestSingleModuleClient* client2 = new TestSingleModuleClient; |
| 219 map()->retrieveAndFetchIfNeeded( |
| 220 moduleRequest, ModuleGraphLevel::TopLevelModuleFetch, client2); |
| 221 |
| 222 modulator()->resolveFetches(); |
| 223 platform->runUntilIdle(); |
| 224 |
| 225 EXPECT_EQ( |
| 226 modulator()->testScriptModuleResolver()->registerModuleScriptCallCount(), |
| 227 1); |
| 228 |
| 229 EXPECT_TRUE(client->wasNotifyFinished()); |
| 230 EXPECT_TRUE(client->moduleScript()); |
| 231 EXPECT_EQ(client->moduleScript()->instantiationState(), |
| 232 ModuleInstantiationState::Uninstantiated); |
| 233 EXPECT_TRUE(client2->wasNotifyFinished()); |
| 234 EXPECT_TRUE(client2->moduleScript()); |
| 235 EXPECT_EQ(client2->moduleScript()->instantiationState(), |
| 236 ModuleInstantiationState::Uninstantiated); |
| 237 } |
| 238 |
| 239 } // namespace blink |
OLD | NEW |