people_provider_browsertest.cc revision 4e180b6a0b4720a9b8e9e959a882386f690f08ff
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 3// found in the LICENSE file. 4 5#include <string> 6 7#include "base/basictypes.h" 8#include "base/bind.h" 9#include "base/command_line.h" 10#include "base/memory/scoped_ptr.h" 11#include "base/run_loop.h" 12#include "base/strings/utf_string_conversions.h" 13#include "chrome/browser/profiles/profile_manager.h" 14#include "chrome/browser/ui/app_list/search/chrome_search_result.h" 15#include "chrome/browser/ui/app_list/search/people/people_provider.h" 16#include "chrome/common/chrome_switches.h" 17#include "chrome/test/base/in_process_browser_test.h" 18#include "content/public/browser/browser_thread.h" 19#include "net/test/embedded_test_server/embedded_test_server.h" 20#include "net/test/embedded_test_server/http_request.h" 21#include "net/test/embedded_test_server/http_response.h" 22 23using content::BrowserThread; 24using net::test_server::BasicHttpResponse; 25using net::test_server::HttpRequest; 26using net::test_server::HttpResponse; 27using net::test_server::EmbeddedTestServer; 28 29namespace app_list { 30namespace test { 31namespace { 32 33// Mock results. 34const char kOneResult[] = "{" 35 "\"items\":[" 36 "{" 37 "\"person\" : {" 38 "\"id\": \"1\"," 39 "\"metadata\" : {" 40 "\"ownerId\": \"1\"" 41 "}," 42 "\"names\" : [{" 43 "\"displayName\": \"first person\"" 44 "}]," 45 "\"emails\" : [{" 46 "\"value\": \"first@person.com\"" 47 "}]," 48 "\"images\" : [{" 49 "\"url\": \"http://host/icon\"" 50 "}]," 51 "\"sortKeys\" : {" 52 "\"interactionRank\": \"0.98\"" 53 "}" 54 "}" 55 "}" 56 "]}"; 57 58const char kThreeValidResults[] = "{" 59 "\"items\":[" 60 "{" 61 "\"person\" : {" 62 "\"id\": \"1\"," 63 "\"metadata\" : {" 64 "\"ownerId\": \"1\"" 65 "}," 66 "\"names\" : [{" 67 "\"displayName\": \"first person\"" 68 "}]," 69 "\"emails\" : [{" 70 "\"value\": \"first@person.com\"" 71 "}]," 72 "\"images\" : [{" 73 "\"url\": \"http://host/icon\"" 74 "}]," 75 "\"sortKeys\" : {" 76 "\"interactionRank\": \"0.98\"" 77 "}" 78 "}" 79 "}," 80 "{" 81 "\"person\" : {" 82 "\"id\": \"2\"," 83 "\"metadata\" : {" 84 "\"ownerId\": \"37\"" 85 "}," 86 "\"names\" : [{" 87 "\"displayName\": \"second person\"" 88 "}]," 89 "\"emails\" : [{" 90 "\"value\": \"second@person.com\"" 91 "}]," 92 "\"images\" : [{" 93 "\"url\": \"http://host/icon\"" 94 "}]," 95 "\"sortKeys\" : {" 96 "\"interactionRank\": \"0.84\"" 97 "}" 98 "}" 99 "}," 100 "{" 101 "\"person\" : {" 102 "\"id\": \"3\"," 103 "\"metadata\" : {" 104 "\"ownerId\": \"3\"" 105 "}," 106 "\"names\" : [{" 107 "\"displayName\": \"third person\"" 108 "}]," 109 "\"emails\" : [{" 110 "\"value\": \"third@person.com\"" 111 "}]," 112 "\"images\" : [{" 113 "\"url\": \"http://host/icon\"" 114 "}]," 115 "\"sortKeys\" : {" 116 "\"interactionRank\": \"0.67\"" 117 "}" 118 "}" 119 "}," 120 "{" 121 "\"person\" : {" 122 "\"id\": \"4\"," 123 "\"metadata\" : {" 124 "\"ownerId\": \"4\"" 125 "}," 126 "\"names\" : [{" 127 "\"displayName\": \"fourth person\"" 128 "}]," 129 "\"emails\" : [{" 130 "\"value\": \"fourth@person.com\"" 131 "}]," 132 "\"images\" : [{" 133 "\"url\": \"http://host/icon\"" 134 "}]," 135 "\"sortKeys\" : {" 136 "\"interactionRank\": \"0.0\"" 137 "}" 138 "}" 139 "}," 140 "{" 141 "\"person\" : {" 142 "\"id\": \"5\"," 143 "\"metadata\" : {" 144 "\"ownerId\": \"5\"" 145 "}," 146 "\"names\" : [{" 147 "\"displayName\": \"fifth person\"" 148 "}]," 149 "\"emails\" : [{" 150 "\"value\": \"fifth@person.com\"" 151 "}]," 152 // Images field is missing on purpose. 153 "\"sortKeys\" : {" 154 "\"interactionRank\": \"0.98\"" 155 "}" 156 "}" 157 "}" 158 "]}"; 159 160} // namespace 161 162class PeopleProviderTest : public InProcessBrowserTest { 163 public: 164 PeopleProviderTest() {} 165 virtual ~PeopleProviderTest() {} 166 167 // InProcessBrowserTest overrides: 168 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 169 command_line->AppendSwitch(switches::kEnablePeopleSearch); 170 } 171 172 virtual void SetUpOnMainThread() OVERRIDE { 173 test_server_.reset(new EmbeddedTestServer( 174 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO))); 175 176 ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady()); 177 test_server_->RegisterRequestHandler( 178 base::Bind(&PeopleProviderTest::HandleRequest, 179 base::Unretained(this))); 180 181 people_provider_.reset(new PeopleProvider( 182 ProfileManager::GetDefaultProfile())); 183 184 people_provider_->SetupForTest( 185 base::Bind(&PeopleProviderTest::OnSearchResultsFetched, 186 base::Unretained(this)), 187 test_server_->base_url()); 188 people_provider_->set_use_throttling(false); 189 } 190 191 virtual void CleanUpOnMainThread() OVERRIDE { 192 EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete()); 193 test_server_.reset(); 194 } 195 196 std::string RunQuery(const std::string& query, 197 const std::string& mock_server_response) { 198 people_provider_->Start(UTF8ToUTF16(query)); 199 200 if (people_provider_->people_search_ && !mock_server_response.empty()) { 201 mock_server_response_ = mock_server_response; 202 203 DCHECK(!run_loop_); 204 run_loop_.reset(new base::RunLoop); 205 run_loop_->Run(); 206 run_loop_.reset(); 207 208 mock_server_response_.clear(); 209 } 210 211 people_provider_->Stop(); 212 return GetResults(); 213 } 214 215 std::string GetResults() const { 216 std::string results; 217 for (SearchProvider::Results::const_iterator it = 218 people_provider_->results().begin(); 219 it != people_provider_->results().end(); 220 ++it) { 221 if (!results.empty()) 222 results += ','; 223 results += UTF16ToUTF8((*it)->title()); 224 } 225 return results; 226 } 227 228 PeopleProvider* people_provider() { return people_provider_.get(); } 229 230 private: 231 scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) { 232 scoped_ptr<BasicHttpResponse> response(new BasicHttpResponse); 233 response->set_code(net::HTTP_OK); 234 response->set_content(mock_server_response_); 235 236 return response.PassAs<HttpResponse>(); 237 } 238 239 void OnSearchResultsFetched() { 240 if (run_loop_) 241 run_loop_->Quit(); 242 } 243 244 scoped_ptr<EmbeddedTestServer> test_server_; 245 scoped_ptr<base::RunLoop> run_loop_; 246 247 std::string mock_server_response_; 248 249 scoped_ptr<PeopleProvider> people_provider_; 250 251 DISALLOW_COPY_AND_ASSIGN(PeopleProviderTest); 252}; 253 254IN_PROC_BROWSER_TEST_F(PeopleProviderTest, Basic) { 255 struct { 256 const char* query; 257 const char* mock_server_response; 258 const char* expected_results_content; 259 } kTestCases[] = { 260 {"first", kOneResult, "first person" }, 261 {"person", kThreeValidResults, "first person,second person,third person" }, 262 }; 263 264 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) { 265 EXPECT_EQ(kTestCases[i].expected_results_content, 266 RunQuery(kTestCases[i].query, 267 kTestCases[i].mock_server_response)) 268 << "Case " << i << ": q=" << kTestCases[i].query; 269 } 270} 271 272IN_PROC_BROWSER_TEST_F(PeopleProviderTest, NoSearchForSensitiveData) { 273 // None of the following input strings should be accepted because they may 274 // contain private data. 275 const char* inputs[] = { 276 // file: scheme is bad. 277 "file://filename", 278 "FILE://filename", 279 // URLs with usernames, ports, queries or refs are bad. 280 "http://username:password@hostname/", 281 "http://www.example.com:1000", 282 "http://foo:1000", 283 "http://hostname/?query=q", 284 "http://hostname/path#ref", 285 // A https URL with path is bad. 286 "https://hostname/path", 287 }; 288 289 for (size_t i = 0; i < arraysize(inputs); ++i) 290 EXPECT_EQ("", RunQuery(inputs[i], kOneResult)); 291} 292 293IN_PROC_BROWSER_TEST_F(PeopleProviderTest, NoSearchForShortQueries) { 294 EXPECT_EQ("", RunQuery("f", kOneResult)); 295 EXPECT_EQ("", RunQuery("fi", kOneResult)); 296 EXPECT_EQ("first person", RunQuery("fir", kOneResult)); 297} 298 299} // namespace test 300} // namespace app_list 301