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