people_provider_browsertest.cc revision 0f1bc08d4cfcc34181b0b5cbf065c40f687bf740
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
175    ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
176    test_server_->RegisterRequestHandler(
177        base::Bind(&PeopleProviderTest::HandleRequest,
178                   base::Unretained(this)));
179
180    people_provider_.reset(new PeopleProvider(
181        ProfileManager::GetDefaultProfile()));
182
183    people_provider_->SetupForTest(
184        base::Bind(&PeopleProviderTest::OnSearchResultsFetched,
185                   base::Unretained(this)),
186        test_server_->base_url());
187    people_provider_->set_use_throttling(false);
188  }
189
190  virtual void CleanUpOnMainThread() OVERRIDE {
191    EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete());
192    test_server_.reset();
193  }
194
195  std::string RunQuery(const std::string& query,
196                       const std::string& mock_server_response) {
197    people_provider_->Start(UTF8ToUTF16(query));
198
199    if (people_provider_->people_search_ && !mock_server_response.empty()) {
200      mock_server_response_ = mock_server_response;
201
202      DCHECK(!run_loop_);
203      run_loop_.reset(new base::RunLoop);
204      run_loop_->Run();
205      run_loop_.reset();
206
207      mock_server_response_.clear();
208    }
209
210    people_provider_->Stop();
211    return GetResults();
212  }
213
214  std::string GetResults() const {
215    std::string results;
216    for (SearchProvider::Results::const_iterator it =
217             people_provider_->results().begin();
218         it != people_provider_->results().end();
219         ++it) {
220      if (!results.empty())
221        results += ',';
222      results += UTF16ToUTF8((*it)->title());
223    }
224    return results;
225  }
226
227  PeopleProvider* people_provider() { return people_provider_.get(); }
228
229 private:
230  scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
231    scoped_ptr<BasicHttpResponse> response(new BasicHttpResponse);
232    response->set_code(net::HTTP_OK);
233    response->set_content(mock_server_response_);
234
235    return response.PassAs<HttpResponse>();
236  }
237
238  void OnSearchResultsFetched() {
239    if (run_loop_)
240      run_loop_->Quit();
241  }
242
243  scoped_ptr<EmbeddedTestServer> test_server_;
244  scoped_ptr<base::RunLoop> run_loop_;
245
246  std::string mock_server_response_;
247
248  scoped_ptr<PeopleProvider> people_provider_;
249
250  DISALLOW_COPY_AND_ASSIGN(PeopleProviderTest);
251};
252
253IN_PROC_BROWSER_TEST_F(PeopleProviderTest, Basic) {
254  struct {
255    const char* query;
256    const char* mock_server_response;
257    const char* expected_results_content;
258  } kTestCases[] = {
259    {"first", kOneResult, "first person" },
260    {"person", kThreeValidResults, "first person,second person,third person" },
261  };
262
263  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
264    EXPECT_EQ(kTestCases[i].expected_results_content,
265              RunQuery(kTestCases[i].query,
266                       kTestCases[i].mock_server_response))
267        << "Case " << i << ": q=" << kTestCases[i].query;
268  }
269}
270
271IN_PROC_BROWSER_TEST_F(PeopleProviderTest, NoSearchForSensitiveData) {
272  // None of the following input strings should be accepted because they may
273  // contain private data.
274  const char* inputs[] = {
275    // file: scheme is bad.
276    "file://filename",
277    "FILE://filename",
278    // URLs with usernames, ports, queries or refs are bad.
279    "http://username:password@hostname/",
280    "http://www.example.com:1000",
281    "http://foo:1000",
282    "http://hostname/?query=q",
283    "http://hostname/path#ref",
284    // A https URL with path is bad.
285    "https://hostname/path",
286  };
287
288  for (size_t i = 0; i < arraysize(inputs); ++i)
289    EXPECT_EQ("", RunQuery(inputs[i], kOneResult));
290}
291
292IN_PROC_BROWSER_TEST_F(PeopleProviderTest, NoSearchForShortQueries) {
293  EXPECT_EQ("", RunQuery("f", kOneResult));
294  EXPECT_EQ("", RunQuery("fi", kOneResult));
295  EXPECT_EQ("first person", RunQuery("fir", kOneResult));
296}
297
298}  // namespace test
299}  // namespace app_list
300