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