OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 <string> | 5 #include <string> |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
11 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
12 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
13 #include "chrome/browser/profiles/profile_manager.h" | 13 #include "chrome/browser/profiles/profile_manager.h" |
14 #include "chrome/browser/ui/app_list/search/chrome_search_result.h" | 14 #include "chrome/browser/ui/app_list/search/chrome_search_result.h" |
15 #include "chrome/browser/ui/app_list/search/webstore_provider.h" | 15 #include "chrome/browser/ui/app_list/search/people/people_provider.h" |
16 #include "chrome/common/chrome_switches.h" | 16 #include "chrome/common/chrome_switches.h" |
17 #include "chrome/test/base/in_process_browser_test.h" | 17 #include "chrome/test/base/in_process_browser_test.h" |
18 #include "content/public/browser/browser_thread.h" | 18 #include "content/public/browser/browser_thread.h" |
19 #include "net/test/embedded_test_server/embedded_test_server.h" | 19 #include "net/test/embedded_test_server/embedded_test_server.h" |
20 #include "net/test/embedded_test_server/http_request.h" | 20 #include "net/test/embedded_test_server/http_request.h" |
21 #include "net/test/embedded_test_server/http_response.h" | 21 #include "net/test/embedded_test_server/http_response.h" |
22 | 22 |
23 using content::BrowserThread; | 23 using content::BrowserThread; |
24 using net::test_server::BasicHttpResponse; | 24 using net::test_server::BasicHttpResponse; |
25 using net::test_server::HttpRequest; | 25 using net::test_server::HttpRequest; |
26 using net::test_server::HttpResponse; | 26 using net::test_server::HttpResponse; |
27 using net::test_server::EmbeddedTestServer; | 27 using net::test_server::EmbeddedTestServer; |
28 | 28 |
29 namespace app_list { | 29 namespace app_list { |
30 namespace test { | 30 namespace test { |
31 namespace { | 31 namespace { |
32 | 32 |
33 // Mock results. | 33 // Mock results. |
34 const char kOneResult[] = "{" | 34 const char kOneResult[] = "{" |
35 "\"search_url\": \"http://host/search\"," | 35 "\"items\":[" |
36 "\"results\":[" | |
37 "{" | 36 "{" |
38 "\"id\": \"app1_id\"," | 37 "\"person\" : {" |
39 "\"localized_name\": \"app1 name\"," | 38 "\"id\": \"1\"," |
40 "\"icon_url\": \"http://host/icon\"" | 39 "\"names\" : [{" |
| 40 "\"displayName\": \"first person\"" |
| 41 "}]," |
| 42 "\"images\" : [{" |
| 43 "\"url\": \"http://host/icon\"" |
| 44 "}]," |
| 45 "\"sortKeys\" : {" |
| 46 "\"interactionRank\": \"0.98\"" |
| 47 "}" |
| 48 "}" |
41 "}" | 49 "}" |
42 "]}"; | 50 "]}"; |
43 | 51 |
44 const char kThreeResults[] = "{" | 52 const char kThreeValidResults[] = "{" |
45 "\"search_url\": \"http://host/search\"," | 53 "\"items\":[" |
46 "\"results\":[" | |
47 "{" | 54 "{" |
48 "\"id\": \"app1_id\"," | 55 "\"person\" : {" |
49 "\"localized_name\": \"one\"," | 56 "\"id\": \"1\"," |
50 "\"icon_url\": \"http://host/icon\"" | 57 "\"names\" : [{" |
| 58 "\"displayName\": \"first person\"" |
| 59 "}]," |
| 60 "\"images\" : [{" |
| 61 "\"url\": \"http://host/icon\"" |
| 62 "}]," |
| 63 "\"sortKeys\" : {" |
| 64 "\"interactionRank\": \"0.98\"" |
| 65 "}" |
| 66 "}" |
51 "}," | 67 "}," |
52 "{" | 68 "{" |
53 "\"id\": \"app2_id\"," | 69 "\"person\" : {" |
54 "\"localized_name\": \"two\"," | 70 "\"id\": \"2\"," |
55 "\"icon_url\": \"http://host/icon\"" | 71 "\"names\" : [{" |
| 72 "\"displayName\": \"second person\"" |
| 73 "}]," |
| 74 "\"images\" : [{" |
| 75 "\"url\": \"http://host/icon\"" |
| 76 "}]," |
| 77 "\"sortKeys\" : {" |
| 78 "\"interactionRank\": \"0.84\"" |
| 79 "}" |
| 80 "}" |
56 "}," | 81 "}," |
57 "{" | 82 "{" |
58 "\"id\": \"app3_id\"," | 83 "\"person\" : {" |
59 "\"localized_name\": \"three\"," | 84 "\"id\": \"3\"," |
60 "\"icon_url\": \"http://host/icon\"" | 85 "\"names\" : [{" |
| 86 "\"displayName\": \"third person\"" |
| 87 "}]," |
| 88 "\"images\" : [{" |
| 89 "\"url\": \"http://host/icon\"" |
| 90 "}]," |
| 91 "\"sortKeys\" : {" |
| 92 "\"interactionRank\": \"0.67\"" |
| 93 "}" |
| 94 "}" |
| 95 "}," |
| 96 "{" |
| 97 "\"person\" : {" |
| 98 "\"id\": \"4\"," |
| 99 "\"names\" : [{" |
| 100 "\"displayName\": \"fourth person\"" |
| 101 "}]," |
| 102 "\"images\" : [{" |
| 103 "\"url\": \"http://host/icon\"" |
| 104 "}]," |
| 105 "\"sortKeys\" : {" |
| 106 "\"interactionRank\": \"0.0\"" |
| 107 "}" |
| 108 "}" |
| 109 "}," |
| 110 "{" |
| 111 "\"person\" : {" |
| 112 "\"id\": \"5\"," |
| 113 "\"names\" : [{" |
| 114 "\"displayName\": \"fifth person\"" |
| 115 "}]," |
| 116 // Images field is missing on purpose. |
| 117 "\"sortKeys\" : {" |
| 118 "\"interactionRank\": \"0.98\"" |
| 119 "}" |
| 120 "}" |
61 "}" | 121 "}" |
62 "]}"; | 122 "]}"; |
63 | 123 |
64 } // namespace | 124 } // namespace |
65 | 125 |
66 class WebstoreProviderTest : public InProcessBrowserTest { | 126 class PeopleProviderTest : public InProcessBrowserTest { |
67 public: | 127 public: |
68 WebstoreProviderTest() {} | 128 PeopleProviderTest() {} |
69 virtual ~WebstoreProviderTest() {} | 129 virtual ~PeopleProviderTest() {} |
70 | 130 |
71 // InProcessBrowserTest overrides: | 131 // InProcessBrowserTest overrides: |
72 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | 132 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
73 command_line->AppendSwitchASCII(switches::kForceFieldTrials, | 133 command_line->AppendSwitch(switches::kEnablePeopleSearch); |
74 "LauncherUseWebstoreSearch/Enable/"); | |
75 } | 134 } |
76 | 135 |
77 virtual void SetUpOnMainThread() OVERRIDE { | 136 virtual void SetUpOnMainThread() OVERRIDE { |
78 test_server_.reset(new EmbeddedTestServer( | 137 test_server_.reset(new EmbeddedTestServer( |
79 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))); | 138 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))); |
80 | 139 |
81 ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady()); | 140 ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady()); |
82 test_server_->RegisterRequestHandler( | 141 test_server_->RegisterRequestHandler( |
83 base::Bind(&WebstoreProviderTest::HandleRequest, | 142 base::Bind(&PeopleProviderTest::HandleRequest, |
84 base::Unretained(this))); | 143 base::Unretained(this))); |
85 CommandLine::ForCurrentProcess()->AppendSwitchASCII( | |
86 switches::kAppsGalleryURL, test_server_->base_url().spec()); | |
87 | 144 |
88 webstore_provider_.reset(new WebstoreProvider( | 145 people_provider_.reset(new PeopleProvider( |
89 ProfileManager::GetDefaultProfile(), NULL)); | 146 ProfileManager::GetDefaultProfile())); |
90 webstore_provider_->set_webstore_search_fetched_callback( | 147 |
91 base::Bind(&WebstoreProviderTest::OnSearchResultsFetched, | 148 people_provider_->SetupForTest( |
92 base::Unretained(this))); | 149 base::Bind(&PeopleProviderTest::OnSearchResultsFetched, |
93 // TODO(mukai): add test cases for throttling. | 150 base::Unretained(this)), |
94 webstore_provider_->set_use_throttling(false); | 151 test_server_->base_url()); |
| 152 people_provider_->set_use_throttling(false); |
95 } | 153 } |
96 | 154 |
97 virtual void CleanUpOnMainThread() OVERRIDE { | 155 virtual void CleanUpOnMainThread() OVERRIDE { |
98 EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete()); | 156 EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete()); |
99 test_server_.reset(); | 157 test_server_.reset(); |
100 } | 158 } |
101 | 159 |
102 std::string RunQuery(const std::string& query, | 160 std::string RunQuery(const std::string& query, |
103 const std::string& mock_server_response) { | 161 const std::string& mock_server_response) { |
104 webstore_provider_->Start(UTF8ToUTF16(query)); | 162 people_provider_->Start(UTF8ToUTF16(query)); |
105 | 163 |
106 if (webstore_provider_->webstore_search_ && !mock_server_response.empty()) { | 164 if (people_provider_->people_search_ && !mock_server_response.empty()) { |
107 mock_server_response_ = mock_server_response; | 165 mock_server_response_ = mock_server_response; |
108 | 166 |
109 DCHECK(!run_loop_); | 167 DCHECK(!run_loop_); |
110 run_loop_.reset(new base::RunLoop); | 168 run_loop_.reset(new base::RunLoop); |
111 run_loop_->Run(); | 169 run_loop_->Run(); |
112 run_loop_.reset(); | 170 run_loop_.reset(); |
113 | 171 |
114 mock_server_response_.clear(); | 172 mock_server_response_.clear(); |
115 } | 173 } |
116 | 174 |
117 webstore_provider_->Stop(); | 175 people_provider_->Stop(); |
118 return GetResults(); | 176 return GetResults(); |
119 } | 177 } |
120 | 178 |
121 std::string GetResults() const { | 179 std::string GetResults() const { |
122 std::string results; | 180 std::string results; |
123 for (SearchProvider::Results::const_iterator it = | 181 for (SearchProvider::Results::const_iterator it = |
124 webstore_provider_->results().begin(); | 182 people_provider_->results().begin(); |
125 it != webstore_provider_->results().end(); | 183 it != people_provider_->results().end(); |
126 ++it) { | 184 ++it) { |
127 if (!results.empty()) | 185 if (!results.empty()) |
128 results += ','; | 186 results += ','; |
129 results += UTF16ToUTF8((*it)->title()); | 187 results += UTF16ToUTF8((*it)->title()); |
130 } | 188 } |
131 return results; | 189 return results; |
132 } | 190 } |
133 | 191 |
134 WebstoreProvider* webstore_provider() { return webstore_provider_.get(); } | 192 PeopleProvider* people_provider() { return people_provider_.get(); } |
135 | 193 |
136 private: | 194 private: |
137 scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { | 195 scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { |
138 scoped_ptr<BasicHttpResponse> response(new BasicHttpResponse); | 196 scoped_ptr<BasicHttpResponse> response(new BasicHttpResponse); |
139 | 197 response->set_code(net::HTTP_OK); |
140 if (request.relative_url.find("/jsonsearch?") != std::string::npos) { | 198 response->set_content(mock_server_response_); |
141 if (mock_server_response_ == "404") { | |
142 response->set_code(net::HTTP_NOT_FOUND); | |
143 } else if (mock_server_response_ == "500") { | |
144 response->set_code(net::HTTP_INTERNAL_SERVER_ERROR); | |
145 } else { | |
146 response->set_code(net::HTTP_OK); | |
147 response->set_content(mock_server_response_); | |
148 } | |
149 } | |
150 | 199 |
151 return response.PassAs<HttpResponse>(); | 200 return response.PassAs<HttpResponse>(); |
152 } | 201 } |
153 | 202 |
154 void OnSearchResultsFetched() { | 203 void OnSearchResultsFetched() { |
155 if (run_loop_) | 204 if (run_loop_) |
156 run_loop_->Quit(); | 205 run_loop_->Quit(); |
157 } | 206 } |
158 | 207 |
159 scoped_ptr<EmbeddedTestServer> test_server_; | 208 scoped_ptr<EmbeddedTestServer> test_server_; |
160 scoped_ptr<base::RunLoop> run_loop_; | 209 scoped_ptr<base::RunLoop> run_loop_; |
161 | 210 |
162 std::string mock_server_response_; | 211 std::string mock_server_response_; |
163 | 212 |
164 scoped_ptr<WebstoreProvider> webstore_provider_; | 213 scoped_ptr<PeopleProvider> people_provider_; |
165 | 214 |
166 DISALLOW_COPY_AND_ASSIGN(WebstoreProviderTest); | 215 DISALLOW_COPY_AND_ASSIGN(PeopleProviderTest); |
167 }; | 216 }; |
168 | 217 |
169 // Flaky on Windows: http://crbug.com/246136. | 218 IN_PROC_BROWSER_TEST_F(PeopleProviderTest, Basic) { |
170 #if defined(OS_WIN) | |
171 #define MAYBE_Basic DISABLED_Basic | |
172 #else | |
173 #define MAYBE_Basic Basic | |
174 #endif | |
175 IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, MAYBE_Basic) { | |
176 struct { | 219 struct { |
177 const char* query; | 220 const char* query; |
178 const char* mock_server_response; | 221 const char* mock_server_response; |
179 const char* expected_results_content; | 222 const char* expected_results_content; |
180 } kTestCases[] = { | 223 } kTestCases[] = { |
181 // "Search in web store" result with query text itself is used for | 224 {"first", kOneResult, "first person" }, |
182 // synchronous placeholder, bad server response etc. | 225 {"person", kThreeValidResults, "first person,second person,third person" }, |
183 {"synchronous", "", "synchronous" }, | |
184 {"404", "404", "404" }, | |
185 {"500", "500", "500" }, | |
186 {"bad json", "invalid json", "bad json" }, | |
187 // Good results. | |
188 {"1 result", kOneResult, "app1 name" }, | |
189 {"3 result", kThreeResults, "one,two,three" }, | |
190 }; | 226 }; |
191 | 227 |
192 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { | 228 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { |
193 EXPECT_EQ(kTestCases[i].expected_results_content, | 229 EXPECT_EQ(kTestCases[i].expected_results_content, |
194 RunQuery(kTestCases[i].query, | 230 RunQuery(kTestCases[i].query, |
195 kTestCases[i].mock_server_response)) | 231 kTestCases[i].mock_server_response)) |
196 << "Case " << i << ": q=" << kTestCases[i].query; | 232 << "Case " << i << ": q=" << kTestCases[i].query; |
197 } | 233 } |
198 } | 234 } |
199 | 235 |
200 IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, NoSearchForSensitiveData) { | 236 IN_PROC_BROWSER_TEST_F(PeopleProviderTest, NoSearchForSensitiveData) { |
201 // None of the following input strings should be accepted because they may | 237 // None of the following input strings should be accepted because they may |
202 // contain private data. | 238 // contain private data. |
203 const char* inputs[] = { | 239 const char* inputs[] = { |
204 // file: scheme is bad. | 240 // file: scheme is bad. |
205 "file://filename", | 241 "file://filename", |
206 "FILE://filename", | 242 "FILE://filename", |
207 // URLs with usernames, ports, queries or refs are bad. | 243 // URLs with usernames, ports, queries or refs are bad. |
208 "http://username:password@hostname/", | 244 "http://username:password@hostname/", |
209 "http://www.example.com:1000", | 245 "http://www.example.com:1000", |
210 "http://foo:1000", | 246 "http://foo:1000", |
211 "http://hostname/?query=q", | 247 "http://hostname/?query=q", |
212 "http://hostname/path#ref", | 248 "http://hostname/path#ref", |
213 // A https URL with path is bad. | 249 // A https URL with path is bad. |
214 "https://hostname/path", | 250 "https://hostname/path", |
215 }; | 251 }; |
216 | 252 |
217 for (size_t i = 0; i < arraysize(inputs); ++i) | 253 for (size_t i = 0; i < arraysize(inputs); ++i) |
218 EXPECT_EQ("", RunQuery(inputs[i], kOneResult)); | 254 EXPECT_EQ("", RunQuery(inputs[i], kOneResult)); |
219 } | 255 } |
220 | 256 |
221 IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, NoSearchForShortQueries) { | 257 IN_PROC_BROWSER_TEST_F(PeopleProviderTest, NoSearchForShortQueries) { |
222 EXPECT_EQ("", RunQuery("a", kOneResult)); | 258 EXPECT_EQ("", RunQuery("f", kOneResult)); |
223 EXPECT_EQ("", RunQuery("ab", kOneResult)); | 259 EXPECT_EQ("", RunQuery("fi", kOneResult)); |
224 EXPECT_EQ("app1 name", RunQuery("abc", kOneResult)); | 260 EXPECT_EQ("first person", RunQuery("fir", kOneResult)); |
225 } | |
226 | |
227 IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, SearchCache) { | |
228 EXPECT_EQ("app1 name", RunQuery("foo", kOneResult)); | |
229 | |
230 // No result is provided but the provider gets the result from the cache. | |
231 EXPECT_EQ("app1 name", RunQuery("foo", "")); | |
232 } | 261 } |
233 | 262 |
234 } // namespace test | 263 } // namespace test |
235 } // namespace app_list | 264 } // namespace app_list |
OLD | NEW |