Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: components/gcm_driver/gcm_driver_desktop_unittest.cc

Issue 617003005: Keep the GCM data intact when the user signs out of the profile (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/gcm_driver/gcm_driver_desktop.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/gcm_driver/gcm_driver_desktop.h" 5 #include "components/gcm_driver/gcm_driver_desktop.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/bind_helpers.h" 8 #include "base/bind_helpers.h"
9 #include "base/files/scoped_temp_dir.h" 9 #include "base/files/scoped_temp_dir.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 driver_->RemoveAppHandler(kTestAppID2); 266 driver_->RemoveAppHandler(kTestAppID2);
267 } 267 }
268 268
269 void GCMDriverTest::SignIn(const std::string& account_id) { 269 void GCMDriverTest::SignIn(const std::string& account_id) {
270 driver_->OnSignedIn(); 270 driver_->OnSignedIn();
271 PumpIOLoop(); 271 PumpIOLoop();
272 PumpUILoop(); 272 PumpUILoop();
273 } 273 }
274 274
275 void GCMDriverTest::SignOut() { 275 void GCMDriverTest::SignOut() {
276 driver_->Purge(); 276 driver_->OnSignedOut();
277 PumpIOLoop(); 277 PumpIOLoop();
278 PumpUILoop(); 278 PumpUILoop();
279 } 279 }
280 280
281 void GCMDriverTest::Register(const std::string& app_id, 281 void GCMDriverTest::Register(const std::string& app_id,
282 const std::vector<std::string>& sender_ids, 282 const std::vector<std::string>& sender_ids,
283 WaitToFinish wait_to_finish) { 283 WaitToFinish wait_to_finish) {
284 base::RunLoop run_loop; 284 base::RunLoop run_loop;
285 async_operation_completed_callback_ = run_loop.QuitClosure(); 285 async_operation_completed_callback_ = run_loop.QuitClosure();
286 driver_->Register(app_id, 286 driver_->Register(app_id,
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
372 EXPECT_FALSE(driver()->IsStarted()); 372 EXPECT_FALSE(driver()->IsStarted());
373 EXPECT_FALSE(driver()->IsConnected()); 373 EXPECT_FALSE(driver()->IsConnected());
374 EXPECT_FALSE(gcm_connection_observer()->connected()); 374 EXPECT_FALSE(gcm_connection_observer()->connected());
375 375
376 // GCM will be started after app handler is added. 376 // GCM will be started after app handler is added.
377 AddAppHandlers(); 377 AddAppHandlers();
378 EXPECT_TRUE(driver()->IsStarted()); 378 EXPECT_TRUE(driver()->IsStarted());
379 PumpIOLoop(); 379 PumpIOLoop();
380 EXPECT_TRUE(driver()->IsConnected()); 380 EXPECT_TRUE(driver()->IsConnected());
381 EXPECT_TRUE(gcm_connection_observer()->connected()); 381 EXPECT_TRUE(gcm_connection_observer()->connected());
382
383 // Sign-in will not affect GCM state.
384 SignIn(kTestAccountID1);
385 PumpIOLoop();
386 EXPECT_TRUE(driver()->IsStarted());
387 EXPECT_TRUE(driver()->IsConnected());
388
389 // Sign-out will not affect GCM state.
390 SignOut();
391 PumpIOLoop();
392 EXPECT_TRUE(driver()->IsStarted());
393 EXPECT_TRUE(driver()->IsConnected());
382 } 394 }
383 395
384 TEST_F(GCMDriverTest, Shutdown) { 396 TEST_F(GCMDriverTest, Shutdown) {
385 CreateDriver(FakeGCMClient::NO_DELAY_START); 397 CreateDriver(FakeGCMClient::NO_DELAY_START);
386 EXPECT_FALSE(HasAppHandlers()); 398 EXPECT_FALSE(HasAppHandlers());
387 399
388 AddAppHandlers(); 400 AddAppHandlers();
389 EXPECT_TRUE(HasAppHandlers()); 401 EXPECT_TRUE(HasAppHandlers());
390 402
391 ShutdownDriver(); 403 ShutdownDriver();
392 EXPECT_FALSE(HasAppHandlers()); 404 EXPECT_FALSE(HasAppHandlers());
393 EXPECT_FALSE(driver()->IsConnected()); 405 EXPECT_FALSE(driver()->IsConnected());
394 EXPECT_FALSE(gcm_connection_observer()->connected()); 406 EXPECT_FALSE(gcm_connection_observer()->connected());
395 } 407 }
396 408
397 TEST_F(GCMDriverTest, SignInAndSignOutOnGCMEnabled) { 409 TEST_F(GCMDriverTest, SignInAndSignOutOnGCMEnabled) {
398 // By default, GCM is enabled. 410 // By default, GCM is enabled.
399 CreateDriver(FakeGCMClient::NO_DELAY_START); 411 CreateDriver(FakeGCMClient::NO_DELAY_START);
400 AddAppHandlers(); 412 AddAppHandlers();
401 413
402 // GCMClient should be started after sign-in. 414 // GCMClient should be started after sign-in.
403 SignIn(kTestAccountID1); 415 SignIn(kTestAccountID1);
404 EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); 416 EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
405 417
406 // GCMClient should be checked out after sign-out. 418 // GCMClient should be stopped out after sign-out.
419 // Note: Before we enable the feature that drops the sign-in enforcement and
420 // make GCM work for all users, GCM is only applicable to signed-in users.
421 // Once the users sign out, the GCM will be shut down while the GCM store
422 // remains intact.
407 SignOut(); 423 SignOut();
408 EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status()); 424 EXPECT_EQ(FakeGCMClient::STOPPED, GetGCMClient()->status());
409 } 425 }
410 426
411 TEST_F(GCMDriverTest, SignInAndSignOutOnGCMDisabled) { 427 TEST_F(GCMDriverTest, SignInAndSignOutOnGCMDisabled) {
412 // By default, GCM is enabled. 428 // By default, GCM is enabled.
413 CreateDriver(FakeGCMClient::NO_DELAY_START); 429 CreateDriver(FakeGCMClient::NO_DELAY_START);
414 AddAppHandlers(); 430 AddAppHandlers();
415 431
416 // Disable GCM. 432 // Disable GCM.
417 driver()->Disable(); 433 driver()->Disable();
418 434
419 // GCMClient should not be started after sign-in. 435 // GCMClient should not be started after sign-in.
420 SignIn(kTestAccountID1); 436 SignIn(kTestAccountID1);
421 EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status()); 437 EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status());
422 438
423 // Check-out should still be performed after sign-out. 439 // GCMClient should remain not started after sign-out.
424 SignOut(); 440 SignOut();
425 EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status()); 441 EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status());
426 } 442 }
427 443
428 TEST_F(GCMDriverTest, SignOutAndThenSignIn) { 444 TEST_F(GCMDriverTest, SignOutAndThenSignIn) {
429 CreateDriver(FakeGCMClient::NO_DELAY_START); 445 CreateDriver(FakeGCMClient::NO_DELAY_START);
430 AddAppHandlers(); 446 AddAppHandlers();
431 447
432 // GCMClient should be started after sign-in. 448 // GCMClient should be started after sign-in.
433 SignIn(kTestAccountID1); 449 SignIn(kTestAccountID1);
434 EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); 450 EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
435 451
436 // GCMClient should be checked out after sign-out. 452 // GCMClient should be stopped after sign-out.
437 SignOut(); 453 SignOut();
438 EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status()); 454 EXPECT_EQ(FakeGCMClient::STOPPED, GetGCMClient()->status());
439 455
440 // Sign-in with a different account. 456 // Sign-in with a different account.
441 SignIn(kTestAccountID2); 457 SignIn(kTestAccountID2);
442 458
443 // GCMClient should be started again. 459 // GCMClient should be started again.
444 EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status()); 460 EXPECT_EQ(FakeGCMClient::STARTED, GetGCMClient()->status());
445 } 461 }
446 462
447 TEST_F(GCMDriverTest, DisableAndReenableGCM) { 463 TEST_F(GCMDriverTest, DisableAndReenableGCM) {
448 CreateDriver(FakeGCMClient::NO_DELAY_START); 464 CreateDriver(FakeGCMClient::NO_DELAY_START);
(...skipping 23 matching lines...) Expand all
472 driver()->Disable(); 488 driver()->Disable();
473 PumpIOLoop(); 489 PumpIOLoop();
474 PumpUILoop(); 490 PumpUILoop();
475 491
476 // GCMClient should be stopped. 492 // GCMClient should be stopped.
477 EXPECT_EQ(FakeGCMClient::STOPPED, GetGCMClient()->status()); 493 EXPECT_EQ(FakeGCMClient::STOPPED, GetGCMClient()->status());
478 494
479 // Sign out. 495 // Sign out.
480 SignOut(); 496 SignOut();
481 497
482 // GCMClient should be checked out. 498 // GCMClient should be stopped.
483 EXPECT_EQ(FakeGCMClient::CHECKED_OUT, GetGCMClient()->status()); 499 EXPECT_EQ(FakeGCMClient::STOPPED, GetGCMClient()->status());
484 } 500 }
485 501
486 TEST_F(GCMDriverTest, StartOrStopGCMOnDemand) { 502 TEST_F(GCMDriverTest, StartOrStopGCMOnDemand) {
487 CreateDriver(FakeGCMClient::NO_DELAY_START); 503 CreateDriver(FakeGCMClient::NO_DELAY_START);
488 SignIn(kTestAccountID1); 504 SignIn(kTestAccountID1);
489 505
490 // GCMClient is not started. 506 // GCMClient is not started.
491 EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status()); 507 EXPECT_EQ(FakeGCMClient::UNINITIALIZED, GetGCMClient()->status());
492 508
493 // GCMClient is started after an app handler has been added. 509 // GCMClient is started after an app handler has been added.
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 CreateDriver(FakeGCMClient::NO_DELAY_START); 699 CreateDriver(FakeGCMClient::NO_DELAY_START);
684 AddAppHandlers(); 700 AddAppHandlers();
685 SignIn(kTestAccountID1); 701 SignIn(kTestAccountID1);
686 } 702 }
687 703
688 TEST_F(GCMDriverFunctionalTest, Register) { 704 TEST_F(GCMDriverFunctionalTest, Register) {
689 std::vector<std::string> sender_ids; 705 std::vector<std::string> sender_ids;
690 sender_ids.push_back("sender1"); 706 sender_ids.push_back("sender1");
691 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT); 707 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
692 const std::string expected_registration_id = 708 const std::string expected_registration_id =
693 FakeGCMClient::GetRegistrationIdFromSenderIds(sender_ids); 709 GetGCMClient()->GetRegistrationIdFromSenderIds(sender_ids);
694 710
695 EXPECT_EQ(expected_registration_id, registration_id()); 711 EXPECT_EQ(expected_registration_id, registration_id());
696 EXPECT_EQ(GCMClient::SUCCESS, registration_result()); 712 EXPECT_EQ(GCMClient::SUCCESS, registration_result());
697 } 713 }
698 714
699 TEST_F(GCMDriverFunctionalTest, RegisterError) { 715 TEST_F(GCMDriverFunctionalTest, RegisterError) {
700 std::vector<std::string> sender_ids; 716 std::vector<std::string> sender_ids;
701 sender_ids.push_back("sender1@error"); 717 sender_ids.push_back("sender1@error");
702 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT); 718 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
703 719
704 EXPECT_TRUE(registration_id().empty()); 720 EXPECT_TRUE(registration_id().empty());
705 EXPECT_NE(GCMClient::SUCCESS, registration_result()); 721 EXPECT_NE(GCMClient::SUCCESS, registration_result());
706 } 722 }
707 723
708 TEST_F(GCMDriverFunctionalTest, RegisterAgainWithSameSenderIDs) { 724 TEST_F(GCMDriverFunctionalTest, RegisterAgainWithSameSenderIDs) {
709 std::vector<std::string> sender_ids; 725 std::vector<std::string> sender_ids;
710 sender_ids.push_back("sender1"); 726 sender_ids.push_back("sender1");
711 sender_ids.push_back("sender2"); 727 sender_ids.push_back("sender2");
712 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT); 728 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
713 const std::string expected_registration_id = 729 const std::string expected_registration_id =
714 FakeGCMClient::GetRegistrationIdFromSenderIds(sender_ids); 730 GetGCMClient()->GetRegistrationIdFromSenderIds(sender_ids);
715 731
716 EXPECT_EQ(expected_registration_id, registration_id()); 732 EXPECT_EQ(expected_registration_id, registration_id());
717 EXPECT_EQ(GCMClient::SUCCESS, registration_result()); 733 EXPECT_EQ(GCMClient::SUCCESS, registration_result());
718 734
719 // Clears the results the would be set by the Register callback in preparation 735 // Clears the results the would be set by the Register callback in preparation
720 // to call register 2nd time. 736 // to call register 2nd time.
721 ClearResults(); 737 ClearResults();
722 738
723 // Calling register 2nd time with the same set of sender IDs but different 739 // Calling register 2nd time with the same set of sender IDs but different
724 // ordering will get back the same registration ID. 740 // ordering will get back the same registration ID.
725 std::vector<std::string> another_sender_ids; 741 std::vector<std::string> another_sender_ids;
726 another_sender_ids.push_back("sender2"); 742 another_sender_ids.push_back("sender2");
727 another_sender_ids.push_back("sender1"); 743 another_sender_ids.push_back("sender1");
728 Register(kTestAppID1, another_sender_ids, GCMDriverTest::WAIT); 744 Register(kTestAppID1, another_sender_ids, GCMDriverTest::WAIT);
729 745
730 EXPECT_EQ(expected_registration_id, registration_id()); 746 EXPECT_EQ(expected_registration_id, registration_id());
731 EXPECT_EQ(GCMClient::SUCCESS, registration_result()); 747 EXPECT_EQ(GCMClient::SUCCESS, registration_result());
732 } 748 }
733 749
734 TEST_F(GCMDriverFunctionalTest, RegisterAgainWithDifferentSenderIDs) { 750 TEST_F(GCMDriverFunctionalTest, RegisterAgainWithDifferentSenderIDs) {
735 std::vector<std::string> sender_ids; 751 std::vector<std::string> sender_ids;
736 sender_ids.push_back("sender1"); 752 sender_ids.push_back("sender1");
737 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT); 753 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
738 const std::string expected_registration_id = 754 const std::string expected_registration_id =
739 FakeGCMClient::GetRegistrationIdFromSenderIds(sender_ids); 755 GetGCMClient()->GetRegistrationIdFromSenderIds(sender_ids);
740 756
741 EXPECT_EQ(expected_registration_id, registration_id()); 757 EXPECT_EQ(expected_registration_id, registration_id());
742 EXPECT_EQ(GCMClient::SUCCESS, registration_result()); 758 EXPECT_EQ(GCMClient::SUCCESS, registration_result());
743 759
744 // Make sender IDs different. 760 // Make sender IDs different.
745 sender_ids.push_back("sender2"); 761 sender_ids.push_back("sender2");
746 const std::string expected_registration_id2 = 762 const std::string expected_registration_id2 =
747 FakeGCMClient::GetRegistrationIdFromSenderIds(sender_ids); 763 GetGCMClient()->GetRegistrationIdFromSenderIds(sender_ids);
748 764
749 // Calling register 2nd time with the different sender IDs will get back a new 765 // Calling register 2nd time with the different sender IDs will get back a new
750 // registration ID. 766 // registration ID.
751 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT); 767 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
752 EXPECT_EQ(expected_registration_id2, registration_id()); 768 EXPECT_EQ(expected_registration_id2, registration_id());
753 EXPECT_EQ(GCMClient::SUCCESS, registration_result()); 769 EXPECT_EQ(GCMClient::SUCCESS, registration_result());
754 } 770 }
755 771
756 TEST_F(GCMDriverFunctionalTest, RegisterAfterSignOut) { 772 TEST_F(GCMDriverFunctionalTest, RegisterAfterSignOut) {
757 // This will trigger check-out.
758 SignOut(); 773 SignOut();
759 774
760 std::vector<std::string> sender_ids; 775 std::vector<std::string> sender_ids;
761 sender_ids.push_back("sender1"); 776 sender_ids.push_back("sender1");
762 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT); 777 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
763 778
764 EXPECT_TRUE(registration_id().empty()); 779 EXPECT_TRUE(registration_id().empty());
765 EXPECT_EQ(GCMClient::NOT_SIGNED_IN, registration_result()); 780 EXPECT_EQ(GCMClient::NOT_SIGNED_IN, registration_result());
766 } 781 }
767 782
783 TEST_F(GCMDriverFunctionalTest, RegisterAfterSignOutAndSignInAgain) {
784 std::vector<std::string> sender_ids;
785 sender_ids.push_back("sender1");
786 const std::string expected_registration_id =
787 GetGCMClient()->GetRegistrationIdFromSenderIds(sender_ids);
788
789 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
790 EXPECT_EQ(expected_registration_id, registration_id());
791 EXPECT_EQ(GCMClient::SUCCESS, registration_result());
792
793 // After signing out, the GCM is stopped and calling register should fail.
794 SignOut();
795 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
796 EXPECT_TRUE(registration_id().empty());
797 EXPECT_EQ(GCMClient::NOT_SIGNED_IN, registration_result());
798
799 // After signing in again, same registration ID should be returned because
800 // the GCM data is not affected.
801 SignIn(kTestAccountID1);
802
803 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
804 EXPECT_EQ(expected_registration_id, registration_id());
805 EXPECT_EQ(GCMClient::SUCCESS, registration_result());
806 }
807
768 TEST_F(GCMDriverFunctionalTest, UnregisterExplicitly) { 808 TEST_F(GCMDriverFunctionalTest, UnregisterExplicitly) {
769 std::vector<std::string> sender_ids; 809 std::vector<std::string> sender_ids;
770 sender_ids.push_back("sender1"); 810 sender_ids.push_back("sender1");
771 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT); 811 Register(kTestAppID1, sender_ids, GCMDriverTest::WAIT);
772 812
773 EXPECT_FALSE(registration_id().empty()); 813 EXPECT_FALSE(registration_id().empty());
774 EXPECT_EQ(GCMClient::SUCCESS, registration_result()); 814 EXPECT_EQ(GCMClient::SUCCESS, registration_result());
775 815
776 Unregister(kTestAppID1, GCMDriverTest::WAIT); 816 Unregister(kTestAppID1, GCMDriverTest::WAIT);
777 817
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
859 899
860 EXPECT_EQ(message.id, send_message_id()); 900 EXPECT_EQ(message.id, send_message_id());
861 EXPECT_EQ(GCMClient::SUCCESS, send_result()); 901 EXPECT_EQ(GCMClient::SUCCESS, send_result());
862 902
863 gcm_app_handler()->WaitForNotification(); 903 gcm_app_handler()->WaitForNotification();
864 EXPECT_EQ(message.id, gcm_app_handler()->acked_message_id()); 904 EXPECT_EQ(message.id, gcm_app_handler()->acked_message_id());
865 EXPECT_EQ(kTestAppID1, gcm_app_handler()->app_id()); 905 EXPECT_EQ(kTestAppID1, gcm_app_handler()->app_id());
866 } 906 }
867 907
868 TEST_F(GCMDriverFunctionalTest, SendAfterSignOut) { 908 TEST_F(GCMDriverFunctionalTest, SendAfterSignOut) {
869 // This will trigger check-out.
870 SignOut(); 909 SignOut();
871 910
872 GCMClient::OutgoingMessage message; 911 GCMClient::OutgoingMessage message;
873 message.id = "1"; 912 message.id = "1";
874 message.data["key1"] = "value1"; 913 message.data["key1"] = "value1";
875 message.data["key2"] = "value2"; 914 message.data["key2"] = "value2";
876 Send(kTestAppID1, kUserID1, message, GCMDriverTest::WAIT); 915 Send(kTestAppID1, kUserID1, message, GCMDriverTest::WAIT);
877 916
878 EXPECT_TRUE(send_message_id().empty()); 917 EXPECT_TRUE(send_message_id().empty());
879 EXPECT_EQ(GCMClient::NOT_SIGNED_IN, send_result()); 918 EXPECT_EQ(GCMClient::NOT_SIGNED_IN, send_result());
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after
1180 // After start-up, the request should still be scheduled at the expected 1219 // After start-up, the request should still be scheduled at the expected
1181 // updated interval. 1220 // updated interval.
1182 actual_delay_seconds = 1221 actual_delay_seconds =
1183 syncer()->current_request_delay_interval().InSeconds(); 1222 syncer()->current_request_delay_interval().InSeconds();
1184 EXPECT_TRUE(CompareDelaySeconds(expected_delay_seconds, actual_delay_seconds)) 1223 EXPECT_TRUE(CompareDelaySeconds(expected_delay_seconds, actual_delay_seconds))
1185 << "expected delay: " << expected_delay_seconds 1224 << "expected delay: " << expected_delay_seconds
1186 << " actual delay: " << actual_delay_seconds; 1225 << " actual delay: " << actual_delay_seconds;
1187 } 1226 }
1188 1227
1189 } // namespace gcm 1228 } // namespace gcm
OLDNEW
« no previous file with comments | « components/gcm_driver/gcm_driver_desktop.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698