Chromium Code Reviews| 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 | |
|
yhirano
2017/02/22 09:10:42
final
kouhei (in TOK)
2017/02/24 02:10:31
Done.
| |
| 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 const ScriptModule& referrer, | |
| 62 ExceptionState&) override { | |
|
yhirano
2017/02/22 09:10:42
NOTREACHED()?
kouhei (in TOK)
2017/02/24 02:10:31
Done.
| |
| 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()->fetchSingleModuleScript(moduleRequest, | |
| 174 ModuleGraphLevel::TopLevelModuleFetch, client); | |
| 175 modulator()->resolveFetches(); | |
|
yhirano
2017/02/22 09:10:42
EXPECT_FALSE(client->wasNotifyFinished());
kouhei (in TOK)
2017/02/24 02:10:31
Done.
| |
| 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()->fetchSingleModuleScript( | |
| 189 moduleRequest, ModuleGraphLevel::TopLevelModuleFetch, client2); | |
| 190 modulator()->resolveFetches(); | |
|
yhirano
2017/02/22 09:10:42
EXPECT_FALSE(client2->wasNotifyFinished);
kouhei (in TOK)
2017/02/24 02:10:31
Done.
| |
| 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()->fetchSingleModuleScript(moduleRequest, | |
| 215 ModuleGraphLevel::TopLevelModuleFetch, client); | |
| 216 | |
| 217 // Secondary request (which should join the first request) | |
| 218 TestSingleModuleClient* client2 = new TestSingleModuleClient; | |
| 219 map()->fetchSingleModuleScript( | |
| 220 moduleRequest, ModuleGraphLevel::TopLevelModuleFetch, client2); | |
| 221 | |
| 222 modulator()->resolveFetches(); | |
|
yhirano
2017/02/22 09:10:42
ditto
| |
| 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 |