1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/auto_reset.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/json/json_reader.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/values.h"
10 #include "chrome/browser/history/download_row.h"
11 #include "chrome/browser/profiles/profile.h"
12 #include "chrome/browser/ui/browser.h"
13 #include "chrome/browser/ui/webui/downloads_dom_handler.h"
14 #include "chrome/common/pref_names.h"
15 #include "chrome/test/base/in_process_browser_test.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "content/public/browser/web_contents.h"
21 // Reads |right_json| into a ListValue |left_list|; returns true if all
22 // key-value pairs in in all dictionaries in |right_list| are also in the
23 // corresponding dictionary in |left_list|. Ignores keys in dictionaries in
24 // |left_list| that are not in the corresponding dictionary in |right_list|.
25 bool ListMatches(base::ListValue
* left_list
, const std::string
& right_json
) {
26 scoped_ptr
<base::Value
> right_value(base::JSONReader::Read(right_json
));
27 base::ListValue
* right_list
= NULL
;
28 CHECK(right_value
->GetAsList(&right_list
));
29 for (size_t i
= 0; i
< left_list
->GetSize(); ++i
) {
30 base::DictionaryValue
* left_dict
= NULL
;
31 base::DictionaryValue
* right_dict
= NULL
;
32 CHECK(left_list
->GetDictionary(i
, &left_dict
));
33 CHECK(right_list
->GetDictionary(i
, &right_dict
));
34 for (base::DictionaryValue::Iterator
iter(*right_dict
);
35 !iter
.IsAtEnd(); iter
.Advance()) {
36 base::Value
* left_value
= NULL
;
37 if (left_dict
->HasKey(iter
.key()) &&
38 left_dict
->Get(iter
.key(), &left_value
) &&
39 !iter
.value().Equals(left_value
)) {
40 LOG(WARNING
) << iter
.key();
48 // A |DownloadsDOMHandler| that doesn't use a real WebUI object, but is real in
49 // all other respects.
50 class MockDownloadsDOMHandler
: public DownloadsDOMHandler
{
52 explicit MockDownloadsDOMHandler(content::DownloadManager
* dlm
)
53 : DownloadsDOMHandler(dlm
),
55 waiting_updated_(false) {
57 virtual ~MockDownloadsDOMHandler() {}
59 base::ListValue
* downloads_list() { return downloads_list_
.get(); }
60 base::ListValue
* download_updated() { return download_updated_
.get(); }
62 void WaitForDownloadsList() {
63 if (downloads_list_
.get())
65 base::AutoReset
<bool> reset_waiting(&waiting_list_
, true);
66 content::RunMessageLoop();
69 void WaitForDownloadUpdated() {
70 if (download_updated_
.get())
72 base::AutoReset
<bool> reset_waiting(&waiting_updated_
, true);
73 content::RunMessageLoop();
76 void ForceSendCurrentDownloads() {
77 ScheduleSendCurrentDownloads();
80 void reset_downloads_list() { downloads_list_
.reset(); }
81 void reset_download_updated() { download_updated_
.reset(); }
84 virtual content::WebContents
* GetWebUIWebContents() OVERRIDE
{
88 virtual void CallDownloadsList(const base::ListValue
& downloads
) OVERRIDE
{
89 downloads_list_
.reset(downloads
.DeepCopy());
91 content::BrowserThread::PostTask(content::BrowserThread::UI
,
93 base::MessageLoop::QuitClosure());
97 virtual void CallDownloadUpdated(const base::ListValue
& download
) OVERRIDE
{
98 download_updated_
.reset(download
.DeepCopy());
99 if (waiting_updated_
) {
100 content::BrowserThread::PostTask(content::BrowserThread::UI
,
102 base::MessageLoop::QuitClosure());
107 scoped_ptr
<base::ListValue
> downloads_list_
;
108 scoped_ptr
<base::ListValue
> download_updated_
;
110 bool waiting_updated_
;
112 DISALLOW_COPY_AND_ASSIGN(MockDownloadsDOMHandler
);
117 class DownloadsDOMHandlerTest
: public InProcessBrowserTest
{
119 DownloadsDOMHandlerTest() {}
121 virtual ~DownloadsDOMHandlerTest() {}
123 virtual void SetUpOnMainThread() OVERRIDE
{
124 mock_handler_
.reset(new MockDownloadsDOMHandler(download_manager()));
125 CHECK(downloads_directory_
.CreateUniqueTempDir());
126 browser()->profile()->GetPrefs()->SetFilePath(
127 prefs::kDownloadDefaultDirectory
,
128 downloads_directory_
.path());
129 CHECK(test_server()->Start());
132 content::DownloadManager
* download_manager() {
133 return content::BrowserContext::GetDownloadManager(browser()->profile());
136 void DownloadAnItem() {
137 GURL url
= test_server()->GetURL("files/downloads/image.jpg");
138 std::vector
<GURL
> url_chain
;
139 url_chain
.push_back(url
);
140 base::Time
current(base::Time::Now());
141 download_manager()->CreateDownloadItem(
143 base::FilePath(FILE_PATH_LITERAL("/path/to/file")),
144 base::FilePath(FILE_PATH_LITERAL("/path/to/file")),
153 content::DownloadItem::COMPLETE
,
154 content::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS
,
155 content::DOWNLOAD_INTERRUPT_REASON_NONE
,
158 mock_handler_
->WaitForDownloadsList();
159 ASSERT_EQ(1, static_cast<int>(mock_handler_
->downloads_list()->GetSize()));
160 EXPECT_TRUE(ListMatches(
161 mock_handler_
->downloads_list(),
162 "[{\"file_externally_removed\": false,"
163 " \"file_name\": \"file\","
166 " \"since_string\": \"Today\","
167 " \"state\": \"COMPLETE\","
168 " \"total\": 128}]"));
172 scoped_ptr
<MockDownloadsDOMHandler
> mock_handler_
;
175 base::ScopedTempDir downloads_directory_
;
177 DISALLOW_COPY_AND_ASSIGN(DownloadsDOMHandlerTest
);
180 // Tests removing all items, both when prohibited and when allowed.
181 IN_PROC_BROWSER_TEST_F(DownloadsDOMHandlerTest
, RemoveAll
) {
184 mock_handler_
->reset_downloads_list();
185 browser()->profile()->GetPrefs()->SetBoolean(
186 prefs::kAllowDeletingBrowserHistory
, false);
187 mock_handler_
->HandleClearAll(NULL
);
188 mock_handler_
->WaitForDownloadsList();
189 ASSERT_EQ(1, static_cast<int>(mock_handler_
->downloads_list()->GetSize()));
191 mock_handler_
->reset_downloads_list();
192 browser()->profile()->GetPrefs()->SetBoolean(
193 prefs::kAllowDeletingBrowserHistory
, true);
194 mock_handler_
->HandleClearAll(NULL
);
195 mock_handler_
->WaitForDownloadsList();
196 EXPECT_EQ(0, static_cast<int>(mock_handler_
->downloads_list()->GetSize()));
199 // Tests removing one item, both when prohibited and when allowed.
200 IN_PROC_BROWSER_TEST_F(DownloadsDOMHandlerTest
, RemoveOneItem
) {
202 base::ListValue item
;
203 item
.AppendInteger(1);
205 mock_handler_
->reset_downloads_list();
206 browser()->profile()->GetPrefs()->SetBoolean(
207 prefs::kAllowDeletingBrowserHistory
, false);
208 mock_handler_
->HandleRemove(&item
);
209 // Removing an item only sends the new download list if anything was actually
210 // removed, so force it.
211 mock_handler_
->ForceSendCurrentDownloads();
212 mock_handler_
->WaitForDownloadsList();
213 ASSERT_EQ(1, static_cast<int>(mock_handler_
->downloads_list()->GetSize()));
215 mock_handler_
->reset_downloads_list();
216 browser()->profile()->GetPrefs()->SetBoolean(
217 prefs::kAllowDeletingBrowserHistory
, true);
218 mock_handler_
->HandleRemove(&item
);
219 mock_handler_
->WaitForDownloadsList();
220 EXPECT_EQ(0, static_cast<int>(mock_handler_
->downloads_list()->GetSize()));
223 // Tests that DownloadsDOMHandler detects new downloads and relays them to the
225 // crbug.com/159390: This test fails when daylight savings time ends.
226 IN_PROC_BROWSER_TEST_F(DownloadsDOMHandlerTest
, DownloadsRelayed
) {
229 mock_handler_
->WaitForDownloadUpdated();
230 ASSERT_EQ(1, static_cast<int>(mock_handler_
->download_updated()->GetSize()));
231 EXPECT_TRUE(ListMatches(
232 mock_handler_
->download_updated(),
233 "[{\"file_externally_removed\": true,"
236 mock_handler_
->reset_downloads_list();
237 browser()->profile()->GetPrefs()->SetBoolean(
238 prefs::kAllowDeletingBrowserHistory
, true);
239 mock_handler_
->HandleClearAll(NULL
);
240 mock_handler_
->WaitForDownloadsList();
241 EXPECT_EQ(0, static_cast<int>(mock_handler_
->downloads_list()->GetSize()));
245 // TODO(benjhayden): Test the extension downloads filter for both
246 // mock_handler_.downloads_list() and mock_handler_.download_updated().
248 // TODO(benjhayden): Test incognito, both downloads_list() and that on-record
249 // calls can't access off-record items.
251 // TODO(benjhayden): Test that bad download ids incoming from the javascript are
252 // dropped on the floor.
254 // TODO(benjhayden): Test that IsTemporary() downloads are not shown.
256 // TODO(benjhayden): Test that RemoveObserver is called on all download items,
257 // including items that crossed IsTemporary() and back.