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

Side by Side Diff: chrome/browser/ui/app_list/search/answer_card/answer_card_search_provider.cc

Issue 2947283002: Unit-testing AnswerCardSearchProvider. (Closed)
Patch Set: CR comments Created 3 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/ui/app_list/search/answer_card/answer_card_search_provi der.h" 5 #include "chrome/browser/ui/app_list/search/answer_card/answer_card_search_provi der.h"
6 6
7 #include <utility> 7 #include <utility>
8 8
9 #include "base/command_line.h" 9 #include "base/command_line.h"
10 #include "base/metrics/histogram_macros.h" 10 #include "base/metrics/histogram_macros.h"
11 #include "base/metrics/user_metrics.h" 11 #include "base/metrics/user_metrics.h"
12 #include "base/strings/utf_string_conversions.h" 12 #include "base/strings/utf_string_conversions.h"
13 #include "chrome/browser/search_engines/template_url_service_factory.h" 13 #include "chrome/browser/search_engines/template_url_service_factory.h"
14 #include "chrome/browser/ui/app_list/search/answer_card/answer_card_result.h" 14 #include "chrome/browser/ui/app_list/search/answer_card/answer_card_result.h"
15 #include "chrome/browser/ui/browser_navigator.h" 15 #include "chrome/browser/ui/browser_navigator.h"
16 #include "chrome/browser/ui/browser_navigator_params.h" 16 #include "chrome/browser/ui/browser_navigator_params.h"
17 #include "components/omnibox/browser/autocomplete_input.h" 17 #include "components/omnibox/browser/autocomplete_input.h"
18 #include "components/omnibox/browser/autocomplete_match.h" 18 #include "components/omnibox/browser/autocomplete_match.h"
19 #include "components/search_engines/template_url_service.h" 19 #include "components/search_engines/template_url_service.h"
20 #include "content/public/browser/navigation_handle.h"
21 #include "content/public/browser/page_navigator.h"
22 #include "net/http/http_response_headers.h"
23 #include "net/http/http_status_code.h"
24 #include "ui/app_list/app_list_features.h" 20 #include "ui/app_list/app_list_features.h"
25 #include "ui/app_list/app_list_model.h" 21 #include "ui/app_list/app_list_model.h"
26 #include "ui/app_list/search_box_model.h" 22 #include "ui/app_list/search_box_model.h"
27 23
28 namespace app_list { 24 namespace app_list {
29 25
30 namespace { 26 namespace {
31 27
32 enum class SearchAnswerRequestResult { 28 enum class SearchAnswerRequestResult {
33 REQUEST_RESULT_ANOTHER_REQUEST_STARTED = 0, 29 REQUEST_RESULT_ANOTHER_REQUEST_STARTED = 0,
34 REQUEST_RESULT_REQUEST_FAILED = 1, 30 REQUEST_RESULT_REQUEST_FAILED = 1,
35 REQUEST_RESULT_NO_ANSWER = 2, 31 REQUEST_RESULT_NO_ANSWER = 2,
36 REQUEST_RESULT_RECEIVED_ANSWER = 3, 32 REQUEST_RESULT_RECEIVED_ANSWER = 3,
37 REQUEST_RESULT_RECEIVED_ANSWER_TOO_LARGE = 4, 33 REQUEST_RESULT_RECEIVED_ANSWER_TOO_LARGE = 4,
38 REQUEST_RESULT_MAX = 5 34 REQUEST_RESULT_MAX = 5
39 }; 35 };
40 36
41 constexpr char kSearchAnswerHasResult[] = "SearchAnswer-HasResult";
42 constexpr char kSearchAnswerIssuedQuery[] = "SearchAnswer-IssuedQuery";
43 constexpr char kSearchAnswerTitle[] = "SearchAnswer-Title";
44
45 void RecordRequestResult(SearchAnswerRequestResult request_result) { 37 void RecordRequestResult(SearchAnswerRequestResult request_result) {
46 UMA_HISTOGRAM_ENUMERATION("SearchAnswer.RequestResult", request_result, 38 UMA_HISTOGRAM_ENUMERATION("SearchAnswer.RequestResult", request_result,
47 SearchAnswerRequestResult::REQUEST_RESULT_MAX); 39 SearchAnswerRequestResult::REQUEST_RESULT_MAX);
48 } 40 }
49 41
50 } // namespace 42 } // namespace
51 43
52 AnswerCardSearchProvider::AnswerCardSearchProvider( 44 AnswerCardSearchProvider::AnswerCardSearchProvider(
53 Profile* profile, 45 Profile* profile,
54 app_list::AppListModel* model, 46 app_list::AppListModel* model,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 void AnswerCardSearchProvider::UpdatePreferredSize(const gfx::Size& pref_size) { 101 void AnswerCardSearchProvider::UpdatePreferredSize(const gfx::Size& pref_size) {
110 preferred_size_ = pref_size; 102 preferred_size_ = pref_size;
111 OnResultAvailable(received_answer_ && IsCardSizeOk() && 103 OnResultAvailable(received_answer_ && IsCardSizeOk() &&
112 !contents_->IsLoading()); 104 !contents_->IsLoading());
113 if (!answer_loaded_time_.is_null()) { 105 if (!answer_loaded_time_.is_null()) {
114 UMA_HISTOGRAM_TIMES("SearchAnswer.ResizeAfterLoadTime", 106 UMA_HISTOGRAM_TIMES("SearchAnswer.ResizeAfterLoadTime",
115 base::TimeTicks::Now() - answer_loaded_time_); 107 base::TimeTicks::Now() - answer_loaded_time_);
116 } 108 }
117 } 109 }
118 110
119 content::WebContents* AnswerCardSearchProvider::OpenURLFromTab(
120 const content::OpenURLParams& params) {
121 // Open the user-clicked link in the browser taking into account the requested
122 // disposition.
123 chrome::NavigateParams new_tab_params(profile_, params.url,
124 params.transition);
125
126 new_tab_params.disposition = params.disposition;
127
128 if (params.disposition == WindowOpenDisposition::NEW_BACKGROUND_TAB) {
129 // When the user asks to open a link as a background tab, we show an
130 // activated window with the new activated tab after the user closes the
131 // launcher. So it's "background" relative to the launcher itself.
132 new_tab_params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
133 new_tab_params.window_action = chrome::NavigateParams::SHOW_WINDOW_INACTIVE;
134 }
135
136 chrome::Navigate(&new_tab_params);
137
138 base::RecordAction(base::UserMetricsAction("SearchAnswer_OpenedUrl"));
139
140 return new_tab_params.target_contents;
141 }
142
143 void AnswerCardSearchProvider::DidFinishNavigation( 111 void AnswerCardSearchProvider::DidFinishNavigation(
144 content::NavigationHandle* navigation_handle) { 112 const GURL& url,
145 if (navigation_handle->GetURL() != current_request_url_) { 113 bool has_error,
114 bool has_answer_card,
115 const std::string& result_title,
116 const std::string& issued_query) {
117 if (url != current_request_url_) {
146 // TODO(vadimt): Remove this and similar logging once testing is complete if 118 // TODO(vadimt): Remove this and similar logging once testing is complete if
147 // we think this is not useful after release or happens too frequently. 119 // we think this is not useful after release or happens too frequently.
148 VLOG(1) << "DidFinishNavigation: Another request started"; 120 VLOG(1) << "DidFinishNavigation: Another request started";
149 RecordRequestResult( 121 RecordRequestResult(
150 SearchAnswerRequestResult::REQUEST_RESULT_ANOTHER_REQUEST_STARTED); 122 SearchAnswerRequestResult::REQUEST_RESULT_ANOTHER_REQUEST_STARTED);
151 return; 123 return;
152 } 124 }
153 125
154 VLOG(1) << "DidFinishNavigation: Latest request completed"; 126 VLOG(1) << "DidFinishNavigation: Latest request completed";
155 if (!navigation_handle->HasCommitted() || navigation_handle->IsErrorPage() || 127 if (has_error) {
156 !navigation_handle->IsInMainFrame()) {
157 LOG(ERROR) << "Failed to navigate: HasCommitted="
158 << navigation_handle->HasCommitted()
159 << ", IsErrorPage=" << navigation_handle->IsErrorPage()
160 << ", IsInMainFrame=" << navigation_handle->IsInMainFrame();
161 RecordRequestResult( 128 RecordRequestResult(
162 SearchAnswerRequestResult::REQUEST_RESULT_REQUEST_FAILED); 129 SearchAnswerRequestResult::REQUEST_RESULT_REQUEST_FAILED);
163 return; 130 return;
164 } 131 }
165 132
166 if (!features::IsAnswerCardDarkRunEnabled()) { 133 if (!features::IsAnswerCardDarkRunEnabled()) {
167 if (!ParseResponseHeaders(navigation_handle->GetResponseHeaders())) { 134 if (!has_answer_card || result_title.empty()) {
168 RecordRequestResult(SearchAnswerRequestResult::REQUEST_RESULT_NO_ANSWER); 135 RecordRequestResult(SearchAnswerRequestResult::REQUEST_RESULT_NO_ANSWER);
169 return; 136 return;
170 } 137 }
138 result_title_ = result_title;
139 if (!issued_query.empty())
140 result_url_ = GetResultUrl(base::UTF8ToUTF16(issued_query));
171 } else { 141 } else {
172 // In the dark run mode, every other "server response" contains a card. 142 // In the dark run mode, every other "server response" contains a card.
173 dark_run_received_answer_ = !dark_run_received_answer_; 143 dark_run_received_answer_ = !dark_run_received_answer_;
174 if (!dark_run_received_answer_) 144 if (!dark_run_received_answer_)
175 return; 145 return;
176 // SearchResult requires a non-empty id. This "url" will never be opened. 146 // SearchResult requires a non-empty id. This "url" will never be opened.
177 result_url_ = "some string"; 147 result_url_ = "https://www.google.com/?q=something";
178 } 148 }
179 149
180 received_answer_ = true; 150 received_answer_ = true;
181 UMA_HISTOGRAM_TIMES("SearchAnswer.NavigationTime", 151 UMA_HISTOGRAM_TIMES("SearchAnswer.NavigationTime",
182 base::TimeTicks::Now() - server_request_start_time_); 152 base::TimeTicks::Now() - server_request_start_time_);
183 } 153 }
184 154
185 void AnswerCardSearchProvider::DidStopLoading() { 155 void AnswerCardSearchProvider::DidStopLoading() {
186 if (!received_answer_) 156 if (!received_answer_)
187 return; 157 return;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
231 GURL(result_url_), AutocompleteInput(), template_url_service_, 201 GURL(result_url_), AutocompleteInput(), template_url_service_,
232 base::string16() /* keyword */); 202 base::string16() /* keyword */);
233 203
234 results.emplace_back(base::MakeUnique<AnswerCardResult>( 204 results.emplace_back(base::MakeUnique<AnswerCardResult>(
235 profile_, list_controller_, result_url_, stripped_result_url.spec(), 205 profile_, list_controller_, result_url_, stripped_result_url.spec(),
236 base::UTF8ToUTF16(result_title_), contents_.get())); 206 base::UTF8ToUTF16(result_title_), contents_.get()));
237 } 207 }
238 SwapResults(&results); 208 SwapResults(&results);
239 } 209 }
240 210
241 bool AnswerCardSearchProvider::ParseResponseHeaders(
242 const net::HttpResponseHeaders* headers) {
243 if (!headers) {
244 LOG(ERROR) << "Failed to parse response headers: no headers";
245 return false;
246 }
247 if (headers->response_code() != net::HTTP_OK) {
248 LOG(ERROR) << "Failed to parse response headers: response code="
249 << headers->response_code();
250 return false;
251 }
252 if (!headers->HasHeaderValue(kSearchAnswerHasResult, "true")) {
253 LOG(ERROR) << "Failed to parse response headers: " << kSearchAnswerHasResult
254 << " header != true";
255 return false;
256 }
257 if (!headers->GetNormalizedHeader(kSearchAnswerTitle, &result_title_)) {
258 LOG(ERROR) << "Failed to parse response headers: " << kSearchAnswerTitle
259 << " header is not present";
260 return false;
261 }
262
263 std::string issued_query;
264 // TODO(749320): Make the header mandatory once the production server starts
265 // serving it.
266 if (headers->GetNormalizedHeader(kSearchAnswerIssuedQuery, &issued_query)) {
267 // The header contains the autocompleted query that corresponds to the card
268 // contents. Use it for the open-URL, and for deduplication with the omnibox
269 // search results.
270 result_url_ = GetResultUrl(base::UTF8ToUTF16(issued_query));
271 } else {
272 VLOG(1) << "Warning: " << kSearchAnswerIssuedQuery
273 << " header is not present";
274 }
275
276 return true;
277 }
278
279 std::string AnswerCardSearchProvider::GetResultUrl( 211 std::string AnswerCardSearchProvider::GetResultUrl(
280 const base::string16& query) const { 212 const base::string16& query) const {
281 return template_url_service_->GetDefaultSearchProvider() 213 return template_url_service_->GetDefaultSearchProvider()
282 ->url_ref() 214 ->url_ref()
283 .ReplaceSearchTerms(TemplateURLRef::SearchTermsArgs(query), 215 .ReplaceSearchTerms(TemplateURLRef::SearchTermsArgs(query),
284 template_url_service_->search_terms_data()); 216 template_url_service_->search_terms_data());
285 } 217 }
286 218
287 } // namespace app_list 219 } // namespace app_list
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698