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