local_discovery_ui_browsertest.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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 "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/memory/scoped_ptr.h" 11#include "base/message_loop/message_loop.h" 12#include "chrome/browser/local_discovery/test_service_discovery_client.h" 13#include "chrome/browser/signin/profile_oauth2_token_service.h" 14#include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 15#include "chrome/browser/signin/signin_manager.h" 16#include "chrome/browser/signin/signin_manager_base.h" 17#include "chrome/browser/signin/signin_manager_factory.h" 18#include "chrome/browser/ui/browser.h" 19#include "chrome/browser/ui/webui/local_discovery/local_discovery_ui_handler.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_browsertest.h" 24#include "google_apis/gaia/gaia_urls.h" 25#include "net/http/http_status_code.h" 26#include "net/url_request/test_url_fetcher_factory.h" 27#include "net/url_request/url_request_status.h" 28#include "net/url_request/url_request_test_util.h" 29 30using testing::InvokeWithoutArgs; 31using testing::Return; 32using testing::AtLeast; 33using testing::DoDefault; 34using testing::DoAll; 35using testing::InSequence; 36using testing::StrictMock; 37using testing::AnyNumber; 38 39using testing::InvokeWithoutArgs; 40using testing::Return; 41using testing::AtLeast; 42 43namespace local_discovery { 44 45namespace { 46 47const uint8 kQueryData[] = { 48 // Header 49 0x00, 0x00, 50 0x00, 0x00, // Flags not set. 51 0x00, 0x01, // Set QDCOUNT (question count) to 1, all the 52 // rest are 0 for a query. 53 0x00, 0x00, 54 0x00, 0x00, 55 0x00, 0x00, 56 57 // Question 58 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 59 0x04, '_', 't', 'c', 'p', 60 0x05, 'l', 'o', 'c', 'a', 'l', 61 0x00, 62 63 0x00, 0x0c, // QTYPE: A query. 64 0x00, 0x01, // QCLASS: IN class. Unicast bit not set. 65}; 66 67const uint8 kAnnouncePacket[] = { 68 // Header 69 0x00, 0x00, // ID is zeroed out 70 0x80, 0x00, // Standard query response, no error 71 0x00, 0x00, // No questions (for simplicity) 72 0x00, 0x05, // 5 RR (answers) 73 0x00, 0x00, // 0 authority RRs 74 0x00, 0x00, // 0 additional RRs 75 76 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 77 0x04, '_', 't', 'c', 'p', 78 0x05, 'l', 'o', 'c', 'a', 'l', 79 0x00, 80 0x00, 0x0c, // TYPE is PTR. 81 0x00, 0x01, // CLASS is IN. 82 0x00, 0x00, // TTL (4 bytes) is 32768 second. 83 0x10, 0x00, 84 0x00, 0x0c, // RDLENGTH is 12 bytes. 85 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 86 0xc0, 0x0c, 87 88 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 89 0xc0, 0x0c, 90 0x00, 0x10, // TYPE is TXT. 91 0x00, 0x01, // CLASS is IN. 92 0x00, 0x00, // TTL (4 bytes) is 32768 seconds. 93 0x01, 0x00, 94 0x00, 0x34, // RDLENGTH is 69 bytes. 95 0x03, 'i', 'd', '=', 96 0x10, 't', 'y', '=', 'S', 'a', 'm', 'p', 'l', 'e', ' ', 97 'd', 'e', 'v', 'i', 'c', 'e', 98 0x1e, 'n', 'o', 't', 'e', '=', 99 'S', 'a', 'm', 'p', 'l', 'e', ' ', 'd', 'e', 'v', 'i', 'c', 'e', ' ', 100 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 101 102 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 103 0xc0, 0x0c, 104 0x00, 0x21, // Type is SRV 105 0x00, 0x01, // CLASS is IN 106 0x00, 0x00, // TTL (4 bytes) is 32768 second. 107 0x10, 0x00, 108 0x00, 0x17, // RDLENGTH is 23 109 0x00, 0x00, 110 0x00, 0x00, 111 0x22, 0xb8, // port 8888 112 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 113 0x05, 'l', 'o', 'c', 'a', 'l', 114 0x00, 115 116 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 117 0x05, 'l', 'o', 'c', 'a', 'l', 118 0x00, 119 0x00, 0x01, // Type is A 120 0x00, 0x01, // CLASS is IN 121 0x00, 0x00, // TTL (4 bytes) is 32768 second. 122 0x10, 0x00, 123 0x00, 0x04, // RDLENGTH is 4 124 0x01, 0x02, 0x03, 0x04, // 1.2.3.4 125 126 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 127 0x05, 'l', 'o', 'c', 'a', 'l', 128 0x00, 129 0x00, 0x1C, // Type is AAAA 130 0x00, 0x01, // CLASS is IN 131 0x00, 0x00, // TTL (4 bytes) is 32768 second. 132 0x10, 0x00, 133 0x00, 0x10, // RDLENGTH is 16 134 0x01, 0x02, 0x03, 0x04, // 1.2.3.4 135 0x01, 0x02, 0x03, 0x04, 136 0x01, 0x02, 0x03, 0x04, 137 0x01, 0x02, 0x03, 0x04, 138}; 139 140 141const uint8 kGoodbyePacket[] = { 142 // Header 143 0x00, 0x00, // ID is zeroed out 144 0x80, 0x00, // Standard query response, RA, no error 145 0x00, 0x00, // No questions (for simplicity) 146 0x00, 0x02, // 1 RR (answers) 147 0x00, 0x00, // 0 authority RRs 148 0x00, 0x00, // 0 additional RRs 149 150 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 151 0x04, '_', 't', 'c', 'p', 152 0x05, 'l', 'o', 'c', 'a', 'l', 153 0x00, 154 0x00, 0x0c, // TYPE is PTR. 155 0x00, 0x01, // CLASS is IN. 156 0x00, 0x00, // TTL (4 bytes) is 0 seconds. 157 0x00, 0x00, 158 0x00, 0x0c, // RDLENGTH is 12 bytes. 159 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 160 0xc0, 0x0c, 161 162 163 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 164 0xc0, 0x0c, 165 0x00, 0x21, // Type is SRV 166 0x00, 0x01, // CLASS is IN 167 0x00, 0x00, // TTL (4 bytes) is 0 seconds. 168 0x00, 0x00, 169 0x00, 0x17, // RDLENGTH is 23 170 0x00, 0x00, 171 0x00, 0x00, 172 0x22, 0xb8, // port 8888 173 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 174 0x05, 'l', 'o', 'c', 'a', 'l', 175 0x00, 176}; 177 178const uint8 kAnnouncePacketRegistered[] = { 179 // Header 180 0x00, 0x00, // ID is zeroed out 181 0x80, 0x00, // Standard query response, RA, no error 182 0x00, 0x00, // No questions (for simplicity) 183 0x00, 0x01, // 1 RR (answers) 184 0x00, 0x00, // 0 authority RRs 185 0x00, 0x00, // 0 additional RRs 186 187 0x09, 'm', 'y', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 188 0x07, '_', 'p', 'r', 'i', 'v', 'e', 't', 189 0x04, '_', 't', 'c', 'p', 190 0x05, 'l', 'o', 'c', 'a', 'l', 191 0x00, 192 0x00, 0x10, // TYPE is TXT. 193 0x00, 0x01, // CLASS is IN. 194 0x00, 0x00, // TTL (4 bytes) is 32768 seconds. 195 0x01, 0x00, 196 0x00, 0x3b, // RDLENGTH is 76 bytes. 197 0x0a, 'i', 'd', '=', 's', 'o', 'm', 'e', '_', 'i', 'd', 198 0x10, 't', 'y', '=', 'S', 'a', 'm', 'p', 'l', 'e', ' ', 199 'd', 'e', 'v', 'i', 'c', 'e', 200 0x1e, 'n', 'o', 't', 'e', '=', 201 'S', 'a', 'm', 'p', 'l', 'e', ' ', 'd', 'e', 'v', 'i', 'c', 'e', ' ', 202 'd', 'e', 's', 'c', 'r', 'i', 'p', 't', 'i', 'o', 'n', 203}; 204 205const char kResponseInfo[] = "{" 206 " \"x-privet-token\" : \"MyPrivetToken\"" 207 "}"; 208 209const char kResponseInfoWithID[] = "{" 210 " \"x-privet-token\" : \"MyPrivetToken\"," 211 " \"id\" : \"my_id\"" 212 "}"; 213 214const char kResponseRegisterStart[] = "{" 215 " \"action\": \"start\"," 216 " \"user\": \"user@host.com\"" 217 "}"; 218 219const char kResponseRegisterClaimTokenNoConfirm[] = "{" 220 " \"action\": \"getClaimToken\"," 221 " \"user\": \"user@host.com\"," 222 " \"error\": \"pending_user_action\"," 223 " \"timeout\": 1" 224 "}"; 225 226const char kResponseRegisterClaimTokenConfirm[] = "{" 227 " \"action\": \"getClaimToken\"," 228 " \"user\": \"user@host.com\"," 229 " \"token\": \"MySampleToken\"," 230 " \"claim_url\": \"http://someurl.com/\"" 231 "}"; 232 233const char kResponseCloudPrintConfirm[] = "{ \"success\": true }"; 234 235const char kResponseRegisterComplete[] = "{" 236 " \"action\": \"complete\"," 237 " \"user\": \"user@host.com\"," 238 " \"device_id\": \"my_id\"" 239 "}"; 240 241const char kResponseGaiaToken[] = "{" 242 " \"access_token\": \"at1\"," 243 " \"expires_in\": 3600," 244 " \"token_type\": \"Bearer\"" 245 "}"; 246 247const char kResponseGaiaId[] = "{" 248 " \"id\": \"12345\"" 249 "}"; 250 251const char kURLInfo[] = "http://1.2.3.4:8888/privet/info"; 252 253const char kURLRegisterStart[] = 254 "http://1.2.3.4:8888/privet/register?action=start&user=user%40host.com"; 255 256const char kURLRegisterClaimToken[] = 257 "http://1.2.3.4:8888/privet/register?action=getClaimToken&" 258 "user=user%40host.com"; 259 260const char kURLCloudPrintConfirm[] = 261 "https://www.google.com/cloudprint/confirm?token=MySampleToken"; 262 263const char kURLRegisterComplete[] = 264 "http://1.2.3.4:8888/privet/register?action=complete&user=user%40host.com"; 265 266const char kURLGaiaToken[] = 267 "https://accounts.google.com/o/oauth2/token"; 268 269const char kSampleUser[] = "user@host.com"; 270 271class TestMessageLoopCondition { 272 public: 273 TestMessageLoopCondition() : signaled_(false), 274 waiting_(false) { 275 } 276 277 ~TestMessageLoopCondition() { 278 } 279 280 // Signal a waiting method that it can continue executing. 281 void Signal() { 282 signaled_ = true; 283 if (waiting_) 284 base::MessageLoop::current()->Quit(); 285 } 286 287 // Pause execution and recursively run the message loop until |Signal()| is 288 // called. Do not pause if |Signal()| has already been called. 289 void Wait() { 290 while (!signaled_) { 291 waiting_ = true; 292 base::MessageLoop::current()->Run(); 293 waiting_ = false; 294 } 295 signaled_ = false; 296 } 297 298 private: 299 bool signaled_; 300 bool waiting_; 301 302 DISALLOW_COPY_AND_ASSIGN(TestMessageLoopCondition); 303}; 304 305class MockableFakeURLFetcherCreator { 306 public: 307 MockableFakeURLFetcherCreator() { 308 } 309 310 ~MockableFakeURLFetcherCreator() { 311 } 312 313 MOCK_METHOD1(OnCreateFakeURLFetcher, void(const std::string& url)); 314 315 scoped_ptr<net::FakeURLFetcher> CreateFakeURLFetcher( 316 const GURL& url, 317 net::URLFetcherDelegate* delegate, 318 const std::string& response_data, 319 net::HttpStatusCode response_code, 320 net::URLRequestStatus::Status status) { 321 OnCreateFakeURLFetcher(url.spec()); 322 return scoped_ptr<net::FakeURLFetcher>(new net::FakeURLFetcher( 323 url, delegate, response_data, response_code, status)); 324 } 325 326 net::FakeURLFetcherFactory::FakeURLFetcherCreator callback() { 327 return base::Bind(&MockableFakeURLFetcherCreator::CreateFakeURLFetcher, 328 base::Unretained(this)); 329 } 330}; 331 332class LocalDiscoveryUITest : public WebUIBrowserTest { 333 public: 334 LocalDiscoveryUITest() : fake_fetcher_factory_( 335 &fetcher_impl_factory_, 336 fake_url_fetcher_creator_.callback()) { 337 } 338 virtual ~LocalDiscoveryUITest() { 339 } 340 341 virtual void SetUpOnMainThread() OVERRIDE { 342 WebUIBrowserTest::SetUpOnMainThread(); 343 344 test_service_discovery_client_ = new TestServiceDiscoveryClient(); 345 test_service_discovery_client_->Start(); 346 EXPECT_CALL(*test_service_discovery_client_, OnSendTo( 347 std::string((const char*)kQueryData, 348 sizeof(kQueryData)))) 349 .Times(AtLeast(2)) 350 .WillOnce(InvokeWithoutArgs(&condition_devices_listed_, 351 &TestMessageLoopCondition::Signal)) 352 .WillRepeatedly(Return()); 353 354 SigninManagerBase* signin_manager = 355 SigninManagerFactory::GetForProfile(browser()->profile()); 356 357 DCHECK(signin_manager); 358 signin_manager->SetAuthenticatedUsername(kSampleUser); 359 360 fake_fetcher_factory().SetFakeResponse( 361 GURL(kURLInfo), 362 kResponseInfo, 363 net::HTTP_OK, 364 net::URLRequestStatus::SUCCESS); 365 366 fake_fetcher_factory().SetFakeResponse( 367 GURL(kURLRegisterStart), 368 kResponseRegisterStart, 369 net::HTTP_OK, 370 net::URLRequestStatus::SUCCESS); 371 372 fake_fetcher_factory().SetFakeResponse( 373 GURL(kURLRegisterClaimToken), 374 kResponseRegisterClaimTokenNoConfirm, 375 net::HTTP_OK, 376 net::URLRequestStatus::SUCCESS); 377 378 fake_fetcher_factory().SetFakeResponse( 379 GURL(kURLCloudPrintConfirm), 380 kResponseCloudPrintConfirm, 381 net::HTTP_OK, 382 net::URLRequestStatus::SUCCESS); 383 384 fake_fetcher_factory().SetFakeResponse( 385 GURL(kURLRegisterComplete), 386 kResponseRegisterComplete, 387 net::HTTP_OK, 388 net::URLRequestStatus::SUCCESS); 389 390 fake_fetcher_factory().SetFakeResponse( 391 GURL(kURLGaiaToken), 392 kResponseGaiaToken, 393 net::HTTP_OK, 394 net::URLRequestStatus::SUCCESS); 395 396 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher( 397 kURLGaiaToken)) 398 .Times(AnyNumber()); 399 400 fake_fetcher_factory().SetFakeResponse( 401 GaiaUrls::GetInstance()->oauth_user_info_url(), 402 kResponseGaiaId, 403 net::HTTP_OK, 404 net::URLRequestStatus::SUCCESS); 405 406 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher( 407 GaiaUrls::GetInstance()->oauth_user_info_url().spec())) 408 .Times(AnyNumber()); 409 410 ProfileOAuth2TokenService* token_service = 411 ProfileOAuth2TokenServiceFactory::GetForProfile(browser()->profile()); 412 413 token_service->UpdateCredentials("user@host.com", "MyFakeToken"); 414 415 AddLibrary(base::FilePath(FILE_PATH_LITERAL("local_discovery_ui_test.js"))); 416 } 417 418 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 419 WebUIBrowserTest::SetUpCommandLine(command_line); 420 } 421 422 void RunFor(base::TimeDelta time_period) { 423 base::CancelableCallback<void()> callback(base::Bind( 424 &base::MessageLoop::Quit, base::Unretained( 425 base::MessageLoop::current()))); 426 base::MessageLoop::current()->PostDelayedTask( 427 FROM_HERE, callback.callback(), time_period); 428 429 base::MessageLoop::current()->Run(); 430 callback.Cancel(); 431 } 432 433 TestServiceDiscoveryClient* test_service_discovery_client() { 434 return test_service_discovery_client_.get(); 435 } 436 437 TestMessageLoopCondition& condition_devices_listed() { 438 return condition_devices_listed_; 439 } 440 441 net::FakeURLFetcherFactory& fake_fetcher_factory() { 442 return fake_fetcher_factory_; 443 } 444 445 MockableFakeURLFetcherCreator& fake_url_fetcher_creator() { 446 return fake_url_fetcher_creator_; 447 } 448 449 private: 450 scoped_refptr<TestServiceDiscoveryClient> test_service_discovery_client_; 451 TestMessageLoopCondition condition_devices_listed_; 452 453 net::URLFetcherImplFactory fetcher_impl_factory_; 454 StrictMock<MockableFakeURLFetcherCreator> fake_url_fetcher_creator_; 455 net::FakeURLFetcherFactory fake_fetcher_factory_; 456 457 DISALLOW_COPY_AND_ASSIGN(LocalDiscoveryUITest); 458}; 459 460IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, EmptyTest) { 461 ui_test_utils::NavigateToURL(browser(), GURL( 462 chrome::kChromeUIDevicesURL)); 463 condition_devices_listed().Wait(); 464 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkNoDevices")); 465} 466 467IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, AddRowTest) { 468 ui_test_utils::NavigateToURL(browser(), GURL( 469 chrome::kChromeUIDevicesURL)); 470 condition_devices_listed().Wait(); 471 472 test_service_discovery_client()->SimulateReceive( 473 kAnnouncePacket, sizeof(kAnnouncePacket)); 474 475 base::MessageLoop::current()->RunUntilIdle(); 476 477 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkOneDevice")); 478 479 test_service_discovery_client()->SimulateReceive( 480 kGoodbyePacket, sizeof(kGoodbyePacket)); 481 482 RunFor(base::TimeDelta::FromMilliseconds(1100)); 483 484 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkNoDevices")); 485} 486 487 488IN_PROC_BROWSER_TEST_F(LocalDiscoveryUITest, RegisterTest) { 489 TestMessageLoopCondition condition_token_claimed; 490 491 ui_test_utils::NavigateToURL(browser(), GURL( 492 chrome::kChromeUIDevicesURL)); 493 condition_devices_listed().Wait(); 494 495 test_service_discovery_client()->SimulateReceive( 496 kAnnouncePacket, sizeof(kAnnouncePacket)); 497 498 base::MessageLoop::current()->RunUntilIdle(); 499 500 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("checkOneDevice")); 501 502 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("registerShowOverlay")); 503 504 { 505 InSequence s; 506 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(kURLInfo)); 507 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher( 508 kURLRegisterStart)); 509 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher( 510 kURLRegisterClaimToken)) 511 .WillOnce(InvokeWithoutArgs(&condition_token_claimed, 512 &TestMessageLoopCondition::Signal)); 513 } 514 515 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("registerBegin")); 516 517 condition_token_claimed.Wait(); 518 519 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("expectPageAdding1")); 520 521 fake_fetcher_factory().SetFakeResponse( 522 GURL(kURLRegisterClaimToken), 523 kResponseRegisterClaimTokenConfirm, 524 net::HTTP_OK, 525 net::URLRequestStatus::SUCCESS); 526 527 fake_fetcher_factory().SetFakeResponse( 528 GURL(kURLInfo), 529 kResponseInfoWithID, 530 net::HTTP_OK, 531 net::URLRequestStatus::SUCCESS); 532 533 { 534 InSequence s; 535 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher( 536 kURLRegisterClaimToken)); 537 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher( 538 kURLCloudPrintConfirm)); 539 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher( 540 kURLRegisterComplete)); 541 EXPECT_CALL(fake_url_fetcher_creator(), OnCreateFakeURLFetcher(kURLInfo)) 542 .WillOnce(InvokeWithoutArgs(&condition_token_claimed, 543 &TestMessageLoopCondition::Signal)); 544 } 545 546 condition_token_claimed.Wait(); 547 548 test_service_discovery_client()->SimulateReceive( 549 kAnnouncePacketRegistered, sizeof(kAnnouncePacketRegistered)); 550 551 base::MessageLoop::current()->RunUntilIdle(); 552 553 EXPECT_TRUE(WebUIBrowserTest::RunJavascriptTest("expectRegisterDone")); 554} 555 556} // namespace 557 558} // namespace local_discovery 559