Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright 2016 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 "base/command_line.h" | |
| 6 #include "chrome/browser/predictors/resource_prefetch_predictor.h" | |
| 7 #include "chrome/browser/predictors/resource_prefetch_predictor_factory.h" | |
| 8 #include "chrome/browser/predictors/resource_prefetch_predictor_test_util.h" | |
| 9 #include "chrome/browser/profiles/profile.h" | |
| 10 #include "chrome/browser/ui/browser.h" | |
| 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 12 #include "chrome/common/chrome_switches.h" | |
| 13 #include "chrome/test/base/in_process_browser_test.h" | |
| 14 #include "chrome/test/base/ui_test_utils.h" | |
| 15 #include "content/public/browser/render_frame_host.h" | |
| 16 #include "content/public/browser/render_process_host.h" | |
| 17 #include "net/test/embedded_test_server/http_request.h" | |
| 18 #include "net/test/embedded_test_server/http_response.h" | |
| 19 #include "testing/gmock/include/gmock/gmock.h" | |
| 20 #include "testing/gtest/include/gtest/gtest.h" | |
| 21 | |
| 22 using testing::UnorderedElementsAreArray; | |
| 23 | |
| 24 namespace predictors { | |
| 25 | |
| 26 static const char kImageUrl[] = "/predictors/image.png"; | |
| 27 static const char kStyleUrl[] = "/predictors/style.css"; | |
| 28 static const char kScriptUrl[] = "/predictors/script.js"; | |
| 29 static const char kFontUrl[] = "/predictors/font.ttf"; | |
| 30 static const char kHtmlSubresourcesUrl[] = "/predictors/html_subresources.html"; | |
| 31 | |
| 32 using PageRequestSummary = ResourcePrefetchPredictor::PageRequestSummary; | |
| 33 using URLRequestSummary = ResourcePrefetchPredictor::URLRequestSummary; | |
| 34 using net::test_server::HttpRequest; | |
| 35 using net::test_server::HttpResponse; | |
| 36 using net::test_server::BasicHttpResponse; | |
| 37 | |
| 38 struct ResourceSummary { | |
|
Benoit L
2016/11/02 14:03:18
This largely duplicates ResourcePrefetchPredictor:
alexilin
2016/11/02 16:14:47
These structures have mismatched fields.
ResourceS
| |
| 39 ResourceSummary() | |
| 40 : resource_type(content::RESOURCE_TYPE_LAST_TYPE), | |
| 41 cached(false), | |
| 42 has_validators(false), | |
| 43 always_revalidate(false), | |
| 44 no_store(false), | |
| 45 version(0) {} | |
|
Benoit L
2016/11/02 14:03:18
Doesn't seem to be used in this CL beyond the Etag
alexilin
2016/11/02 16:14:47
True
| |
| 46 | |
| 47 GURL url; | |
| 48 content::ResourceType resource_type; | |
| 49 std::string mime_type; | |
| 50 bool cached; | |
| 51 bool has_validators; | |
| 52 bool always_revalidate; | |
| 53 std::string content; | |
| 54 bool no_store; | |
|
Benoit L
2016/11/02 14:03:18
tiny nit: I quite like "is_X" for boolean variable
alexilin
2016/11/02 16:14:47
Done.
| |
| 55 size_t version; | |
| 56 }; | |
| 57 | |
| 58 net::RequestPriority TypeToPriority(content::ResourceType type) { | |
|
Benoit L
2016/11/02 09:56:42
I'm not really sure about the mapping of resource
alexilin
2016/11/02 10:09:14
I'm not sure too. Probably it would be better not
Benoit L
2016/11/02 12:23:12
The actual priority logic is indeed more complex.
alexilin
2016/11/02 13:46:16
I'm not sure that I understood you correctly becau
| |
| 59 switch (type) { | |
| 60 case content::RESOURCE_TYPE_STYLESHEET: | |
| 61 case content::RESOURCE_TYPE_FONT_RESOURCE: | |
| 62 return net::HIGHEST; | |
| 63 case content::RESOURCE_TYPE_SCRIPT: | |
| 64 return net::MEDIUM; | |
| 65 case content::RESOURCE_TYPE_IMAGE: | |
| 66 return net::LOWEST; | |
| 67 default: | |
| 68 return net::DEFAULT_PRIORITY; | |
| 69 } | |
| 70 } | |
| 71 | |
| 72 // Helper class to track and allow waiting for ResourcePrefetchPredictor events. | |
| 73 class ResourcePrefetchPredictorTestObserver : public TestObserver { | |
| 74 public: | |
| 75 explicit ResourcePrefetchPredictorTestObserver( | |
| 76 ResourcePrefetchPredictor* predictor, | |
| 77 const size_t expected_url_visit_count, | |
| 78 const PageRequestSummary& expected_summary) | |
| 79 : TestObserver(predictor), | |
| 80 message_loop_runner_(new content::MessageLoopRunner), | |
|
Benoit L
2016/11/02 14:03:18
nit: content::MessageLoopRunner().
That's safer.
alexilin
2016/11/02 16:14:47
Done.
| |
| 81 url_visit_count_(expected_url_visit_count), | |
| 82 summary_(expected_summary) {} | |
| 83 | |
| 84 ~ResourcePrefetchPredictorTestObserver() override {} | |
| 85 | |
| 86 // ResourcePrefetchPredictor::Observer | |
| 87 void OnNavigationLearned(size_t url_visit_count, | |
| 88 const PageRequestSummary& summary) override { | |
| 89 EXPECT_EQ(url_visit_count, url_visit_count_); | |
| 90 EXPECT_EQ(summary.main_frame_url, summary_.main_frame_url); | |
| 91 EXPECT_EQ(summary.initial_url, summary_.initial_url); | |
| 92 EXPECT_THAT(summary.subresource_requests, | |
| 93 UnorderedElementsAreArray(summary_.subresource_requests)); | |
| 94 message_loop_runner_->Quit(); | |
| 95 } | |
| 96 | |
| 97 void Wait() { message_loop_runner_->Run(); } | |
| 98 | |
| 99 private: | |
| 100 scoped_refptr<content::MessageLoopRunner> message_loop_runner_; | |
| 101 size_t url_visit_count_; | |
| 102 PageRequestSummary summary_; | |
| 103 | |
| 104 DISALLOW_COPY_AND_ASSIGN(ResourcePrefetchPredictorTestObserver); | |
| 105 }; | |
| 106 | |
| 107 class ResourcePrefetchPredictorBrowserTest : public InProcessBrowserTest { | |
| 108 public: | |
| 109 void SetUpCommandLine(base::CommandLine* command_line) override { | |
| 110 command_line->AppendSwitchASCII( | |
| 111 switches::kSpeculativeResourcePrefetching, | |
| 112 switches::kSpeculativeResourcePrefetchingEnabled); | |
| 113 } | |
| 114 | |
| 115 void SetUpOnMainThread() override { | |
| 116 embedded_test_server()->RegisterRequestHandler( | |
| 117 base::Bind(&ResourcePrefetchPredictorBrowserTest::HandleRequest, | |
| 118 base::Unretained(this))); | |
| 119 ASSERT_TRUE(embedded_test_server()->Start()); | |
| 120 predictor_ = | |
| 121 ResourcePrefetchPredictorFactory::GetForProfile(browser()->profile()); | |
| 122 ASSERT_TRUE(predictor_); | |
| 123 } | |
| 124 | |
| 125 void NavigateToURLAndCheckSubresources( | |
| 126 const std::string& main_frame_relative) { | |
| 127 GURL main_frame_absolute = | |
| 128 embedded_test_server()->GetURL(main_frame_relative); | |
| 129 std::vector<URLRequestSummary> url_request_summaries; | |
| 130 for (const auto& kv : resources_) { | |
| 131 if (kv.second.no_store) | |
| 132 continue; | |
| 133 url_request_summaries.push_back( | |
| 134 GetURLRequestSummaryForResource(main_frame_absolute, kv.second)); | |
| 135 } | |
| 136 ResourcePrefetchPredictorTestObserver observer( | |
| 137 predictor_, UpdateAndGetVisitCount(main_frame_relative), | |
| 138 CreatePageRequestSummary(main_frame_absolute.spec(), | |
| 139 main_frame_absolute.spec(), | |
| 140 url_request_summaries)); | |
| 141 ui_test_utils::NavigateToURL(browser(), main_frame_absolute); | |
| 142 observer.Wait(); | |
| 143 } | |
| 144 | |
| 145 void AddResource(const std::string& relative_url, | |
| 146 content::ResourceType resource_type, | |
| 147 const std::string& mime_type = std::string(), | |
| 148 bool has_validators = true, | |
| 149 bool always_revalidate = false, | |
| 150 const std::string& content = std::string(), | |
| 151 bool no_store = false) { | |
| 152 ResourceSummary resource; | |
| 153 resource.url = embedded_test_server()->GetURL(relative_url); | |
| 154 resource.resource_type = resource_type; | |
| 155 resource.mime_type = mime_type; | |
| 156 resource.has_validators = has_validators; | |
| 157 resource.always_revalidate = always_revalidate; | |
| 158 resource.content = content; | |
| 159 resource.no_store = no_store; | |
| 160 resources_[relative_url] = resource; | |
| 161 } | |
| 162 | |
| 163 private: | |
| 164 URLRequestSummary GetURLRequestSummaryForResource( | |
| 165 const GURL& main_frame_url, | |
| 166 const ResourceSummary& summary) { | |
| 167 content::WebContents* web_contents = | |
| 168 browser()->tab_strip_model()->GetActiveWebContents(); | |
| 169 int process_id = web_contents->GetRenderProcessHost()->GetID(); | |
| 170 int frame_id = web_contents->GetMainFrame()->GetRoutingID(); | |
| 171 return CreateURLRequestSummary( | |
| 172 process_id, frame_id, main_frame_url.spec(), summary.url.spec(), | |
| 173 summary.resource_type, TypeToPriority(summary.resource_type), | |
| 174 summary.mime_type, summary.cached, std::string(), | |
| 175 summary.has_validators, summary.always_revalidate); | |
| 176 } | |
| 177 | |
| 178 std::unique_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { | |
| 179 auto resource_it = resources_.find(request.relative_url); | |
| 180 if (resource_it == resources_.end()) | |
| 181 return nullptr; | |
| 182 | |
| 183 const ResourceSummary& summary = resource_it->second; | |
| 184 std::unique_ptr<BasicHttpResponse> http_response(new BasicHttpResponse); | |
|
Benoit L
2016/11/02 14:03:18
nit: ()
Or better: MakeUnique
alexilin
2016/11/02 16:14:47
Done.
| |
| 185 http_response->set_code(net::HTTP_OK); | |
| 186 http_response->set_content_type(summary.mime_type); | |
| 187 http_response->set_content(summary.content); | |
| 188 if (summary.no_store) | |
| 189 http_response->AddCustomHeader("Cache-Control", "no-store"); | |
|
Benoit L
2016/11/02 14:03:18
It's possible to call this several times, good.
Th
alexilin
2016/11/02 16:14:47
Is it good or bad? I had DCHECK checked that no_st
| |
| 190 if (summary.has_validators) { | |
| 191 http_response->AddCustomHeader( | |
| 192 "ETag", base::StringPrintf("'%zu%s'", summary.version, | |
| 193 request.relative_url.c_str())); | |
| 194 } | |
| 195 if (summary.always_revalidate) | |
| 196 http_response->AddCustomHeader("Cache-Control", "no-cache"); | |
| 197 else | |
| 198 http_response->AddCustomHeader("Cache-Control", "max-age=2147483648"); | |
| 199 return std::move(http_response); | |
| 200 } | |
| 201 | |
| 202 size_t UpdateAndGetVisitCount(const std::string& main_frame_relative) { | |
| 203 return ++visit_count_[main_frame_relative]; | |
| 204 } | |
| 205 | |
| 206 ResourcePrefetchPredictor* predictor_; | |
| 207 std::map<std::string, ResourceSummary> resources_; | |
| 208 std::map<std::string, size_t> visit_count_; | |
| 209 }; | |
| 210 | |
| 211 IN_PROC_BROWSER_TEST_F(ResourcePrefetchPredictorBrowserTest, ) { | |
| 212 AddResource(kImageUrl, content::RESOURCE_TYPE_IMAGE, "image/png"); | |
| 213 AddResource(kStyleUrl, content::RESOURCE_TYPE_STYLESHEET, "text/css"); | |
| 214 AddResource(kScriptUrl, content::RESOURCE_TYPE_SCRIPT, | |
| 215 "application/javascript"); | |
| 216 AddResource(kFontUrl, content::RESOURCE_TYPE_FONT_RESOURCE, | |
| 217 "application/x-font-truetype"); | |
| 218 NavigateToURLAndCheckSubresources(kHtmlSubresourcesUrl); | |
| 219 } | |
| 220 | |
| 221 } // namespace predictors | |
| OLD | NEW |