Home | History | Annotate | Download | only in search
      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/webstore_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 
     32 class WebstoreProviderTest : public InProcessBrowserTest {
     33  public:
     34   WebstoreProviderTest() {}
     35   virtual ~WebstoreProviderTest() {}
     36 
     37   // InProcessBrowserTest overrides:
     38   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
     39     command_line->AppendSwitchASCII(switches::kForceFieldTrials,
     40                                     "LauncherUseWebstoreSearch/Enable/");
     41   }
     42 
     43   virtual void SetUpOnMainThread() OVERRIDE {
     44     test_server_.reset(new EmbeddedTestServer(
     45         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO)));
     46 
     47     ASSERT_TRUE(test_server_->InitializeAndWaitUntilReady());
     48     test_server_->RegisterRequestHandler(
     49         base::Bind(&WebstoreProviderTest::HandleRequest,
     50                    base::Unretained(this)));
     51     CommandLine::ForCurrentProcess()->AppendSwitchASCII(
     52         switches::kAppsGalleryURL, test_server_->base_url().spec());
     53 
     54     webstore_provider_.reset(new WebstoreProvider(
     55         ProfileManager::GetDefaultProfile(), NULL));
     56     webstore_provider_->set_webstore_search_fetched_callback(
     57         base::Bind(&WebstoreProviderTest::OnSearchResultsFetched,
     58                    base::Unretained(this)));
     59   }
     60 
     61   virtual void CleanUpOnMainThread() OVERRIDE {
     62     EXPECT_TRUE(test_server_->ShutdownAndWaitUntilComplete());
     63     test_server_.reset();
     64   }
     65 
     66   std::string RunQuery(const std::string& query,
     67                        const std::string& mock_server_response) {
     68     webstore_provider_->Start(UTF8ToUTF16(query));
     69 
     70     if (!mock_server_response.empty()) {
     71       mock_server_response_ = mock_server_response;
     72 
     73       DCHECK(!run_loop_);
     74       run_loop_.reset(new base::RunLoop);
     75       run_loop_->Run();
     76       run_loop_.reset();
     77 
     78       mock_server_response_.clear();
     79     }
     80 
     81     webstore_provider_->Stop();
     82     return GetResults();
     83   }
     84 
     85   std::string GetResults() const {
     86     std::string results;
     87     for (SearchProvider::Results::const_iterator it =
     88              webstore_provider_->results().begin();
     89          it != webstore_provider_->results().end();
     90          ++it) {
     91       if (!results.empty())
     92         results += ',';
     93       results += UTF16ToUTF8((*it)->title());
     94     }
     95     return results;
     96   }
     97 
     98   WebstoreProvider* webstore_provider() { return webstore_provider_.get(); }
     99 
    100  private:
    101   scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
    102     scoped_ptr<BasicHttpResponse> response(new BasicHttpResponse);
    103 
    104     if (request.relative_url.find("/jsonsearch?") != std::string::npos) {
    105       if (mock_server_response_ == "404") {
    106         response->set_code(net::HTTP_NOT_FOUND);
    107       } else if (mock_server_response_ == "500") {
    108         response->set_code(net::HTTP_INTERNAL_SERVER_ERROR);
    109       } else {
    110         response->set_code(net::HTTP_OK);
    111         response->set_content(mock_server_response_);
    112       }
    113     }
    114 
    115     return response.PassAs<HttpResponse>();
    116   }
    117 
    118   void OnSearchResultsFetched() {
    119     if (run_loop_)
    120       run_loop_->Quit();
    121   }
    122 
    123   scoped_ptr<EmbeddedTestServer> test_server_;
    124   scoped_ptr<base::RunLoop> run_loop_;
    125 
    126   std::string mock_server_response_;
    127 
    128   scoped_ptr<WebstoreProvider> webstore_provider_;
    129 
    130   DISALLOW_COPY_AND_ASSIGN(WebstoreProviderTest);
    131 };
    132 
    133 // Flaky on Windows: http://crbug.com/246136.
    134 #if defined(OS_WIN)
    135 #define MAYBE_Basic DISABLED_Basic
    136 #else
    137 #define MAYBE_Basic Basic
    138 #endif
    139 IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, MAYBE_Basic) {
    140   const char kOneResult[] = "{"
    141       "\"search_url\": \"http://host/search\","
    142       "\"results\":["
    143         "{"
    144           "\"id\": \"app1_id\","
    145           "\"localized_name\": \"app1 name\","
    146           "\"icon_url\": \"http://host/icon\""
    147         "}"
    148       "]}";
    149   const char kThreeResults[] = "{"
    150       "\"search_url\": \"http://host/search\","
    151       "\"results\":["
    152         "{"
    153           "\"id\": \"app1_id\","
    154           "\"localized_name\": \"one\","
    155           "\"icon_url\": \"http://host/icon\""
    156         "},"
    157         "{"
    158           "\"id\": \"app2_id\","
    159           "\"localized_name\": \"two\","
    160           "\"icon_url\": \"http://host/icon\""
    161         "},"
    162         "{"
    163           "\"id\": \"app3_id\","
    164           "\"localized_name\": \"three\","
    165           "\"icon_url\": \"http://host/icon\""
    166         "}"
    167       "]}";
    168   struct {
    169     const char* query;
    170     const char* mock_server_response;
    171     const char* expected_results_content;
    172   } kTestCases[] = {
    173     // "Search in web store" result with query text itself is used for
    174     // synchronous placeholder, bad server response etc.
    175     {"synchronous", "", "synchronous" },
    176     {"404", "404", "404" },
    177     {"500", "500", "500" },
    178     {"bad json", "invalid json", "bad json" },
    179     // Good results.
    180     {"1 result", kOneResult, "app1 name" },
    181     {"3 result", kThreeResults, "one,two,three" },
    182   };
    183 
    184   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestCases); ++i) {
    185     EXPECT_EQ(kTestCases[i].expected_results_content,
    186               RunQuery(kTestCases[i].query,
    187                        kTestCases[i].mock_server_response))
    188         << "Case " << i << ": q=" << kTestCases[i].query;
    189   }
    190 }
    191 
    192 IN_PROC_BROWSER_TEST_F(WebstoreProviderTest, NoSearchForSensitiveData) {
    193   // None of the following input strings should be accepted because they may
    194   // contain private data.
    195   const char* inputs[] = {
    196     // file: scheme is bad.
    197     "file://filename",
    198     "FILE://filename",
    199     // URLs with usernames, ports, queries or refs are bad.
    200     "http://username:password@hostname/",
    201     "http://www.example.com:1000",
    202     "http://foo:1000",
    203     "http://hostname/?query=q",
    204     "http://hostname/path#ref",
    205     // A https URL with path is bad.
    206     "https://hostname/path",
    207   };
    208 
    209   for (size_t i = 0; i < arraysize(inputs); ++i)
    210     EXPECT_EQ("", RunQuery(inputs[i], ""));
    211 }
    212 
    213 }  // namespace test
    214 }  // namespace app_list
    215