Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / webui / local_discovery / local_discovery_ui_browsertest.cc
blobf08f5fe72a0dc71174b99c818a6aa38b4f20126d
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.
5 #include "base/basictypes.h"
6 #include "base/bind.h"
7 #include "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/compiler_specific.h"
10 #include "base/location.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "base/message_loop/message_loop.h"
13 #include "chrome/browser/local_discovery/test_service_discovery_client.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
16 #include "chrome/browser/signin/signin_manager_factory.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.h"
19 #include "chrome/common/chrome_constants.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/url_constants.h"
22 #include "chrome/test/base/ui_test_utils.h"
23 #include "chrome/test/base/web_ui_browser_test.h"
24 #include "components/signin/core/browser/profile_oauth2_token_service.h"
25 #include "components/signin/core/browser/signin_manager.h"
26 #include "components/signin/core/browser/signin_manager_base.h"
27 #include "google_apis/gaia/gaia_urls.h"
28 #include "net/http/http_status_code.h"
29 #include "net/url_request/test_url_fetcher_factory.h"
30 #include "net/url_request/url_request_status.h"
31 #include "net/url_request/url_request_test_util.h"
33 #if defined(OS_CHROMEOS)
34 #include "base/prefs/pref_service.h"
35 #include "chrome/common/pref_names.h"
36 #include "chromeos/chromeos_switches.h"
37 #endif
39 using testing::InvokeWithoutArgs;
40 using testing::Return;
41 using testing::AtLeast;
42 using testing::DoDefault;
43 using testing::DoAll;
44 using testing::InSequence;
45 using testing::StrictMock;
46 using testing::AnyNumber;
48 using testing::InvokeWithoutArgs;
49 using testing::Return;
50 using testing::AtLeast;
52 namespace local_discovery {
54 namespace {
56 const uint8 kQueryData[] = {
57 // Header
58 0x00, 0x00,
59 0x00, 0x00, // Flags not set.
60 0x00, 0x01, // Set QDCOUNT (question count) to 1, all the
61 // rest are 0 for a query.
62 0x00, 0x00,
63 0x00, 0x00,
64 0x00, 0x00,
66 // Question
67 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
68 0x04, '_', 't', 'c', 'p',
69 0x05, 'l', 'o', 'c', 'a', 'l',
70 0x00,
72 0x00, 0x0c, // QTYPE: A query.
73 0x00, 0x01, // QCLASS: IN class. Unicast bit not set.
76 const uint8 kAnnouncePacket[] = {
77 // Header
78 0x00, 0x00, // ID is zeroed out
79 0x80, 0x00, // Standard query response, no error
80 0x00, 0x00, // No questions (for simplicity)
81 0x00, 0x05, // 5 RR (answers)
82 0x00, 0x00, // 0 authority RRs
83 0x00, 0x00, // 0 additional RRs
85 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
86 0x04, '_', 't', 'c', 'p',
87 0x05, 'l', 'o', 'c', 'a', 'l',
88 0x00,
89 0x00, 0x0c, // TYPE is PTR.
90 0x00, 0x01, // CLASS is IN.
91 0x00, 0x00, // TTL (4 bytes) is 32768 second.
92 0x10, 0x00,
93 0x00, 0x0c, // RDLENGTH is 12 bytes.
94 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
95 0xc0, 0x0c,
97 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
98 0xc0, 0x0c,
99 0x00, 0x10, // TYPE is TXT.
100 0x00, 0x01, // CLASS is IN.
101 0x00, 0x00, // TTL (4 bytes) is 32768 seconds.
102 0x01, 0x00,
103 0x00, 0x41, // RDLENGTH is 69 bytes.
104 0x03, 'i', 'd', '=',
105 0x10, 't', 'y', '=', 'S', 'a', 'm', 'p', 'l', 'e', ' ',
106 'd', 'e', 'v', 'i', 'c', 'e',
107 0x1e, 'n', 'o', 't', 'e', '=',
108 'S', 'a', 'm', 'p', 'l', 'e', ' ', 'd', 'e', 'v', 'i', 'c', 'e', ' ',
109 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n',
110 0x0c, 't', 'y', 'p', 'e', '=', 'p', 'r', 'i', 'n', 't', 'e', 'r',
112 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
113 0xc0, 0x0c,
114 0x00, 0x21, // Type is SRV
115 0x00, 0x01, // CLASS is IN
116 0x00, 0x00, // TTL (4 bytes) is 32768 second.
117 0x10, 0x00,
118 0x00, 0x17, // RDLENGTH is 23
119 0x00, 0x00,
120 0x00, 0x00,
121 0x22, 0xb8, // port 8888
122 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
123 0x05, 'l', 'o', 'c', 'a', 'l',
124 0x00,
126 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
127 0x05, 'l', 'o', 'c', 'a', 'l',
128 0x00,
129 0x00, 0x01, // Type is A
130 0x00, 0x01, // CLASS is IN
131 0x00, 0x00, // TTL (4 bytes) is 32768 second.
132 0x10, 0x00,
133 0x00, 0x04, // RDLENGTH is 4
134 0x01, 0x02, 0x03, 0x04, // 1.2.3.4
136 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
137 0x05, 'l', 'o', 'c', 'a', 'l',
138 0x00,
139 0x00, 0x1C, // Type is AAAA
140 0x00, 0x01, // CLASS is IN
141 0x00, 0x00, // TTL (4 bytes) is 32768 second.
142 0x10, 0x00,
143 0x00, 0x10, // RDLENGTH is 16
144 0x01, 0x02, 0x03, 0x04, // 1.2.3.4
145 0x01, 0x02, 0x03, 0x04,
146 0x01, 0x02, 0x03, 0x04,
147 0x01, 0x02, 0x03, 0x04,
151 const uint8 kGoodbyePacket[] = {
152 // Header
153 0x00, 0x00, // ID is zeroed out
154 0x80, 0x00, // Standard query response, RA, no error
155 0x00, 0x00, // No questions (for simplicity)
156 0x00, 0x02, // 1 RR (answers)
157 0x00, 0x00, // 0 authority RRs
158 0x00, 0x00, // 0 additional RRs
160 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
161 0x04, '_', 't', 'c', 'p',
162 0x05, 'l', 'o', 'c', 'a', 'l',
163 0x00,
164 0x00, 0x0c, // TYPE is PTR.
165 0x00, 0x01, // CLASS is IN.
166 0x00, 0x00, // TTL (4 bytes) is 0 seconds.
167 0x00, 0x00,
168 0x00, 0x0c, // RDLENGTH is 12 bytes.
169 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
170 0xc0, 0x0c,
173 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
174 0xc0, 0x0c,
175 0x00, 0x21, // Type is SRV
176 0x00, 0x01, // CLASS is IN
177 0x00, 0x00, // TTL (4 bytes) is 0 seconds.
178 0x00, 0x00,
179 0x00, 0x17, // RDLENGTH is 23
180 0x00, 0x00,
181 0x00, 0x00,
182 0x22, 0xb8, // port 8888
183 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
184 0x05, 'l', 'o', 'c', 'a', 'l',
185 0x00,
188 const uint8 kAnnouncePacketRegistered[] = {
189 // Header
190 0x00, 0x00, // ID is zeroed out
191 0x80, 0x00, // Standard query response, RA, no error
192 0x00, 0x00, // No questions (for simplicity)
193 0x00, 0x01, // 1 RR (answers)
194 0x00, 0x00, // 0 authority RRs
195 0x00, 0x00, // 0 additional RRs
197 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e',
198 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't',
199 0x04, '_', 't', 'c', 'p',
200 0x05, 'l', 'o', 'c', 'a', 'l',
201 0x00,
202 0x00, 0x10, // TYPE is TXT.
203 0x00, 0x01, // CLASS is IN.
204 0x00, 0x00, // TTL (4 bytes) is 32768 seconds.
205 0x01, 0x00,
206 0x00, 0x3b, // RDLENGTH is 76 bytes.
207 0x0a, 'i', 'd', '=', 's', 'o', 'm', 'e', '_', 'i', 'd',
208 0x10, 't', 'y', '=', 'S', 'a', 'm', 'p', 'l', 'e', ' ',
209 'd', 'e', 'v', 'i', 'c', 'e',
210 0x1e, 'n', 'o', 't', 'e', '=',
211 'S', 'a', 'm', 'p', 'l', 'e', ' ', 'd', 'e', 'v', 'i', 'c', 'e', ' ',
212 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n',
215 const char kResponseInfo[] = "{"
216 " \"x-privet-token\" : \"MyPrivetToken\""
217 "}";
219 const char kResponseInfoWithID[] = "{"
220 " \"x-privet-token\" : \"MyPrivetToken\","
221 " \"id\" : \"my_id\""
222 "}";
224 const char kResponseRegisterStart[] = "{"
225 " \"action\": \"start\","
226 " \"user\": \"user@host.com\""
227 "}";
229 const char kResponseRegisterClaimTokenNoConfirm[] = "{"
230 " \"action\": \"getClaimToken\","
231 " \"user\": \"user@host.com\","
232 " \"error\": \"pending_user_action\","
233 " \"timeout\": 1"
234 "}";
236 const char kResponseRegisterClaimTokenConfirm[] = "{"
237 " \"action\": \"getClaimToken\","
238 " \"user\": \"user@host.com\","
239 " \"token\": \"MySampleToken\","
240 " \"claim_url\": \"http://someurl.com/\""
241 "}";
243 const char kResponseCloudPrintConfirm[] = "{ \"success\": true }";
245 const char kResponseRegisterComplete[] = "{"
246 " \"action\": \"complete\","
247 " \"user\": \"user@host.com\","
248 " \"device_id\": \"my_id\""
249 "}";
251 const char kResponseGaiaToken[] = "{"
252 " \"access_token\": \"at1\","
253 " \"expires_in\": 3600,"
254 " \"token_type\": \"Bearer\""
255 "}";
257 const char kResponseGaiaId[] = "{"
258 " \"id\": \"12345\""
259 "}";
261 const char kURLInfo[] = "http://1.2.3.4:8888/privet/info";
263 const char kURLRegisterStart[] =
264 "http://1.2.3.4:8888/privet/register?action=start&user=user%40host.com";
266 const char kURLRegisterClaimToken[] =
267 "http://1.2.3.4:8888/privet/register?action=getClaimToken&"
268 "user=user%40host.com";
270 const char kURLCloudPrintConfirm[] =
271 "https://www.google.com/cloudprint/confirm?token=MySampleToken";
273 const char kURLRegisterComplete[] =
274 "http://1.2.3.4:8888/privet/register?action=complete&user=user%40host.com";
276 const char kSampleGaiaId[] = "12345";
277 const char kSampleUser[] = "user@host.com";
279 class TestMessageLoopCondition {
280 public:
281 TestMessageLoopCondition() : signaled_(false),
282 waiting_(false) {
285 ~TestMessageLoopCondition() {
288 // Signal a waiting method that it can continue executing.
289 void Signal() {
290 signaled_ = true;
291 if (waiting_)
292 base::MessageLoop::current()->Quit();
295 // Pause execution and recursively run the message loop until |Signal()| is
296 // called. Do not pause if |Signal()| has already been called.
297 void Wait() {
298 while (!signaled_) {
299 waiting_ = true;
300 base::MessageLoop::current()->Run();
301 waiting_ = false;
303 signaled_ = false;
306 private:
307 bool signaled_;
308 bool waiting_;
310 DISALLOW_COPY_AND_ASSIGN(TestMessageLoopCondition);
313 class MockableFakeURLFetcherCreator {
314 public:
315 MockableFakeURLFetcherCreator() {
318 ~MockableFakeURLFetcherCreator() {
321 MOCK_METHOD1(OnCreateFakeURLFetcher, void(const std::string& url));
323 scoped_ptr<net::FakeURLFetcher> CreateFakeURLFetcher(
324 const GURL& url,
325 net::URLFetcherDelegate* delegate,
326 const std::string& response_data,
327 net::HttpStatusCode response_code,
328 net::URLRequestStatus::Status status) {
329 OnCreateFakeURLFetcher(url.spec());
330 return scoped_ptr<net::FakeURLFetcher>(new net::FakeURLFetcher(
331 url, delegate, response_data, response_code, status));
334 net::FakeURLFetcherFactory::FakeURLFetcherCreator callback() {
335 return base::Bind(&MockableFakeURLFetcherCreator::CreateFakeURLFetcher,
336 base::Unretained(this));
340 class LocalDiscoveryUITest : public WebUIBrowserTest {
341 public:
342 LocalDiscoveryUITest() : fake_fetcher_factory_(
343 &fetcher_impl_factory_,
344 fake_url_fetcher_creator_.callback()) {
346 ~LocalDiscoveryUITest() override {
349 void SetUpOnMainThread() override {
350 WebUIBrowserTest::SetUpOnMainThread();
352 test_service_discovery_client_ = new TestServiceDiscoveryClient();
353 test_service_discovery_client_->Start();
354 EXPECT_CALL(
355 *test_service_discovery_client_.get(),
356 OnSendTo(std::string((const char*)kQueryData, sizeof(kQueryData))))
357 .Times(AtLeast(2))
358 .WillOnce(InvokeWithoutArgs(&condition_devices_listed_,
359 &TestMessageLoopCondition::Signal))
360 .WillRepeatedly(Return());
362 SigninManagerBase* signin_manager =
363 SigninManagerFactory::GetForProfile(browser()->profile());
365 DCHECK(signin_manager);
366 signin_manager->SetAuthenticatedAccountInfo(kSampleGaiaId, kSampleUser);
368 fake_fetcher_factory().SetFakeResponse(
369 GURL(kURLInfo),
370 kResponseInfo,
371 net::HTTP_OK,
372 net::URLRequestStatus::SUCCESS);
374 fake_fetcher_factory().SetFakeResponse(
375 GURL(kURLRegisterStart),
376 kResponseRegisterStart,
377 net::HTTP_OK,
378 net::URLRequestStatus::SUCCESS);
380 fake_fetcher_factory().SetFakeResponse(
381 GURL(kURLRegisterClaimToken),
382 kResponseRegisterClaimTokenNoConfirm,
383 net::HTTP_OK,
384 net::URLRequestStatus::SUCCESS);
386 fake_fetcher_factory().SetFakeResponse(
387 GURL(kURLCloudPrintConfirm),
388 kResponseCloudPrintConfirm,
389 net::HTTP_OK,
390 net::URLRequestStatus::SUCCESS);
392 fake_fetcher_factory().SetFakeResponse(
393 GURL(kURLRegisterComplete),
394 kResponseRegisterComplete,
395 net::HTTP_OK,
396 net::URLRequestStatus::SUCCESS);
398 fake_fetcher_factory().SetFakeResponse(
399 GaiaUrls::GetInstance()->oauth2_token_url(),
400 kResponseGaiaToken,
401 net::HTTP_OK,
402 net::URLRequestStatus::SUCCESS);
404 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
405 GaiaUrls::GetInstance()->oauth2_token_url().spec()))
406 .Times(AnyNumber());
408 fake_fetcher_factory().SetFakeResponse(
409 GaiaUrls::GetInstance()->oauth_user_info_url(),
410 kResponseGaiaId,
411 net::HTTP_OK,
412 net::URLRequestStatus::SUCCESS);
414 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
415 GaiaUrls::GetInstance()->oauth_user_info_url().spec()))
416 .Times(AnyNumber());
418 ProfileOAuth2TokenService* token_service =
419 ProfileOAuth2TokenServiceFactory::GetForProfile(browser()->profile());
421 token_service->UpdateCredentials(
422 signin_manager->GetAuthenticatedAccountId(), "MyFakeToken");
424 AddLibrary(base::FilePath(FILE_PATH_LITERAL("local_discovery_ui_test.js")));
427 void SetUpCommandLine(base::CommandLine* command_line) override {
428 #if defined(OS_CHROMEOS)
429 // On chromeos, don't sign in with the stub-user automatically. Use the
430 // kLoginUser instead.
431 command_line->AppendSwitchASCII(chromeos::switches::kLoginUser,
432 kSampleUser);
433 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile,
434 chrome::kTestUserProfileDir);
435 #endif
436 WebUIBrowserTest::SetUpCommandLine(command_line);
439 void RunFor(base::TimeDelta time_period) {
440 base::CancelableCallback<void()> callback(base::Bind(
441 &base::MessageLoop::Quit, base::Unretained(
442 base::MessageLoop::current())));
443 base::MessageLoop::current()->task_runner()->PostDelayedTask(
444 FROM_HERE, callback.callback(), time_period);
446 base::MessageLoop::current()->Run();
447 callback.Cancel();
450 TestServiceDiscoveryClient* test_service_discovery_client() {
451 return test_service_discovery_client_.get();
454 TestMessageLoopCondition& condition_devices_listed() {
455 return condition_devices_listed_;
458 net::FakeURLFetcherFactory& fake_fetcher_factory() {
459 return fake_fetcher_factory_;
462 MockableFakeURLFetcherCreator& fake_url_fetcher_creator() {
463 return fake_url_fetcher_creator_;
466 private:
467 scoped_refptr<TestServiceDiscoveryClient> test_service_discovery_client_;
468 TestMessageLoopCondition condition_devices_listed_;
470 net::URLFetcherImplFactory fetcher_impl_factory_;
471 StrictMock<MockableFakeURLFetcherCreator> fake_url_fetcher_creator_;
472 net::FakeURLFetcherFactory fake_fetcher_factory_;
474 DISALLOW_COPY_AND_ASSIGN(LocalDiscoveryUITest);
477 IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, EmptyTest) {
478 ui_test_utils::NavigateToURL(browser(), GURL(
479 chrome::kChromeUIDevicesURL));
480 condition_devices_listed().Wait();
481 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkNoDevices"));
484 IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, AddRowTest) {
485 ui_test_utils::NavigateToURL(browser(), GURL(
486 chrome::kChromeUIDevicesURL));
487 condition_devices_listed().Wait();
489 test_service_discovery_client()->SimulateReceive(
490 kAnnouncePacket, sizeof(kAnnouncePacket));
492 base::MessageLoop::current()->RunUntilIdle();
494 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkOneDevice"));
496 test_service_discovery_client()->SimulateReceive(
497 kGoodbyePacket, sizeof(kGoodbyePacket));
499 RunFor(base::TimeDelta::FromMilliseconds(1100));
501 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkNoDevices"));
505 IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, RegisterTest) {
506 TestMessageLoopCondition condition_token_claimed;
508 ui_test_utils::NavigateToURL(browser(), GURL(
509 chrome::kChromeUIDevicesURL));
510 condition_devices_listed().Wait();
512 test_service_discovery_client()->SimulateReceive(
513 kAnnouncePacket, sizeof(kAnnouncePacket));
515 base::MessageLoop::current()->RunUntilIdle();
517 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkOneDevice"));
519 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("registerShowOverlay"));
522 InSequence s;
523 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(kURLInfo));
524 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
525 kURLRegisterStart));
526 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
527 kURLRegisterClaimToken))
528 .WillOnce(InvokeWithoutArgs(&condition_token_claimed,
529 &TestMessageLoopCondition::Signal));
532 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("registerBegin"));
534 condition_token_claimed.Wait();
536 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("expectPageAdding1"));
538 fake_fetcher_factory().SetFakeResponse(
539 GURL(kURLRegisterClaimToken),
540 kResponseRegisterClaimTokenConfirm,
541 net::HTTP_OK,
542 net::URLRequestStatus::SUCCESS);
544 fake_fetcher_factory().SetFakeResponse(
545 GURL(kURLInfo),
546 kResponseInfoWithID,
547 net::HTTP_OK,
548 net::URLRequestStatus::SUCCESS);
551 InSequence s;
552 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
553 kURLRegisterClaimToken));
554 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
555 kURLCloudPrintConfirm));
556 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(
557 kURLRegisterComplete));
558 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(kURLInfo))
559 .WillOnce(InvokeWithoutArgs(&condition_token_claimed,
560 &TestMessageLoopCondition::Signal));
563 condition_token_claimed.Wait();
565 test_service_discovery_client()->SimulateReceive(
566 kAnnouncePacketRegistered, sizeof(kAnnouncePacketRegistered));
568 base::MessageLoop::current()->RunUntilIdle();
570 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("expectRegisterDone"));
573 } // namespace
575 } // namespace local_discovery