Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / extensions / api / gcd_private / gcd_private_apitest.cc
blob3a3eaa66ea59aa1d0f6f1a00cf8d039eea288a2e
1 // Copyright 2014 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.
5 #include "base/bind.h"
6 #include "base/command_line.h"
7 #include "base/json/json_reader.h"
8 #include "base/thread_task_runner_handle.h"
9 #include "chrome/browser/extensions/api/gcd_private/gcd_private_api.h"
10 #include "chrome/browser/extensions/extension_apitest.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/local_discovery/gcd_api_flow.h"
13 #include "chrome/browser/local_discovery/wifi/mock_wifi_manager.h"
14 #include "chrome/common/extensions/api/mdns.h"
15 #include "extensions/common/switches.h"
16 #include "net/url_request/test_url_fetcher_factory.h"
17 #include "testing/gmock/include/gmock/gmock.h"
19 #if defined(ENABLE_MDNS)
20 #include "chrome/browser/local_discovery/test_service_discovery_client.h"
21 #endif // ENABLE_MDNS
23 namespace api = extensions::api;
25 using testing::Invoke;
27 namespace {
29 const char kCloudPrintResponse[] =
30 "{"
31 " \"success\": true,"
32 " \"printers\": ["
33 " {\"id\" : \"someCloudPrintID\","
34 " \"displayName\": \"someCloudPrintDisplayName\","
35 " \"description\": \"someCloudPrintDescription\"}"
36 " ]"
37 "}";
39 const char kGCDResponse[] =
40 "{"
41 "\"kind\": \"clouddevices#devicesListResponse\","
42 "\"devices\": [{"
43 " \"kind\": \"clouddevices#device\","
44 " \"id\": \"someGCDID\","
45 " \"deviceKind\": \"someType\","
46 " \"creationTimeMs\": \"123\","
47 " \"systemName\": \"someGCDDisplayName\","
48 " \"owner\": \"user@domain.com\","
49 " \"description\": \"someGCDDescription\","
50 " \"state\": {"
51 " \"base\": {"
52 " \"connectionStatus\": \"offline\""
53 " }"
54 " },"
55 " \"channel\": {"
56 " \"supportedType\": \"xmpp\""
57 " },"
58 " \"personalizedInfo\": {"
59 " \"maxRole\": \"owner\""
60 " }}]}";
62 #if defined(ENABLE_MDNS)
64 const char kPrivetInfoResponse[] =
65 "{\"version\":\"3.0\","
66 "\"endpoints\":{\"httpsPort\": 443},"
67 "\"authentication\":{"
68 " \"mode\":[\"anonymous\",\"pairing\",\"cloud\"],"
69 " \"pairing\":[\"embeddedCode\"],"
70 " \"crypto\":[\"p224_spake2\"]"
71 "}}";
73 const uint8 kAnnouncePacket[] = {
74 // Header
75 0x00, 0x00, // ID is zeroed out
76 0x80, 0x00, // Standard query response, no error
77 0x00, 0x00, // No questions (for simplicity)
78 0x00, 0x05, // 5 RR (answers)
79 0x00, 0x00, // 0 authority RRs
80 0x00, 0x00, // 0 additional RRs
81 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_',
82 't', 'c', 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00,
83 0x00, 0x0c, // TYPE is PTR.
84 0x00, 0x01, // CLASS is IN.
85 0x00, 0x00, // TTL (4 bytes) is 32768 second.
86 0x10, 0x00, 0x00, 0x0c, // RDLENGTH is 12 bytes.
87 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
88 0xc0, 0x0c, 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i',
89 'c', 'e', 0xc0, 0x0c, 0x00, 0x10, // TYPE is TXT.
90 0x00, 0x01, // CLASS is IN.
91 0x00, 0x00, // TTL (4 bytes) is 32768 seconds.
92 0x01, 0x00, 0x00, 0x41, // RDLENGTH is 69 bytes.
93 0x03, 'i', 'd', '=', 0x10, 't', 'y', '=', 'S', 'a',
94 'm', 'p', 'l', 'e', ' ', 'd', 'e', 'v', 'i', 'c',
95 'e', 0x1e, 'n', 'o', 't', 'e', '=', 'S', 'a', 'm',
96 'p', 'l', 'e', ' ', 'd', 'e', 'v', 'i', 'c', 'e',
97 ' ', 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i',
98 'o', 'n', 0x0c, 't', 'y', 'p', 'e', '=', 'p', 'r',
99 'i', 'n', 't', 'e', 'r', 0x09, 'm', 'y', 'S', 'e',
100 'r', 'v', 'i', 'c', 'e', 0xc0, 0x0c, 0x00, 0x21, // Type is SRV
101 0x00, 0x01, // CLASS is IN
102 0x00, 0x00, // TTL (4 bytes) is 32768 second.
103 0x10, 0x00, 0x00, 0x17, // RDLENGTH is 23
104 0x00, 0x00, 0x00, 0x00, 0x22, 0xb8, // port 8888
105 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
106 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0x09, 'm', 'y',
107 'S', 'e', 'r', 'v', 'i', 'c', 'e', 0x05, 'l', 'o',
108 'c', 'a', 'l', 0x00, 0x00, 0x01, // Type is A
109 0x00, 0x01, // CLASS is IN
110 0x00, 0x00, // TTL (4 bytes) is 32768 second.
111 0x10, 0x00, 0x00, 0x04, // RDLENGTH is 4
112 0x01, 0x02, 0x03, 0x04, // 1.2.3.4
113 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
114 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x1C, // Type is AAAA
115 0x00, 0x01, // CLASS is IN
116 0x00, 0x00, // TTL (4 bytes) is 32768 second.
117 0x10, 0x00, 0x00, 0x10, // RDLENGTH is 16
118 0x01, 0x02, 0x03, 0x04, // 1.2.3.4
119 0x01, 0x02, 0x03, 0x04, 0x01, 0x02, 0x03, 0x04, 0x01, 0x02,
120 0x03, 0x04,
123 const uint8 kGoodbyePacket[] = {
124 // Header
125 0x00, 0x00, // ID is zeroed out
126 0x80, 0x00, // Standard query response, RA, no error
127 0x00, 0x00, // No questions (for simplicity)
128 0x00, 0x02, // 1 RR (answers)
129 0x00, 0x00, // 0 authority RRs
130 0x00, 0x00, // 0 additional RRs
131 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c',
132 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
133 0x00, 0x01, // CLASS is IN.
134 0x00, 0x00, // TTL (4 bytes) is 0 seconds.
135 0x00, 0x00, 0x00, 0x0c, // RDLENGTH is 12 bytes.
136 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 0xc0, 0x0c,
137 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 0xc0, 0x0c,
138 0x00, 0x21, // Type is SRV
139 0x00, 0x01, // CLASS is IN
140 0x00, 0x00, // TTL (4 bytes) is 0 seconds.
141 0x00, 0x00, 0x00, 0x17, // RDLENGTH is 23
142 0x00, 0x00, 0x00, 0x00, 0x22, 0xb8, // port 8888
143 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 0x05, 'l',
144 'o', 'c', 'a', 'l', 0x00,
147 #if !defined(OS_WIN) || defined(NDEBUG)
148 const uint8 kQueryPacket[] = {
149 // Header
150 0x00, 0x00, // ID is zeroed out
151 0x00, 0x00, // No flags.
152 0x00, 0x01, // One question.
153 0x00, 0x00, // 0 RRs (answers)
154 0x00, 0x00, // 0 authority RRs
155 0x00, 0x00, // 0 additional RRs
157 // Question
158 // This part is echoed back from the respective query.
159 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 0x04, '_', 't', 'c',
160 'p', 0x05, 'l', 'o', 'c', 'a', 'l', 0x00, 0x00, 0x0c, // TYPE is PTR.
161 0x00, 0x01, // CLASS is IN.
163 #endif // !defined(OS_WIN) || defined(NDEBUG)
165 #endif // ENABLE_MDNS
167 // Sentinel value to signify the request should fail.
168 const char kResponseValueFailure[] = "FAILURE";
170 class FakeGCDApiFlowFactory
171 : public extensions::GcdPrivateAPI::GCDApiFlowFactoryForTests {
172 public:
173 FakeGCDApiFlowFactory() {
174 extensions::GcdPrivateAPI::SetGCDApiFlowFactoryForTests(this);
177 ~FakeGCDApiFlowFactory() override {
178 extensions::GcdPrivateAPI::SetGCDApiFlowFactoryForTests(NULL);
181 scoped_ptr<local_discovery::GCDApiFlow> CreateGCDApiFlow() override {
182 return scoped_ptr<local_discovery::GCDApiFlow>(new FakeGCDApiFlow(this));
185 void SetResponse(const GURL& url, const std::string& response) {
186 responses_[url] = response;
189 private:
190 class FakeGCDApiFlow : public local_discovery::GCDApiFlow {
191 public:
192 explicit FakeGCDApiFlow(FakeGCDApiFlowFactory* factory)
193 : factory_(factory) {}
195 ~FakeGCDApiFlow() override {}
197 void Start(scoped_ptr<Request> request) override {
198 std::string response_str = factory_->responses_[request->GetURL()];
200 if (response_str == kResponseValueFailure) {
201 request->OnGCDAPIFlowError(
202 local_discovery::GCDApiFlow::ERROR_MALFORMED_RESPONSE);
203 return;
206 scoped_ptr<base::Value> response = base::JSONReader::Read(response_str);
207 ASSERT_TRUE(response);
209 base::DictionaryValue* response_dict;
210 ASSERT_TRUE(response->GetAsDictionary(&response_dict));
212 request->OnGCDAPIFlowComplete(*response_dict);
215 private:
216 FakeGCDApiFlowFactory* factory_;
219 std::map<GURL /*request url*/, std::string /*response json*/> responses_;
222 class GcdPrivateAPITest : public ExtensionApiTest {
223 public:
224 GcdPrivateAPITest() : url_fetcher_factory_(&url_fetcher_impl_factory_) {
225 #if defined(ENABLE_MDNS)
226 test_service_discovery_client_ =
227 new local_discovery::TestServiceDiscoveryClient();
228 test_service_discovery_client_->Start();
229 #endif // ENABLE_MDNS
232 void SetUpCommandLine(base::CommandLine* command_line) override {
233 ExtensionApiTest::SetUpCommandLine(command_line);
234 command_line->AppendSwitchASCII(
235 extensions::switches::kWhitelistedExtensionID,
236 "ddchlicdkolnonkihahngkmmmjnjlkkf");
239 #if defined(ENABLE_WIFI_BOOTSTRAPPING)
240 virtual void OnCreateWifiManager() {
241 wifi_manager_ = wifi_manager_factory_.GetLastCreatedWifiManager();
243 EXPECT_CALL(*wifi_manager_, Start());
245 EXPECT_CALL(*wifi_manager_,
246 RequestNetworkCredentialsInternal("SuccessNetwork"))
247 .WillOnce(Invoke(this, &GcdPrivateAPITest::RespondToNetwork));
249 EXPECT_CALL(*wifi_manager_,
250 RequestNetworkCredentialsInternal("FailureNetwork"))
251 .WillOnce(Invoke(this, &GcdPrivateAPITest::RespondToNetwork));
254 void RespondToNetwork(const std::string& network) {
255 bool success = (network == "SuccessNetwork");
257 wifi_manager_->CallRequestNetworkCredentialsCallback(
258 success, network, success ? "SuccessPass" : "");
260 #endif
262 protected:
263 FakeGCDApiFlowFactory api_flow_factory_;
264 net::URLFetcherImplFactory url_fetcher_impl_factory_;
265 net::FakeURLFetcherFactory url_fetcher_factory_;
267 #if defined(ENABLE_MDNS)
268 scoped_refptr<local_discovery::TestServiceDiscoveryClient>
269 test_service_discovery_client_;
270 #endif // ENABLE_MDNS
272 #if defined(ENABLE_WIFI_BOOTSTRAPPING)
273 local_discovery::wifi::MockWifiManagerFactory wifi_manager_factory_;
274 local_discovery::wifi::MockWifiManager* wifi_manager_;
275 #endif
278 IN_PROC_BROWSER_TEST_F(GcdPrivateAPITest, GetCloudList) {
279 api_flow_factory_.SetResponse(
280 GURL("https://www.google.com/cloudprint/search"), kCloudPrintResponse);
282 api_flow_factory_.SetResponse(
283 GURL("https://www.googleapis.com/clouddevices/v1/devices"), kGCDResponse);
285 EXPECT_TRUE(RunExtensionSubtest("gcd_private/api", "get_cloud_list.html"));
288 #if defined(ENABLE_MDNS)
289 IN_PROC_BROWSER_TEST_F(GcdPrivateAPITest, DeviceInfo) {
290 test_service_discovery_client_->SimulateReceive(kAnnouncePacket,
291 sizeof(kAnnouncePacket));
292 url_fetcher_factory_.SetFakeResponse(GURL("http://1.2.3.4:8888/privet/info"),
293 kPrivetInfoResponse,
294 net::HTTP_OK,
295 net::URLRequestStatus::SUCCESS);
296 EXPECT_TRUE(RunExtensionSubtest("gcd_private/api", "device_info.html"));
299 IN_PROC_BROWSER_TEST_F(GcdPrivateAPITest, Session) {
300 test_service_discovery_client_->SimulateReceive(kAnnouncePacket,
301 sizeof(kAnnouncePacket));
302 url_fetcher_factory_.SetFakeResponse(GURL("http://1.2.3.4:8888/privet/info"),
303 kPrivetInfoResponse,
304 net::HTTP_OK,
305 net::URLRequestStatus::SUCCESS);
306 EXPECT_TRUE(RunExtensionSubtest("gcd_private/api", "session.html"));
309 IN_PROC_BROWSER_TEST_F(GcdPrivateAPITest, AddBefore) {
310 test_service_discovery_client_->SimulateReceive(kAnnouncePacket,
311 sizeof(kAnnouncePacket));
313 EXPECT_TRUE(
314 RunExtensionSubtest("gcd_private/api", "receive_new_device.html"));
317 IN_PROC_BROWSER_TEST_F(GcdPrivateAPITest, AddAfter) {
318 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
319 FROM_HERE,
320 base::Bind(&local_discovery::TestServiceDiscoveryClient::SimulateReceive,
321 test_service_discovery_client_,
322 kAnnouncePacket,
323 sizeof(kAnnouncePacket)),
324 base::TimeDelta::FromSeconds(1));
326 EXPECT_TRUE(
327 RunExtensionSubtest("gcd_private/api", "receive_new_device.html"));
330 IN_PROC_BROWSER_TEST_F(GcdPrivateAPITest, AddRemove) {
331 test_service_discovery_client_->SimulateReceive(kAnnouncePacket,
332 sizeof(kAnnouncePacket));
334 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
335 FROM_HERE,
336 base::Bind(&local_discovery::TestServiceDiscoveryClient::SimulateReceive,
337 test_service_discovery_client_,
338 kGoodbyePacket,
339 sizeof(kGoodbyePacket)),
340 base::TimeDelta::FromSeconds(1));
342 EXPECT_TRUE(RunExtensionSubtest("gcd_private/api", "remove_device.html"));
345 IN_PROC_BROWSER_TEST_F(GcdPrivateAPITest, SendQuery) {
346 // TODO(noamsml): Win Dbg has a workaround that makes RunExtensionSubtest
347 // always return true without actually running the test. Remove when fixed.
348 // See http://crbug.com/177163 for details.
349 #if !defined(OS_WIN) || defined(NDEBUG)
350 EXPECT_CALL(*test_service_discovery_client_.get(),
351 OnSendTo(std::string(reinterpret_cast<const char*>(kQueryPacket),
352 sizeof(kQueryPacket)))).Times(2);
353 #endif
354 EXPECT_TRUE(RunExtensionSubtest("gcd_private/api", "send_query.html"));
357 #endif // ENABLE_MDNS
359 #if defined(ENABLE_WIFI_BOOTSTRAPPING)
361 IN_PROC_BROWSER_TEST_F(GcdPrivateAPITest, WifiMessage) {
362 EXPECT_TRUE(RunExtensionSubtest("gcd_private/api", "wifi_message.html"));
365 IN_PROC_BROWSER_TEST_F(GcdPrivateAPITest, WifiPasswords) {
366 // TODO(noamsml): Win Dbg has a workaround that makes RunExtensionSubtest
367 // always return true without actually running the test. Remove when fixed.
368 // See http://crbug.com/177163 for details.
369 #if !defined(OS_WIN) || defined(NDEBUG)
370 EXPECT_CALL(wifi_manager_factory_, WifiManagerCreated())
371 .WillOnce(Invoke(this, &GcdPrivateAPITest::OnCreateWifiManager));
372 #endif
374 EXPECT_TRUE(RunExtensionSubtest("gcd_private/api", "wifi_password.html"));
377 #endif // ENABLE_WIFI_BOOTSTRAPPING
379 } // namespace