Home | History | Annotate | Download | only in people
      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 
     23 using content::BrowserThread;
     24 using net::test_server::BasicHttpResponse;
     25 using net::test_server::HttpRequest;
     26 using net::test_server::HttpResponse;
     27 using net::test_server::EmbeddedTestServer;
     28 
     29 namespace app_list {
     30 namespace test {
     31 namespace {
     32 
     33 // Mock results.
     34 const 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 (at) person.com\""
     47           "}],"
     48           "\"images\" : [{"
     49             "\"url\": \"http://host/icon\""
     50           "}],"
     51           "\"sortKeys\" : {"
     52             "\"interactionRank\": \"0.98\""
     53           "}"
     54         "}"
     55       "}"
     56     "]}";
     57 
     58 const 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 (at) 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 (at) 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 (at) 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 (at) 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 (at) person.com\""
    151           "}],"
    152           // Images field is missing on purpose.
    153           "\"sortKeys\" : {"
    154             "\"interactionRank\": \"0.98\""
    155           "}"
    156         "}"
    157       "}"
    158     "]}";
    159 
    160 }  // namespace
    161 
    162 class PeopleProviderTest : public InProcessBrowserTest {
    163  public:
    164   PeopleProviderTest() {}
    165   virtual ~PeopleProviderTest() {}
    166 
    167   // InProcessBrowserTest overrides:
    168   virtual void SetUpOnMainThread() OVERRIDE {
    169     test_server_.reset(new EmbeddedTestServer);
    170 
    171     ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
    172     test_server_->RegisterRequestHandler(
    173         base::Bind(&PeopleProviderTest::HandleRequest,
    174                    base::Unretained(this)));
    175 
    176     people_provider_.reset(new PeopleProvider(
    177         ProfileManager::GetActiveUserProfile()));
    178 
    179     people_provider_->SetupForTest(
    180         base::Bind(&PeopleProviderTest::OnSearchResultsFetched,
    181                    base::Unretained(this)),
    182         test_server_->base_url());
    183     people_provider_->set_use_throttling(false);
    184   }
    185 
    186   virtual void CleanUpOnMainThread() OVERRIDE {
    187     EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete());
    188     test_server_.reset();
    189   }
    190 
    191   std::string RunQuery(const std::string& query,
    192                        const std::string& mock_server_response) {
    193     people_provider_->Start(base::UTF8ToUTF16(query));
    194 
    195     if (people_provider_->people_search_ && !mock_server_response.empty()) {
    196       mock_server_response_ = mock_server_response;
    197 
    198       DCHECK(!run_loop_);
    199       run_loop_.reset(new base::RunLoop);
    200       run_loop_->Run();
    201       run_loop_.reset();
    202 
    203       mock_server_response_.clear();
    204     }
    205 
    206     people_provider_->Stop();
    207     return GetResults();
    208   }
    209 
    210   std::string GetResults() const {
    211     std::string results;
    212     for (SearchProvider::Results::const_iterator it =
    213              people_provider_->results().begin();
    214          it != people_provider_->results().end();
    215          ++it) {
    216       if (!results.empty())
    217         results += ',';
    218       results += base::UTF16ToUTF8((*it)->title());
    219     }
    220     return results;
    221   }
    222 
    223   PeopleProvider* people_provider() { return people_provider_.get(); }
    224 
    225  private:
    226   scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
    227     scoped_ptr<BasicHttpResponse> response(new BasicHttpResponse);
    228     response->set_code(net::HTTP_OK);
    229     response->set_content(mock_server_response_);
    230 
    231     return response.PassAs<HttpResponse>();
    232   }
    233 
    234   void OnSearchResultsFetched() {
    235     if (run_loop_)
    236       run_loop_->Quit();
    237   }
    238 
    239   scoped_ptr<EmbeddedTestServer> test_server_;
    240   scoped_ptr<base::RunLoop> run_loop_;
    241 
    242   std::string mock_server_response_;
    243 
    244   scoped_ptr<PeopleProvider> people_provider_;
    245 
    246   DISALLOW_COPY_AND_ASSIGN(PeopleProviderTest);
    247 };
    248 
    249 IN_PROC_BROWSER_TEST_F(PeopleProviderTest, Basic) {
    250   struct {
    251     const char* query;
    252     const char* mock_server_response;
    253     const char* expected_results_content;
    254   } kTestCases[] = {
    255     {"first", kOneResult, "first person" },
    256     {"person", kThreeValidResults, "first person,second person,third person" },
    257   };
    258 
    259   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
    260     EXPECT_EQ(kTestCases[i].expected_results_content,
    261               RunQuery(kTestCases[i].query,
    262                        kTestCases[i].mock_server_response))
    263         << "Case " << i << ": q=" << kTestCases[i].query;
    264   }
    265 }
    266 
    267 IN_PROC_BROWSER_TEST_F(PeopleProviderTest, NoSearchForSensitiveData) {
    268   // None of the following input strings should be accepted because they may
    269   // contain private data.
    270   const char* inputs[] = {
    271     // file: scheme is bad.
    272     "file://filename",
    273     "FILE://filename",
    274     // URLs with usernames, ports, queries or refs are bad.
    275     "http://username:password@hostname/",
    276     "http://www.example.com:1000",
    277     "http://foo:1000",
    278     "http://hostname/?query=q",
    279     "http://hostname/path#ref",
    280     // A https URL with path is bad.
    281     "https://hostname/path",
    282   };
    283 
    284   for (size_t i = 0; i < arraysize(inputs); ++i)
    285     EXPECT_EQ("", RunQuery(inputs[i], kOneResult));
    286 }
    287 
    288 IN_PROC_BROWSER_TEST_F(PeopleProviderTest, NoSearchForShortQueries) {
    289   EXPECT_EQ("", RunQuery("f", kOneResult));
    290   EXPECT_EQ("", RunQuery("fi", kOneResult));
    291   EXPECT_EQ("first person", RunQuery("fir", kOneResult));
    292 }
    293 
    294 }  // namespace test
    295 }  // namespace app_list
    296