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.
7 #include "base/rand_util.h"
8 #include "chrome/browser/webdata/autofill_table.h"
9 #include "chrome/browser/webdata/web_database.h"
10 #include "chrome/common/url_constants.h"
11 #include "chrome/common/chrome_constants.h"
12 #include "chrome_frame/test/mock_ie_event_sink_actions.h"
13 #include "chrome_frame/test/mock_ie_event_sink_test.h"
17 namespace chrome_frame_test
{
19 class DeleteBrowsingHistoryTest
20 : public MockIEEventSinkTest
,
21 public testing::Test
{
23 DeleteBrowsingHistoryTest() {}
25 virtual void SetUp() {
26 // We will use the OnAccLoad event to monitor page loads, so we ignore
28 ie_mock_
.ExpectAnyNavigations();
29 ie_mock2_
.ExpectAnyNavigations();
30 ie_mock3_
.ExpectAnyNavigations();
31 EXPECT_CALL(acc_observer_
, OnAccDocLoad(_
)).Times(testing::AnyNumber());
33 // Use a random image_path to ensure that a prior run does not
34 // interfere with our expectations about caching.
35 image_path_
= L
"/" + RandomChars(32);
38 "<meta http-equiv=\"x-ua-compatible\" content=\"chrome=1\" />"
41 "<form method=\"POST\" action=\"/form\">"
42 "<input title=\"username\" type=\"text\" name=\"username\" />"
43 "<input type=\"submit\" title=\"Submit\" name=\"Submit\" />"
45 "<img alt=\"Blank image.\" src=\"" + WideToASCII(image_path_
) + "\" />"
46 "This is some text.</body></html>";
50 std::wstring image_path_
;
53 testing::NiceMock
<MockAccEventObserver
> acc_observer_
;
54 MockWindowObserver delete_browsing_history_window_observer_mock_
;
55 MockObjectWatcherDelegate ie_process_exit_watcher_mock_
;
57 testing::StrictMock
<MockIEEventSink
> ie_mock2_
;
58 testing::StrictMock
<MockIEEventSink
> ie_mock3_
;
60 // Returns a string of |count| lowercase random characters.
61 static std::wstring
RandomChars(int count
) {
62 srand(static_cast<unsigned int>(time(NULL
)));
64 for (int i
= 0; i
< count
; ++i
)
65 str
+= L
'a' + base::RandInt(0, 25);
72 const wchar_t* kFormFieldName
= L
"username";
73 const wchar_t* kFormFieldValue
= L
"test_username";
75 const char* kHtmlHttpHeaders
=
77 "Connection: close\r\n"
78 "Content-Type: text/html\r\n";
79 const char* kFormResultHtml
=
80 "<html><head><meta http-equiv=\"x-ua-compatible\" content=\"chrome=1\" />"
81 "</head><body>Nice work.</body></html>";
82 const char* kBlankPngResponse
[] = {
84 "Connection: close\r\n"
85 "Content-Type: image/png\r\n"
86 "Cache-Control: max-age=3600, must-revalidate\r\n",
87 "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a\x00\x00\x00\x0d\x49\x48\x44\x52"
88 "\x00\x00\x00\x01\x00\x00\x00\x01\x01\x03\x00\x00\x00\x25\xdb\x56"
89 "\xca\x00\x00\x00\x03\x50\x4c\x54\x45\x00\x00\x00\xa7\x7a\x3d\xda"
90 "\x00\x00\x00\x01\x74\x52\x4e\x53\x00\x40\xe6\xd8\x66\x00\x00\x00"
91 "\x0a\x49\x44\x41\x54\x08\xd7\x63\x60\x00\x00\x00\x02\x00\x01\xe2"
92 "\x21\xbc\x33\x00\x00\x00\x00\x49\x45\x4e\x44\xae\x42\x60\x82"};
94 const size_t kBlankPngFileLength
= 95;
95 } // anonymous namespace
97 // Looks up |element_name| in the Chrome form data DB and ensures that the
98 // results match |matcher|.
99 ACTION_P2(ExpectFormValuesForElementNameMatch
, element_name
, matcher
) {
101 GetChromeFrameProfilePath(kIexploreProfileName
, &root_path
);
102 FilePath
profile_path(
103 root_path
.Append(L
"Default").Append(chrome::kWebDataFilename
));
105 WebDatabase web_database
;
106 sql::InitStatus init_status
= web_database
.Init(profile_path
);
107 EXPECT_EQ(sql::INIT_OK
, init_status
);
109 if (init_status
== sql::INIT_OK
) {
110 std::vector
<string16
> values
;
111 web_database
.GetAutofillTable()->GetFormValuesForElementName(
112 element_name
, L
"", &values
, 9999);
113 EXPECT_THAT(values
, matcher
);
117 // Launch |ie_mock| and navigate it to |url|.
118 ACTION_P2(LaunchThisIEAndNavigate
, ie_mock
, url
) {
119 EXPECT_HRESULT_SUCCEEDED(ie_mock
->event_sink()->LaunchIEAndNavigate(url
,
123 // Listens for OnAccLoad and OnLoad events for an IE instance and
124 // sends a single signal once both have been received.
126 // Allows tests to wait for both events to occur irrespective of their relative
128 class PageLoadHelper
{
130 explicit PageLoadHelper(testing::StrictMock
<MockIEEventSink
>* ie_mock
)
131 : received_acc_load_(false),
132 received_on_load_(false),
134 EXPECT_CALL(*ie_mock_
, OnLoad(_
, _
))
135 .Times(testing::AnyNumber())
136 .WillRepeatedly(testing::InvokeWithoutArgs(
137 this, &PageLoadHelper::HandleOnLoad
));
138 EXPECT_CALL(acc_observer_
, OnAccDocLoad(_
))
139 .Times(testing::AnyNumber())
140 .WillRepeatedly(testing::Invoke(this, &PageLoadHelper::HandleAccLoad
));
143 void HandleAccLoad(HWND hwnd
) {
144 ReconcileHwnds(hwnd
, &acc_loaded_hwnds_
, &on_loaded_hwnds_
);
147 void HandleOnLoad() {
148 HWND hwnd
= ie_mock_
->event_sink()->GetRendererWindow();
149 ReconcileHwnds(hwnd
, &on_loaded_hwnds_
, &acc_loaded_hwnds_
);
152 MOCK_METHOD0(OnLoadComplete
, void());
155 void ReconcileHwnds(HWND signaled_hwnd
,
156 std::set
<HWND
>* signaled_hwnd_set
,
157 std::set
<HWND
>* other_hwnd_set
) {
158 if (other_hwnd_set
->erase(signaled_hwnd
) != 0) {
161 signaled_hwnd_set
->insert(signaled_hwnd
);
164 std::set
<HWND
> acc_loaded_hwnds_
;
165 std::set
<HWND
> on_loaded_hwnds_
;
166 bool received_acc_load_
;
167 bool received_on_load_
;
168 testing::StrictMock
<MockIEEventSink
>* ie_mock_
;
169 testing::NiceMock
<MockAccEventObserver
> acc_observer_
;
172 TEST_F(DeleteBrowsingHistoryTest
, DISABLED_CFDeleteBrowsingHistory
) {
173 if (GetInstalledIEVersion() < IE_8
) {
174 LOG(ERROR
) << "Test does not apply to IE versions < 8.";
178 PageLoadHelper
load_helper(&ie_mock_
);
179 PageLoadHelper
load_helper2(&ie_mock2_
);
180 PageLoadHelper
load_helper3(&ie_mock3_
);
182 delete_browsing_history_window_observer_mock_
.WatchWindow(
183 "Delete Browsing History", "");
185 // For some reason, this page is occasionally being cached, so we randomize
186 // its name to ensure that, at least the first time we request it, it is
188 std::wstring top_name
= RandomChars(32);
189 std::wstring top_url
= server_mock_
.Resolve(top_name
);
190 std::wstring top_path
= L
"/" + top_name
;
192 // Even still, it might not be hit the second or third time, so let's just
193 // not worry about how often or whether it's called
194 EXPECT_CALL(server_mock_
, Get(_
, testing::StrEq(top_path
), _
))
195 .Times(testing::AnyNumber())
196 .WillRepeatedly(SendFast(kHtmlHttpHeaders
, topHtml
));
198 testing::InSequence expect_in_sequence_for_scope
;
200 // First launch will hit the server, requesting top.html and then image_path_
201 EXPECT_CALL(server_mock_
, Get(_
, testing::StrEq(image_path_
), _
))
202 .WillOnce(SendFast(kBlankPngResponse
[0],
203 std::string(kBlankPngResponse
[1],
204 kBlankPngFileLength
)));
206 // top.html contains a form. Fill in the username field and submit, causing
207 // the value to be stored in Chrome's form data DB.
208 EXPECT_CALL(load_helper
, OnLoadComplete())
209 .WillOnce(testing::DoAll(
210 AccLeftClickInRenderer(&ie_mock_
, AccObjectMatcher(L
"username")),
211 PostCharMessagesToRenderer(&ie_mock_
, WideToASCII(kFormFieldValue
)),
212 AccLeftClickInRenderer(&ie_mock_
, AccObjectMatcher(L
"Submit"))));
214 EXPECT_CALL(server_mock_
, Post(_
, testing::StrEq(L
"/form"), _
))
215 .WillOnce(SendFast(kHtmlHttpHeaders
, kFormResultHtml
));
217 // OnLoad of the result page from form submission. Now close the browser.
218 EXPECT_CALL(load_helper
, OnLoadComplete())
219 .WillOnce(testing::DoAll(
220 WatchRendererProcess(&ie_process_exit_watcher_mock_
, &ie_mock_
),
221 CloseBrowserMock(&ie_mock_
)));
223 EXPECT_CALL(ie_mock_
, OnQuit());
225 // Wait until the process is gone, so that the Chrome databases are unlocked.
226 // Verify that the submitted username is in the database, then launch a new
228 EXPECT_CALL(ie_process_exit_watcher_mock_
, OnObjectSignaled(_
))
229 .WillOnce(testing::DoAll(
230 ExpectFormValuesForElementNameMatch(
231 kFormFieldName
, testing::Contains(kFormFieldValue
)),
232 LaunchThisIEAndNavigate(&ie_mock2_
, top_url
)));
234 // Second launch won't load the image due to the cache.
236 // We do the delete private data twice, each time toggling the state of the
237 // 'Delete form data' and 'Delete temporary files' options.
238 // That's because we have no way to know their initial states. Using this,
239 // trick we are guaranteed to run it exactly once with each option turned on.
240 // Running it once with the option turned off is harmless.
242 // Proceed to open up the "Safety" menu for the first time through the loop.
243 EXPECT_CALL(load_helper2
, OnLoadComplete())
244 .WillOnce(AccDoDefaultActionInBrowser(&ie_mock2_
,
245 AccObjectMatcher(L
"Safety")));
247 // Store the dialog and progress_bar HWNDs for each iteration
248 // in order to distinguish between the OnClose of each.
249 HWND dialog
[] = {NULL
, NULL
};
250 HWND progress_bar
[] = {NULL
, NULL
};
252 for (int i
= 0; i
< 2; ++i
) {
253 // Watch for the popup menu, click 'Delete Browsing History...'
254 EXPECT_CALL(acc_observer_
, OnMenuPopup(_
))
256 AccLeftClick(AccObjectMatcher(L
"Delete Browsing History...*")));
258 // When it shows up, toggle the options and click "Delete".
259 EXPECT_CALL(delete_browsing_history_window_observer_mock_
, OnWindowOpen(_
))
260 .WillOnce(testing::DoAll(
261 testing::SaveArg
<0>(&dialog
[i
]),
262 AccLeftClick(AccObjectMatcher(L
"Temporary Internet files")),
263 AccLeftClick(AccObjectMatcher(L
"Form data")),
264 AccLeftClick(AccObjectMatcher(L
"Delete"))));
266 // The configuration dialog closes.
267 // This is not reliably ordered with respect to the following OnWindowOpen.
268 // Specifying 'AnyNumber' of times allows us to disregard it, although we
269 // can't avoid receiving the call.
270 EXPECT_CALL(delete_browsing_history_window_observer_mock_
,
271 OnWindowClose(testing::Eq(testing::ByRef(dialog
[i
]))))
272 .Times(testing::AnyNumber());
274 // The progress dialog that pops up has the same caption.
275 EXPECT_CALL(delete_browsing_history_window_observer_mock_
,
276 OnWindowOpen(_
)).WillOnce(testing::SaveArg
<0>(&progress_bar
[i
]));
278 // Watch for it to go away, then either do the "Delete History" again or
279 // close the browser.
280 // In either case, validate the contents of the renderer to ensure that
281 // we didn't cause Chrome to crash.
283 EXPECT_CALL(delete_browsing_history_window_observer_mock_
,
284 OnWindowClose(testing::Eq(testing::ByRef(progress_bar
[i
]))))
285 .WillOnce(testing::DoAll(
286 AccExpectInRenderer(&ie_mock2_
,
287 AccObjectMatcher(L
"Blank image.")),
288 AccDoDefaultActionInBrowser(&ie_mock2_
,
289 AccObjectMatcher(L
"Safety"))));
291 EXPECT_CALL(delete_browsing_history_window_observer_mock_
,
292 OnWindowClose(testing::Eq(testing::ByRef(progress_bar
[i
]))))
293 .WillOnce(testing::DoAll(
294 AccExpectInRenderer(&ie_mock2_
,
295 AccObjectMatcher(L
"Blank image.")),
296 WatchRendererProcess(&ie_process_exit_watcher_mock_
,
298 CloseBrowserMock(&ie_mock2_
)));
302 EXPECT_CALL(ie_mock2_
, OnQuit());
304 // When the process is actually exited, and the DB has been released, verify
305 // that the remembered form data is not in the form data DB.
306 EXPECT_CALL(ie_process_exit_watcher_mock_
, OnObjectSignaled(_
))
307 .WillOnce(testing::DoAll(
308 ExpectFormValuesForElementNameMatch(
309 kFormFieldName
, testing::Not(testing::Contains(kFormFieldValue
))),
310 LaunchThisIEAndNavigate(&ie_mock3_
, top_url
)));
312 // Now that the cache is cleared, final session should load the image from the
314 EXPECT_CALL(server_mock_
, Get(_
, testing::StrEq(image_path_
), _
))
316 SendFast(kBlankPngResponse
[0], std::string(kBlankPngResponse
[1],
317 kBlankPngFileLength
)));
319 EXPECT_CALL(load_helper3
, OnLoadComplete())
320 .WillOnce(CloseBrowserMock(&ie_mock3_
));
322 EXPECT_CALL(ie_mock3_
, OnQuit())
323 .WillOnce(QUIT_LOOP(loop_
));
325 // Start it up. Everything else is triggered as mock actions.
326 ASSERT_HRESULT_SUCCEEDED(
327 ie_mock_
.event_sink()->LaunchIEAndNavigate(top_url
, &ie_mock_
));
329 // 3 navigations + 2 invocations of delete browser history == 5
330 loop_
.RunFor(kChromeFrameLongNavigationTimeout
* 5);
333 } // namespace chrome_frame_test