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

Side by Side Diff: chrome/browser/download/download_browsertest.cc

Issue 7796014: Make cancel remove cancelled download from active queues at time of cancel. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Final Cancel arg fix. Created 9 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "base/file_path.h" 5 #include "base/file_path.h"
6 #include "base/file_util.h" 6 #include "base/file_util.h"
7 #include "base/memory/ref_counted.h" 7 #include "base/memory/ref_counted.h"
8 #include "base/path_service.h" 8 #include "base/path_service.h"
9 #include "base/scoped_temp_dir.h" 9 #include "base/scoped_temp_dir.h"
10 #include "base/stl_util.h" 10 #include "base/stl_util.h"
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
51 const char kGoodCrxId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf"; 51 const char kGoodCrxId[] = "ldnnhddmnhbkjipkidpdiheffobcpfmf";
52 const FilePath kGoodCrxPath(FILE_PATH_LITERAL("extensions/good.crx")); 52 const FilePath kGoodCrxPath(FILE_PATH_LITERAL("extensions/good.crx"));
53 53
54 const char kLargeThemeCrxId[] = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf"; 54 const char kLargeThemeCrxId[] = "pjpgmfcmabopnnfonnhmdjglfpjjfkbf";
55 const FilePath kLargeThemePath(FILE_PATH_LITERAL("extensions/theme2.crx")); 55 const FilePath kLargeThemePath(FILE_PATH_LITERAL("extensions/theme2.crx"));
56 56
57 // Action a test should take if a dangerous download is encountered. 57 // Action a test should take if a dangerous download is encountered.
58 enum DangerousDownloadAction { 58 enum DangerousDownloadAction {
59 ON_DANGEROUS_DOWNLOAD_ACCEPT, // Accept the download 59 ON_DANGEROUS_DOWNLOAD_ACCEPT, // Accept the download
60 ON_DANGEROUS_DOWNLOAD_DENY, // Deny the download 60 ON_DANGEROUS_DOWNLOAD_DENY, // Deny the download
61 ON_DANGEROUS_DOWNLOAD_IGNORE, // Don't do anything; calling code will handle.
61 ON_DANGEROUS_DOWNLOAD_FAIL // Fail if a dangerous download is seen 62 ON_DANGEROUS_DOWNLOAD_FAIL // Fail if a dangerous download is seen
62 }; 63 };
63 64
64 // Fake user click on "Accept". 65 // Fake user click on "Accept".
65 void AcceptDangerousDownload(scoped_refptr<DownloadManager> download_manager, 66 void AcceptDangerousDownload(scoped_refptr<DownloadManager> download_manager,
66 int32 download_id) { 67 int32 download_id) {
67 DownloadItem* download = download_manager->GetDownloadItem(download_id); 68 DownloadItem* download = download_manager->GetDownloadItem(download_id);
68 download->DangerousDownloadValidated(); 69 download->DangerousDownloadValidated();
69 } 70 }
70 71
71 // Fake user click on "Deny". 72 // Fake user click on "Deny".
72 void DenyDangerousDownload(scoped_refptr<DownloadManager> download_manager, 73 void DenyDangerousDownload(scoped_refptr<DownloadManager> download_manager,
73 int32 download_id) { 74 int32 download_id) {
74 DownloadItem* download = download_manager->GetDownloadItem(download_id); 75 DownloadItem* download = download_manager->GetDownloadItem(download_id);
75 ASSERT_TRUE(download->IsPartialDownload()); 76 ASSERT_TRUE(download->IsPartialDownload());
76 download->Cancel(true); 77 download->Cancel();
77 download->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD); 78 download->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
78 } 79 }
79 80
80 // Construction of this class defines a system state, based on some number 81 // Construction of this class defines a system state, based on some number
81 // of downloads being seen in a particular state + other events that 82 // of downloads being seen in a particular state + other events that
82 // may occur in the download system. That state will be recorded if it 83 // may occur in the download system. That state will be recorded if it
83 // occurs at any point after construction. When that state occurs, the class 84 // occurs at any point after construction. When that state occurs, the class
84 // is considered finished. Callers may either probe for the finished state, or 85 // is considered finished. Callers may either probe for the finished state, or
85 // wait on it. 86 // wait on it.
86 // 87 //
87 // TODO(rdsmith): Detect manager going down, remove pointer to 88 // TODO(rdsmith): Detect manager going down, remove pointer to
88 // DownloadManager, transition to finished. (For right now we 89 // DownloadManager, transition to finished. (For right now we
89 // just use a scoped_refptr<> to keep it around, but that may cause 90 // just use a scoped_refptr<> to keep it around, but that may cause
90 // timeouts on waiting if a DownloadManager::Shutdown() occurs which 91 // timeouts on waiting if a DownloadManager::Shutdown() occurs which
91 // cancels our in-progress downloads.) 92 // cancels our in-progress downloads.)
92 class DownloadsObserver : public DownloadManager::Observer, 93 class DownloadsObserver : public DownloadManager::Observer,
93 public DownloadItem::Observer { 94 public DownloadItem::Observer {
94 public: 95 public:
96 typedef std::set<DownloadItem::DownloadState> StateSet;
97
95 // Create an object that will be considered finished when |wait_count| 98 // Create an object that will be considered finished when |wait_count|
96 // download items have entered state |download_finished_state|. 99 // download items have entered any states in |download_finished_states|.
97 // If |finish_on_select_file| is true, the object will also be 100 // If |finish_on_select_file| is true, the object will also be
98 // considered finished if the DownloadManager raises a 101 // considered finished if the DownloadManager raises a
99 // SelectFileDialogDisplayed() notification. 102 // SelectFileDialogDisplayed() notification.
100 103
101 // TODO(rdsmith): Consider rewriting the interface to take a list of events 104 // TODO(rdsmith): Consider rewriting the interface to take a list of events
102 // to treat as completion events. 105 // to treat as completion events.
103 DownloadsObserver(DownloadManager* download_manager, 106 DownloadsObserver(DownloadManager* download_manager,
104 size_t wait_count, 107 size_t wait_count,
105 DownloadItem::DownloadState download_finished_state, 108 StateSet download_finished_states,
106 bool finish_on_select_file, 109 bool finish_on_select_file,
107 DangerousDownloadAction dangerous_download_action) 110 DangerousDownloadAction dangerous_download_action)
108 : download_manager_(download_manager), 111 : download_manager_(download_manager),
109 wait_count_(wait_count), 112 wait_count_(wait_count),
110 finished_downloads_at_construction_(0), 113 finished_downloads_at_construction_(0),
111 waiting_(false), 114 waiting_(false),
112 download_finished_state_(download_finished_state), 115 download_finished_states_(download_finished_states),
113 finish_on_select_file_(finish_on_select_file), 116 finish_on_select_file_(finish_on_select_file),
114 select_file_dialog_seen_(false), 117 select_file_dialog_seen_(false),
115 dangerous_download_action_(dangerous_download_action) { 118 dangerous_download_action_(dangerous_download_action) {
116 download_manager_->AddObserver(this); // Will call initial ModelChanged(). 119 download_manager_->AddObserver(this); // Will call initial ModelChanged().
117 finished_downloads_at_construction_ = finished_downloads_.size(); 120 finished_downloads_at_construction_ = finished_downloads_.size();
118 EXPECT_NE(DownloadItem::REMOVING, download_finished_state) 121 EXPECT_TRUE(download_finished_states.find(DownloadItem::REMOVING) ==
122 download_finished_states.end())
119 << "Waiting for REMOVING is not supported. Try COMPLETE."; 123 << "Waiting for REMOVING is not supported. Try COMPLETE.";
120 } 124 }
121 125
122 ~DownloadsObserver() { 126 ~DownloadsObserver() {
123 std::set<DownloadItem*>::iterator it = downloads_observed_.begin(); 127 std::set<DownloadItem*>::iterator it = downloads_observed_.begin();
124 for (; it != downloads_observed_.end(); ++it) 128 for (; it != downloads_observed_.end(); ++it)
125 (*it)->RemoveObserver(this); 129 (*it)->RemoveObserver(this);
126 130
127 download_manager_->RemoveObserver(this); 131 download_manager_->RemoveObserver(this);
128 } 132 }
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 NewRunnableFunction( 191 NewRunnableFunction(
188 &DenyDangerousDownload, 192 &DenyDangerousDownload,
189 download_manager_, 193 download_manager_,
190 download->id())); 194 download->id()));
191 break; 195 break;
192 196
193 case ON_DANGEROUS_DOWNLOAD_FAIL: 197 case ON_DANGEROUS_DOWNLOAD_FAIL:
194 ADD_FAILURE() << "Unexpected dangerous download item."; 198 ADD_FAILURE() << "Unexpected dangerous download item.";
195 break; 199 break;
196 200
201 case ON_DANGEROUS_DOWNLOAD_IGNORE:
202 break;
203
197 default: 204 default:
198 NOTREACHED(); 205 NOTREACHED();
199 } 206 }
200 } 207 }
201 208
202 if (download->state() == download_finished_state_) { 209 if (download_finished_states_.find(download->state()) !=
210 download_finished_states_.end()) {
203 DownloadInFinalState(download); 211 DownloadInFinalState(download);
204 } 212 }
205 } 213 }
206 214
207 virtual void OnDownloadOpened(DownloadItem* download) {} 215 virtual void OnDownloadOpened(DownloadItem* download) {}
208 216
209 // DownloadManager::Observer 217 // DownloadManager::Observer
210 virtual void ModelChanged() { 218 virtual void ModelChanged() {
211 // Regenerate DownloadItem observers. If there are any download items 219 // Regenerate DownloadItem observers. If there are any download items
212 // in our final state, note them in |finished_downloads_| 220 // in our final state, note them in |finished_downloads_|
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 // construction and return from wait. But some downloads may be in our 303 // construction and return from wait. But some downloads may be in our
296 // final state (and thus be entered into |finished_downloads_|) when we 304 // final state (and thus be entered into |finished_downloads_|) when we
297 // construct this class. We don't want to count those in our transition 305 // construct this class. We don't want to count those in our transition
298 // to finished. 306 // to finished.
299 int finished_downloads_at_construction_; 307 int finished_downloads_at_construction_;
300 308
301 // Whether an internal message loop has been started and must be quit upon 309 // Whether an internal message loop has been started and must be quit upon
302 // all downloads completing. 310 // all downloads completing.
303 bool waiting_; 311 bool waiting_;
304 312
305 // The state on which to consider the DownloadItem finished. 313 // The states on which to consider the DownloadItem finished.
306 DownloadItem::DownloadState download_finished_state_; 314 StateSet download_finished_states_;
307 315
308 // True if we should transition the DownloadsObserver to finished if 316 // True if we should transition the DownloadsObserver to finished if
309 // the select file dialog comes up. 317 // the select file dialog comes up.
310 bool finish_on_select_file_; 318 bool finish_on_select_file_;
311 319
312 // True if we've seen the select file dialog. 320 // True if we've seen the select file dialog.
313 bool select_file_dialog_seen_; 321 bool select_file_dialog_seen_;
314 322
315 // Action to take if a dangerous download is encountered. 323 // Action to take if a dangerous download is encountered.
316 DangerousDownloadAction dangerous_download_action_; 324 DangerousDownloadAction dangerous_download_action_;
(...skipping 298 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 (*it)->TestMockDownloadOpen(); 623 (*it)->TestMockDownloadOpen();
616 } 624 }
617 } 625 }
618 626
619 private: 627 private:
620 DownloadManager* download_manager_; 628 DownloadManager* download_manager_;
621 629
622 DISALLOW_COPY_AND_ASSIGN(MockDownloadOpeningObserver); 630 DISALLOW_COPY_AND_ASSIGN(MockDownloadOpeningObserver);
623 }; 631 };
624 632
633 static const DownloadItem::DownloadState kTerminalStates[] = {
634 DownloadItem::CANCELLED,
635 DownloadItem::INTERRUPTED,
636 DownloadItem::COMPLETE,
637 };
638
639 static const DownloadItem::DownloadState kInProgressStates[] = {
640 DownloadItem::IN_PROGRESS,
641 };
642
643 // Not in anonymous namespace so that friend class from DownloadManager
644 // can target it.
625 class DownloadTest : public InProcessBrowserTest { 645 class DownloadTest : public InProcessBrowserTest {
626 public: 646 public:
627 enum SelectExpectation { 647 enum SelectExpectation {
628 EXPECT_NO_SELECT_DIALOG = -1, 648 EXPECT_NO_SELECT_DIALOG = -1,
629 EXPECT_NOTHING, 649 EXPECT_NOTHING,
630 EXPECT_SELECT_DIALOG 650 EXPECT_SELECT_DIALOG
631 }; 651 };
632 652
633 DownloadTest() { 653 DownloadTest() {
634 EnableDOMAutomation(); 654 EnableDOMAutomation();
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 if (!downloads_directory_.CreateUniqueTempDir()) 711 if (!downloads_directory_.CreateUniqueTempDir())
692 return false; 712 return false;
693 713
694 browser->profile()->GetPrefs()->SetFilePath( 714 browser->profile()->GetPrefs()->SetFilePath(
695 prefs::kDownloadDefaultDirectory, 715 prefs::kDownloadDefaultDirectory,
696 downloads_directory_.path()); 716 downloads_directory_.path());
697 717
698 return true; 718 return true;
699 } 719 }
700 720
721 // For tests that want to test system reaction to files
722 // going away underneath them.
723 void DeleteDownloadsDirectory() {
724 EXPECT_TRUE(downloads_directory_.Delete());
725 }
726
701 DownloadPrefs* GetDownloadPrefs(Browser* browser) { 727 DownloadPrefs* GetDownloadPrefs(Browser* browser) {
702 return DownloadPrefs::FromDownloadManager( 728 return DownloadPrefs::FromDownloadManager(
703 browser->profile()->GetDownloadManager()); 729 browser->profile()->GetDownloadManager());
704 } 730 }
705 731
706 FilePath GetDownloadDirectory(Browser* browser) { 732 FilePath GetDownloadDirectory(Browser* browser) {
707 return GetDownloadPrefs(browser)->download_path(); 733 return GetDownloadPrefs(browser)->download_path();
708 } 734 }
709 735
710 // Create a DownloadsObserver that will wait for the 736 // Create a DownloadsObserver that will wait for the
711 // specified number of downloads to finish. 737 // specified number of downloads to finish.
712 DownloadsObserver* CreateWaiter(Browser* browser, int num_downloads) { 738 DownloadsObserver* CreateWaiter(Browser* browser, int num_downloads) {
713 DownloadManager* download_manager = 739 DownloadManager* download_manager =
714 browser->profile()->GetDownloadManager(); 740 browser->profile()->GetDownloadManager();
715 return new DownloadsObserver( 741 return new DownloadsObserver(
716 download_manager, num_downloads, 742 download_manager, num_downloads,
717 DownloadItem::COMPLETE, // Really done 743 DownloadsObserver::StateSet(
744 kTerminalStates, kTerminalStates + arraysize(kTerminalStates)),
718 true, // Bail on select file 745 true, // Bail on select file
719 ON_DANGEROUS_DOWNLOAD_FAIL); 746 ON_DANGEROUS_DOWNLOAD_FAIL);
720 } 747 }
721 748
722 // Create a DownloadsObserver that will wait for the 749 // Create a DownloadsObserver that will wait for the
750 // specified number of downloads to finish, and is
751 // ok with dangerous downloads. Note that use of this
752 // waiter is conditional on accepting the dangerous download.
753 DownloadsObserver* CreateDangerousWaiter(
754 Browser* browser, int num_downloads) {
755 DownloadManager* download_manager =
756 browser->profile()->GetDownloadManager();
757 return new DownloadsObserver(
758 download_manager, num_downloads,
759 DownloadsObserver::StateSet(
760 kTerminalStates, kTerminalStates + arraysize(kTerminalStates)),
761 true, // Bail on select file
762 ON_DANGEROUS_DOWNLOAD_IGNORE);
763 }
764
765 // Create a DownloadsObserver that will wait for the
723 // specified number of downloads to start. 766 // specified number of downloads to start.
724 DownloadsObserver* CreateInProgressWaiter(Browser* browser, 767 DownloadsObserver* CreateInProgressWaiter(Browser* browser,
725 int num_downloads) { 768 int num_downloads) {
726 DownloadManager* download_manager = 769 DownloadManager* download_manager =
727 browser->profile()->GetDownloadManager(); 770 browser->profile()->GetDownloadManager();
728 return new DownloadsObserver( 771 return new DownloadsObserver(
729 download_manager, num_downloads, 772 download_manager, num_downloads,
730 DownloadItem::IN_PROGRESS, // Has started 773 DownloadsObserver::StateSet(
774 kInProgressStates,
775 kInProgressStates + arraysize(kInProgressStates)),
731 true, // Bail on select file 776 true, // Bail on select file
732 ON_DANGEROUS_DOWNLOAD_FAIL); 777 ON_DANGEROUS_DOWNLOAD_IGNORE);
733 } 778 }
734 779
735 // Create a DownloadsObserver that will wait for the 780 // Create a DownloadsObserver that will wait for the
736 // specified number of downloads to finish, or for 781 // specified number of downloads to finish, or for
737 // a dangerous download warning to be shown. 782 // a dangerous download warning to be shown.
738 DownloadsObserver* DangerousInstallWaiter( 783 DownloadsObserver* DangerousInstallWaiter(
739 Browser* browser, 784 Browser* browser,
740 int num_downloads, 785 int num_downloads,
741 DownloadItem::DownloadState final_state, 786 DownloadItem::DownloadState final_state,
742 DangerousDownloadAction dangerous_download_action) { 787 DangerousDownloadAction dangerous_download_action) {
788 DownloadsObserver::StateSet states;
789 states.insert(final_state);
743 DownloadManager* download_manager = 790 DownloadManager* download_manager =
744 browser->profile()->GetDownloadManager(); 791 browser->profile()->GetDownloadManager();
745 return new DownloadsObserver( 792 return new DownloadsObserver(
746 download_manager, num_downloads, 793 download_manager, num_downloads,
747 final_state, 794 states,
748 true, // Bail on select file 795 true, // Bail on select file
749 dangerous_download_action); 796 dangerous_download_action);
750 } 797 }
751 798
752 // Download |url|, then wait for the download to finish. 799 // Download |url|, then wait for the download to finish.
753 // |disposition| indicates where the navigation occurs (current tab, new 800 // |disposition| indicates where the navigation occurs (current tab, new
754 // foreground tab, etc). 801 // foreground tab, etc).
755 // |expectation| indicates whether or not a Select File dialog should be 802 // |expectation| indicates whether or not a Select File dialog should be
756 // open when the download is finished, or if we don't care. 803 // open when the download is finished, or if we don't care.
757 // If the dialog appears, the routine exits. The only effect |expectation| 804 // If the dialog appears, the routine exits. The only effect |expectation|
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
892 if (!downloaded_path_exists) 939 if (!downloaded_path_exists)
893 return false; 940 return false;
894 941
895 // Delete the file we just downloaded. 942 // Delete the file we just downloaded.
896 EXPECT_TRUE(file_util::DieFileDie(download_path, true)); 943 EXPECT_TRUE(file_util::DieFileDie(download_path, true));
897 EXPECT_FALSE(file_util::PathExists(download_path)); 944 EXPECT_FALSE(file_util::PathExists(download_path));
898 945
899 return true; 946 return true;
900 } 947 }
901 948
902 void GetDownloads(Browser* browser, std::vector<DownloadItem*>* downloads) { 949 void GetPersistentDownloads(Browser* browser,
950 std::vector<DownloadItem*>* downloads) {
951 DCHECK(downloads);
952 downloads->clear();
953 DownloadManager* manager = browser->profile()->GetDownloadManager();
954 manager->SearchDownloads(string16(), downloads);
955 }
956
957 void GetInProgressDownloads(Browser* browser,
958 std::vector<DownloadItem*>* downloads) {
959 downloads->clear();
903 DCHECK(downloads); 960 DCHECK(downloads);
904 DownloadManager* manager = browser->profile()->GetDownloadManager(); 961 DownloadManager* manager = browser->profile()->GetDownloadManager();
905 manager->SearchDownloads(string16(), downloads); 962 manager->GetInProgressDownloads(downloads);
906 } 963 }
907 964
908 // Check that the download UI (shelf on non-chromeos or panel on chromeos) 965 // Check that the download UI (shelf on non-chromeos or panel on chromeos)
909 // is visible or not as expected. Additionally, check that the filename 966 // is visible or not as expected. Additionally, check that the filename
910 // is present in the UI (currently only on chromeos). 967 // is present in the UI (currently only on chromeos).
911 void CheckDownloadUI(Browser* browser, bool expected_non_cros, 968 void CheckDownloadUI(Browser* browser, bool expected_non_cros,
912 bool expected_cros, const FilePath& filename) { 969 bool expected_cros, const FilePath& filename) {
913 #if defined(OS_CHROMEOS) 970 #if defined(OS_CHROMEOS)
914 Browser* popup = ActiveDownloadsUI::GetPopup(); 971 Browser* popup = ActiveDownloadsUI::GetPopup();
915 EXPECT_EQ(expected_cros, popup != NULL); 972 EXPECT_EQ(expected_cros, popup != NULL);
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
1020 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 1077 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1021 1078
1022 NullSelectFile(browser()); 1079 NullSelectFile(browser());
1023 1080
1024 // Download the file and wait. We expect the Select File dialog to appear 1081 // Download the file and wait. We expect the Select File dialog to appear
1025 // due to the MIME type, but we still wait until the download completes. 1082 // due to the MIME type, but we still wait until the download completes.
1026 scoped_ptr<DownloadsObserver> observer( 1083 scoped_ptr<DownloadsObserver> observer(
1027 new DownloadsObserver( 1084 new DownloadsObserver(
1028 browser()->profile()->GetDownloadManager(), 1085 browser()->profile()->GetDownloadManager(),
1029 1, 1086 1,
1030 DownloadItem::COMPLETE, // Really done 1087 DownloadsObserver::StateSet(
1088 kTerminalStates, kTerminalStates + arraysize(kTerminalStates)),
1031 false, // Continue on select file. 1089 false, // Continue on select file.
1032 ON_DANGEROUS_DOWNLOAD_FAIL)); 1090 ON_DANGEROUS_DOWNLOAD_FAIL));
1033 ui_test_utils::NavigateToURLWithDisposition( 1091 ui_test_utils::NavigateToURLWithDisposition(
1034 browser(), url, CURRENT_TAB, 1092 browser(), url, CURRENT_TAB,
1035 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); 1093 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
1036 observer->WaitForFinished(); 1094 observer->WaitForFinished();
1037 EXPECT_TRUE(observer->select_file_dialog_seen()); 1095 EXPECT_TRUE(observer->select_file_dialog_seen());
1038 1096
1039 1097
1040 EXPECT_EQ(1, browser()->tab_count()); 1098 EXPECT_EQ(1, browser()->tab_count());
1041 CheckDownload(browser(), file, file); 1099 CheckDownload(browser(), file, file);
1042 CheckDownloadUI(browser(), true, true, file); 1100 CheckDownloadUI(browser(), true, true, file);
1043 } 1101 }
1044 1102
1103 // Put up a Select File dialog when the file is downloaded, due to
1104 // prompt_for_download==true argument to InitialSetup().
1105 // Confirm that we can cancel the download in that state.
1106 IN_PROC_BROWSER_TEST_F(DownloadTest, CancelFromFileSelection) {
1107 ASSERT_TRUE(InitialSetup(true));
1108 FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
1109 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1110
1111 // Download the file and wait. We expect the Select File dialog to appear.
1112 DownloadAndWait(browser(), url, EXPECT_SELECT_DIALOG);
1113
1114 std::vector<DownloadItem*> active_downloads, history_downloads;
1115 GetInProgressDownloads(browser(), &active_downloads);
1116 ASSERT_EQ(1u, active_downloads.size());
1117 EXPECT_EQ(DownloadItem::IN_PROGRESS, active_downloads[0]->state());
1118 GetPersistentDownloads(browser(), &history_downloads);
1119 EXPECT_EQ(0u, history_downloads.size());
1120
1121 // This should remove the download as it hasn't yet been entered into
1122 // the history.
1123 active_downloads[0]->Cancel();
1124
1125 GetInProgressDownloads(browser(), &active_downloads);
1126 EXPECT_EQ(0u, active_downloads.size());
1127 GetPersistentDownloads(browser(), &history_downloads);
1128 EXPECT_EQ(0u, history_downloads.size());
1129
1130 // Check state.
1131 EXPECT_EQ(1, browser()->tab_count());
1132 // Since we exited while the Select File dialog was visible, there should not
1133 // be anything in the download shelf and so it should not be visible.
1134 CheckDownloadUI(browser(), false, false, FilePath());
1135 }
1136
1137 // Put up a Select File dialog when the file is downloaded, due to
1138 // prompt_for_download==true argument to InitialSetup().
1139 // Confirm that we can remove the download in that state.
1140 IN_PROC_BROWSER_TEST_F(DownloadTest, RemoveFromFileSelection) {
1141 ASSERT_TRUE(InitialSetup(true));
1142 FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
1143 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1144
1145 // Download the file and wait. We expect the Select File dialog to appear.
1146 DownloadAndWait(browser(), url, EXPECT_SELECT_DIALOG);
1147
1148 std::vector<DownloadItem*> active_downloads, history_downloads;
1149 GetInProgressDownloads(browser(), &active_downloads);
1150 ASSERT_EQ(1u, active_downloads.size());
1151 EXPECT_EQ(DownloadItem::IN_PROGRESS, active_downloads[0]->state());
1152 GetPersistentDownloads(browser(), &history_downloads);
1153 EXPECT_EQ(0u, history_downloads.size());
1154
1155 // Confirm the file can be successfully removed from the select file
1156 // dialog blocked state.
1157 active_downloads[0]->Remove();
1158
1159 GetInProgressDownloads(browser(), &active_downloads);
1160 EXPECT_EQ(0u, active_downloads.size());
1161 GetPersistentDownloads(browser(), &history_downloads);
1162 EXPECT_EQ(0u, history_downloads.size());
1163
1164 EXPECT_EQ(1, browser()->tab_count());
1165 // Since we exited while the Select File dialog was visible, there should not
1166 // be anything in the download shelf and so it should not be visible.
1167 CheckDownloadUI(browser(), false, false, FilePath());
1168 }
1169
1170 // Put up a Select File dialog when the file is downloaded, due to
1171 // prompt_for_download==true argument to InitialSetup().
1172 // Confirm that an error coming in from the network works properly
1173 // when in that state.
1174 IN_PROC_BROWSER_TEST_F(DownloadTest, InterruptFromFileSelection) {
1175 ASSERT_TRUE(InitialSetup(true));
1176 GURL url(URLRequestSlowDownloadJob::kKnownSizeUrl);
1177
1178 // Download the file and wait. We expect the Select File dialog to appear.
1179 DownloadAndWait(browser(), url, EXPECT_SELECT_DIALOG);
1180
1181 std::vector<DownloadItem*> active_downloads, history_downloads;
1182 GetInProgressDownloads(browser(), &active_downloads);
1183 ASSERT_EQ(1u, active_downloads.size());
1184 EXPECT_EQ(DownloadItem::IN_PROGRESS, active_downloads[0]->state());
1185 GetPersistentDownloads(browser(), &history_downloads);
1186 EXPECT_EQ(0u, history_downloads.size());
1187
1188 // Complete the download with error.
1189 GURL error_url(URLRequestSlowDownloadJob::kErrorFinishDownloadUrl);
1190 ui_test_utils::NavigateToURL(browser(), error_url);
1191 MessageLoopForUI::current()->RunAllPending();
1192
1193 // Confirm that a download error before entry into history
1194 // deletes the download.
1195 GetInProgressDownloads(browser(), &active_downloads);
1196 EXPECT_EQ(0u, active_downloads.size());
1197 GetPersistentDownloads(browser(), &history_downloads);
1198 EXPECT_EQ(0u, history_downloads.size());
1199
1200 // Since we exited while the Select File dialog was visible, there should not
1201 // be anything in the download shelf and so it should not be visible.
1202 CheckDownloadUI(browser(), false, false, FilePath());
1203 }
1204
1045 // Access a file with a viewable mime-type, verify that a download 1205 // Access a file with a viewable mime-type, verify that a download
1046 // did not initiate. 1206 // did not initiate.
1047 IN_PROC_BROWSER_TEST_F(DownloadTest, NoDownload) { 1207 IN_PROC_BROWSER_TEST_F(DownloadTest, NoDownload) {
1048 ASSERT_TRUE(InitialSetup(false)); 1208 ASSERT_TRUE(InitialSetup(false));
1049 FilePath file(FILE_PATH_LITERAL("download-test2.html")); 1209 FilePath file(FILE_PATH_LITERAL("download-test2.html"));
1050 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 1210 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1051 FilePath file_path(DestinationFile(browser(), file)); 1211 FilePath file_path(DestinationFile(browser(), file));
1052 1212
1053 // Open a web page and wait. 1213 // Open a web page and wait.
1054 ui_test_utils::NavigateToURL(browser(), url); 1214 ui_test_utils::NavigateToURL(browser(), url);
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
1463 1623
1464 // Create a download, wait until it's started, and confirm 1624 // Create a download, wait until it's started, and confirm
1465 // we're in the expected state. 1625 // we're in the expected state.
1466 scoped_ptr<DownloadsObserver> observer( 1626 scoped_ptr<DownloadsObserver> observer(
1467 CreateInProgressWaiter(browser(), 1)); 1627 CreateInProgressWaiter(browser(), 1));
1468 ui_test_utils::NavigateToURL( 1628 ui_test_utils::NavigateToURL(
1469 browser(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl)); 1629 browser(), GURL(URLRequestSlowDownloadJob::kUnknownSizeUrl));
1470 observer->WaitForFinished(); 1630 observer->WaitForFinished();
1471 1631
1472 std::vector<DownloadItem*> downloads; 1632 std::vector<DownloadItem*> downloads;
1473 browser()->profile()->GetDownloadManager()->SearchDownloads( 1633 GetPersistentDownloads(browser(), &downloads);
1474 string16(), &downloads);
1475 ASSERT_EQ(1u, downloads.size()); 1634 ASSERT_EQ(1u, downloads.size());
1476 ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->state()); 1635 ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->state());
1477 CheckDownloadUI(browser(), true, true, FilePath()); 1636 CheckDownloadUI(browser(), true, true, FilePath());
1478 1637
1479 // Cancel the download and wait for download system quiesce. 1638 // Cancel the download and wait for download system quiesce.
1480 downloads[0]->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD); 1639 downloads[0]->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
1481 scoped_refptr<DownloadsFlushObserver> flush_observer( 1640 scoped_refptr<DownloadsFlushObserver> flush_observer(
1482 new DownloadsFlushObserver(browser()->profile()->GetDownloadManager())); 1641 new DownloadsFlushObserver(browser()->profile()->GetDownloadManager()));
1483 flush_observer->WaitForFlush(); 1642 flush_observer->WaitForFlush();
1484 1643
1485 // Get the important info from other threads and check it. 1644 // Get the important info from other threads and check it.
1486 scoped_refptr<CancelTestDataCollector> info(new CancelTestDataCollector()); 1645 scoped_refptr<CancelTestDataCollector> info(new CancelTestDataCollector());
1487 info->WaitForDataCollected(); 1646 info->WaitForDataCollected();
1488 EXPECT_EQ(0, info->rdh_pending_requests()); 1647 EXPECT_EQ(0, info->rdh_pending_requests());
1489 EXPECT_EQ(0, info->dfm_pending_downloads()); 1648 EXPECT_EQ(0, info->dfm_pending_downloads());
1490 1649
1491 // Using "DownloadItem::Remove" follows the discard dangerous download path, 1650 // Using "DownloadItem::Remove" follows the discard dangerous download path,
1492 // which completely removes the browser from the shelf and closes the shelf 1651 // which completely removes the browser from the shelf and closes the shelf
1493 // if it was there. Download panel stays open on ChromeOS. 1652 // if it was there. Download panel stays open on ChromeOS.
1494 CheckDownloadUI(browser(), false, true, FilePath()); 1653 CheckDownloadUI(browser(), false, true, FilePath());
1495 } 1654 }
1496 1655
1656 // Do a dangerous download and confirm that the download does
1657 // not complete until user accept, and that all states are
1658 // correct along the way.
1659 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadDangerous) {
1660 ASSERT_TRUE(InitialSetup(false));
1661 FilePath file(FILE_PATH_LITERAL("download-dangerous.jar"));
1662 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1663
1664 EXPECT_EQ(1, browser()->tab_count());
1665
1666 scoped_ptr<DownloadsObserver> observer(
1667 CreateInProgressWaiter(browser(), 1));
1668 ui_test_utils::NavigateToURL(browser(), url);
1669 observer->WaitForFinished();
1670
1671 // We should have one download, in history, and it should
1672 // still be dangerous.
1673 std::vector<DownloadItem*> downloads;
1674 GetPersistentDownloads(browser(), &downloads);
1675 ASSERT_EQ(1u, downloads.size());
1676 DownloadItem* download = downloads[0];
1677 EXPECT_EQ(DownloadItem::IN_PROGRESS, download->state());
1678 EXPECT_EQ(DownloadItem::DANGEROUS, download->safety_state());
1679 EXPECT_EQ(DownloadItem::DANGEROUS_FILE, download->GetDangerType());
1680 // In ChromeOS, popup will be up, but file name will be unrecognizable.
1681 CheckDownloadUI(browser(), true, true, FilePath());
1682
1683 // See if accepting completes the download and changes the safety
1684 // state.
1685 scoped_ptr<DownloadsObserver> completion_observer(
1686 CreateDangerousWaiter(browser(), 1));
1687 AcceptDangerousDownload(browser()->profile()->GetDownloadManager(),
1688 download->id());
1689 completion_observer->WaitForFinished();
1690
1691 GetPersistentDownloads(browser(), &downloads);
1692 ASSERT_EQ(1u, downloads.size());
1693 ASSERT_EQ(downloads[0], download);
1694 EXPECT_EQ(DownloadItem::COMPLETE, download->state());
1695 EXPECT_EQ(DownloadItem::DANGEROUS_BUT_VALIDATED, download->safety_state());
1696 CheckDownloadUI(browser(), true, true, file);
1697 }
1698
1699 // Confirm that a dangerous download that gets a file error before
1700 // completion ends in the right state (currently cancelled because file
1701 // errors are non-resumable). Note that this is really testing
1702 // to make sure errors from the final rename are propagated properly.
1703 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadDangerousFileError) {
1704 ASSERT_TRUE(InitialSetup(false));
1705 FilePath file(FILE_PATH_LITERAL("download-dangerous.jar"));
1706 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1707
1708 EXPECT_EQ(1, browser()->tab_count());
1709
1710 scoped_ptr<DownloadsObserver> observer(
1711 CreateInProgressWaiter(browser(), 1));
1712 ui_test_utils::NavigateToURL(browser(), url);
1713 observer->WaitForFinished();
1714
1715 // We should have one download, in history, and it should
1716 // still be dangerous.
1717 std::vector<DownloadItem*> downloads;
1718 GetPersistentDownloads(browser(), &downloads);
1719 ASSERT_EQ(1u, downloads.size());
1720 DownloadItem* download = downloads[0];
1721 EXPECT_EQ(DownloadItem::IN_PROGRESS, download->state());
1722 EXPECT_EQ(DownloadItem::DANGEROUS, download->safety_state());
1723 EXPECT_EQ(DownloadItem::DANGEROUS_FILE, download->GetDangerType());
1724 // In ChromeOS, popup will be up, but file name will be unrecognizable.
1725 CheckDownloadUI(browser(), true, true, FilePath());
1726
1727 // Accept it after nuking the directory into which it's being downloaded;
1728 // that should complete the download with an error.
1729 DeleteDownloadsDirectory();
1730 scoped_ptr<DownloadsObserver> completion_observer(
1731 CreateDangerousWaiter(browser(), 1));
1732 AcceptDangerousDownload(browser()->profile()->GetDownloadManager(),
1733 download->id());
1734 completion_observer->WaitForFinished();
1735
1736 GetPersistentDownloads(browser(), &downloads);
1737 ASSERT_EQ(1u, downloads.size());
1738 ASSERT_EQ(downloads[0], download);
1739 EXPECT_EQ(DownloadItem::INTERRUPTED, download->state());
1740 EXPECT_EQ(DownloadItem::DANGEROUS_BUT_VALIDATED, download->safety_state());
1741 // In ChromeOS, popup will still be up, but the file will have been
1742 // deleted.
1743 CheckDownloadUI(browser(), true, true, FilePath());
1744 }
1745
1746 // Confirm that declining a dangerous download erases it from living memory.
1747 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadDangerousDecline) {
1748 ASSERT_TRUE(InitialSetup(false));
1749 FilePath file(FILE_PATH_LITERAL("download-dangerous.jar"));
1750 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1751
1752 EXPECT_EQ(1, browser()->tab_count());
1753
1754 scoped_ptr<DownloadsObserver> observer(
1755 CreateInProgressWaiter(browser(), 1));
1756 ui_test_utils::NavigateToURL(browser(), url);
1757 observer->WaitForFinished();
1758
1759 // We should have one download, in history, and it should
1760 // still be dangerous.
1761 std::vector<DownloadItem*> downloads;
1762 GetPersistentDownloads(browser(), &downloads);
1763 ASSERT_EQ(1u, downloads.size());
1764 DownloadItem* download = downloads[0];
1765 EXPECT_EQ(DownloadItem::IN_PROGRESS, download->state());
1766 EXPECT_EQ(DownloadItem::DANGEROUS, download->safety_state());
1767 EXPECT_EQ(DownloadItem::DANGEROUS_FILE, download->GetDangerType());
1768 CheckDownloadUI(browser(), true, true, FilePath());
1769
1770 DenyDangerousDownload(browser()->profile()->GetDownloadManager(),
1771 download->id());
1772
1773 GetPersistentDownloads(browser(), &downloads);
1774 ASSERT_EQ(0u, downloads.size());
1775 CheckDownloadUI(browser(), false, true, FilePath());
1776 }
1777
1778 // Fail a download with a network error partway through, and make sure the
1779 // state is INTERRUPTED and the error is propagated.
1780 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadInterrupted) {
1781 ASSERT_TRUE(InitialSetup(false));
1782 GURL url(URLRequestSlowDownloadJob::kKnownSizeUrl);
1783
1784 scoped_ptr<DownloadsObserver> observer(
1785 CreateInProgressWaiter(browser(), 1));
1786 ui_test_utils::NavigateToURL(browser(), url);
1787 observer->WaitForFinished();
1788
1789 std::vector<DownloadItem*> downloads;
1790 GetPersistentDownloads(browser(), &downloads);
1791 ASSERT_EQ(1u, downloads.size());
1792 ASSERT_EQ(DownloadItem::IN_PROGRESS, downloads[0]->state());
1793 FilePath filename;
1794 net::FileURLToFilePath(url, &filename);
1795 CheckDownloadUI(browser(), true, true,
1796 download_util::GetCrDownloadPath(filename.BaseName()));
1797
1798 // Fail the download
1799 GURL error_url(URLRequestSlowDownloadJob::kErrorFinishDownloadUrl);
1800 ui_test_utils::NavigateToURL(browser(), error_url);
1801 MessageLoopForUI::current()->RunAllPending();
1802
1803 // Should still be visible, with INTERRUPTED state.
1804 GetPersistentDownloads(browser(), &downloads);
1805 ASSERT_EQ(1u, downloads.size());
1806 DownloadItem* download = downloads[0];
1807 ASSERT_EQ(DownloadItem::INTERRUPTED, download->state());
1808 // TODO(rdsmith): Confirm error provided by URLRequest is shown
1809 // in DownloadItem.
1810 CheckDownloadUI(browser(), true, true, FilePath());
1811
1812 // Confirm cancel does nothing.
1813 download->Cancel();
1814 MessageLoopForUI::current()->RunAllPending();
1815
1816 GetPersistentDownloads(browser(), &downloads);
1817 ASSERT_EQ(1u, downloads.size());
1818 ASSERT_EQ(download, downloads[0]);
1819 ASSERT_EQ(DownloadItem::INTERRUPTED, download->state());
1820 CheckDownloadUI(browser(), true, true, FilePath());
1821
1822 // Confirm remove gets rid of it.
1823 download->Remove();
1824 download = NULL;
1825 MessageLoopForUI::current()->RunAllPending();
1826
1827 GetPersistentDownloads(browser(), &downloads);
1828 ASSERT_EQ(0u, downloads.size());
1829 CheckDownloadUI(browser(), false, true, FilePath());
1830 }
1831
1497 // Confirm a download makes it into the history properly. 1832 // Confirm a download makes it into the history properly.
1498 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadHistoryCheck) { 1833 IN_PROC_BROWSER_TEST_F(DownloadTest, DownloadHistoryCheck) {
1499 ASSERT_TRUE(InitialSetup(false)); 1834 ASSERT_TRUE(InitialSetup(false));
1500 FilePath file(FILE_PATH_LITERAL("download-test1.lib")); 1835 FilePath file(FILE_PATH_LITERAL("download-test1.lib"));
1501 GURL url(URLRequestMockHTTPJob::GetMockUrl(file)); 1836 GURL url(URLRequestMockHTTPJob::GetMockUrl(file));
1502 FilePath origin_file(OriginFile(file)); 1837 FilePath origin_file(OriginFile(file));
1503 int64 origin_size; 1838 int64 origin_size;
1504 file_util::GetFileSize(origin_file, &origin_size); 1839 file_util::GetFileSize(origin_file, &origin_size);
1505 1840
1506 // Download the file and wait. We do not expect the Select File dialog. 1841 // Download the file and wait. We do not expect the Select File dialog.
1507 DownloadAndWait(browser(), url, EXPECT_NO_SELECT_DIALOG); 1842 DownloadAndWait(browser(), url, EXPECT_NO_SELECT_DIALOG);
1508 1843
1509 // Get details of what downloads have just happened. 1844 // Get details of what downloads have just happened.
1510 std::vector<DownloadItem*> downloads; 1845 std::vector<DownloadItem*> downloads;
1511 GetDownloads(browser(), &downloads); 1846 GetPersistentDownloads(browser(), &downloads);
1512 ASSERT_EQ(1u, downloads.size()); 1847 ASSERT_EQ(1u, downloads.size());
1513 int64 db_handle = downloads[0]->db_handle(); 1848 int64 db_handle = downloads[0]->db_handle();
1514 1849
1515 // Check state. 1850 // Check state.
1516 EXPECT_EQ(1, browser()->tab_count()); 1851 EXPECT_EQ(1, browser()->tab_count());
1517 CheckDownload(browser(), file, file); 1852 CheckDownload(browser(), file, file);
1518 CheckDownloadUI(browser(), true, true, file); 1853 CheckDownloadUI(browser(), true, true, file);
1519 1854
1520 // Check history results. 1855 // Check history results.
1521 DownloadsHistoryDataCollector history_collector( 1856 DownloadsHistoryDataCollector history_collector(
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
1615 GetDownloadPrefs(browser())->EnableAutoOpenBasedOnExtension(file)); 1950 GetDownloadPrefs(browser())->EnableAutoOpenBasedOnExtension(file));
1616 1951
1617 // Mock out external opening on all downloads until end of test. 1952 // Mock out external opening on all downloads until end of test.
1618 MockDownloadOpeningObserver observer( 1953 MockDownloadOpeningObserver observer(
1619 browser()->profile()->GetDownloadManager()); 1954 browser()->profile()->GetDownloadManager());
1620 1955
1621 DownloadAndWait(browser(), url, EXPECT_NO_SELECT_DIALOG); 1956 DownloadAndWait(browser(), url, EXPECT_NO_SELECT_DIALOG);
1622 1957
1623 // Find the download and confirm it was opened. 1958 // Find the download and confirm it was opened.
1624 std::vector<DownloadItem*> downloads; 1959 std::vector<DownloadItem*> downloads;
1625 browser()->profile()->GetDownloadManager()->SearchDownloads( 1960 GetPersistentDownloads(browser(), &downloads);
1626 string16(), &downloads);
1627 ASSERT_EQ(1u, downloads.size()); 1961 ASSERT_EQ(1u, downloads.size());
1628 EXPECT_EQ(DownloadItem::COMPLETE, downloads[0]->state()); 1962 EXPECT_EQ(DownloadItem::COMPLETE, downloads[0]->state());
1629 EXPECT_TRUE(downloads[0]->opened()); 1963 EXPECT_TRUE(downloads[0]->opened());
1630 1964
1631 // As long as we're here, confirmed everything else is good. 1965 // As long as we're here, confirmed everything else is good.
1632 EXPECT_EQ(1, browser()->tab_count()); 1966 EXPECT_EQ(1, browser()->tab_count());
1633 CheckDownload(browser(), file, file); 1967 CheckDownload(browser(), file, file);
1634 // Download shelf should close. Download panel stays open on ChromeOS. 1968 // Download shelf should close. Download panel stays open on ChromeOS.
1635 CheckDownloadUI(browser(), false, true, FilePath()); 1969 CheckDownloadUI(browser(), false, true, FilePath());
1636 } 1970 }
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
1768 EXPECT_EQ(1u, observer->NumDangerousDownloadsSeen()); 2102 EXPECT_EQ(1u, observer->NumDangerousDownloadsSeen());
1769 2103
1770 // Download shelf should close. Download panel stays open on ChromeOS. 2104 // Download shelf should close. Download panel stays open on ChromeOS.
1771 CheckDownloadUI(browser(), false, true, FilePath()); 2105 CheckDownloadUI(browser(), false, true, FilePath());
1772 2106
1773 // Check that the extension was installed. 2107 // Check that the extension was installed.
1774 ExtensionService* extension_service = 2108 ExtensionService* extension_service =
1775 browser()->profile()->GetExtensionService(); 2109 browser()->profile()->GetExtensionService();
1776 ASSERT_TRUE(extension_service->GetExtensionById(kLargeThemeCrxId, false)); 2110 ASSERT_TRUE(extension_service->GetExtensionById(kLargeThemeCrxId, false));
1777 } 2111 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698