OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include <string> | |
6 | |
7 #include "base/rand_util.h" | |
8 #include "chrome/common/url_constants.h" | |
9 #include "chrome_frame/test/mock_ie_event_sink_actions.h" | |
10 #include "chrome_frame/test/mock_ie_event_sink_test.h" | |
11 #include "components/autofill/core/browser/webdata/autofill_table.h" | |
12 #include "components/webdata/common/web_database.h" | |
13 #include "components/webdata/common/webdata_constants.h" | |
14 | |
15 using testing::_; | |
16 | |
17 namespace chrome_frame_test { | |
18 | |
19 class DeleteBrowsingHistoryTest | |
20 : public MockIEEventSinkTest, | |
21 public testing::Test { | |
22 public: | |
23 DeleteBrowsingHistoryTest() {} | |
24 | |
25 virtual void SetUp() { | |
26 // We will use the OnAccLoad event to monitor page loads, so we ignore | |
27 // these. | |
28 ie_mock_.ExpectAnyNavigations(); | |
29 ie_mock2_.ExpectAnyNavigations(); | |
30 ie_mock3_.ExpectAnyNavigations(); | |
31 EXPECT_CALL(acc_observer_, OnAccDocLoad(_)).Times(testing::AnyNumber()); | |
32 | |
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); | |
36 topHtml = | |
37 "<html><head>" | |
38 "<meta http-equiv=\"x-ua-compatible\" content=\"chrome=1\" />" | |
39 "</head>" | |
40 "<body>" | |
41 "<form method=\"POST\" action=\"/form\">" | |
42 "<input title=\"username\" type=\"text\" name=\"username\" />" | |
43 "<input type=\"submit\" title=\"Submit\" name=\"Submit\" />" | |
44 "</form>" | |
45 "<img alt=\"Blank image.\" src=\"" + WideToASCII(image_path_) + "\" />" | |
46 "This is some text.</body></html>"; | |
47 } | |
48 | |
49 protected: | |
50 std::wstring image_path_; | |
51 std::string topHtml; | |
52 | |
53 testing::NiceMock<MockAccEventObserver> acc_observer_; | |
54 MockWindowObserver delete_browsing_history_window_observer_mock_; | |
55 MockObjectWatcherDelegate ie_process_exit_watcher_mock_; | |
56 | |
57 testing::StrictMock<MockIEEventSink> ie_mock2_; | |
58 testing::StrictMock<MockIEEventSink> ie_mock3_; | |
59 | |
60 // Returns a string of |count| lowercase random characters. | |
61 static std::wstring RandomChars(int count) { | |
62 srand(static_cast<unsigned int>(time(NULL))); | |
63 std::wstring str; | |
64 for (int i = 0; i < count; ++i) | |
65 str += L'a' + base::RandInt(0, 25); | |
66 return str; | |
67 } | |
68 }; | |
69 | |
70 namespace { | |
71 | |
72 const wchar_t* kFormFieldName = L"username"; | |
73 const wchar_t* kFormFieldValue = L"test_username"; | |
74 | |
75 const char* kHtmlHttpHeaders = | |
76 "HTTP/1.1 200 OK\r\n" | |
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[] = { | |
83 "HTTP/1.1 200 OK\r\n" | |
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"}; | |
93 | |
94 const size_t kBlankPngFileLength = 95; | |
95 } // anonymous namespace | |
96 | |
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) { | |
100 base::FilePath root_path; | |
101 GetChromeFrameProfilePath(kIexploreProfileName, &root_path); | |
102 base::FilePath profile_path( | |
103 root_path.Append(L"Default").Append(kWebDataFilename)); | |
104 | |
105 autofill::AutofillTable autofill_table("en-US"); | |
106 WebDatabase web_database; | |
107 web_database.AddTable(&autofill_table); | |
108 sql::InitStatus init_status = web_database.Init(profile_path); | |
109 EXPECT_EQ(sql::INIT_OK, init_status); | |
110 | |
111 if (init_status == sql::INIT_OK) { | |
112 std::vector<base::string16> values; | |
113 autofill_table.GetFormValuesForElementName( | |
114 element_name, L"", &values, 9999); | |
115 EXPECT_THAT(values, matcher); | |
116 } | |
117 } | |
118 | |
119 // Launch |ie_mock| and navigate it to |url|. | |
120 ACTION_P2(LaunchThisIEAndNavigate, ie_mock, url) { | |
121 EXPECT_HRESULT_SUCCEEDED(ie_mock->event_sink()->LaunchIEAndNavigate(url, | |
122 ie_mock)); | |
123 } | |
124 | |
125 // Listens for OnAccLoad and OnLoad events for an IE instance and | |
126 // sends a single signal once both have been received. | |
127 // | |
128 // Allows tests to wait for both events to occur irrespective of their relative | |
129 // ordering. | |
130 class PageLoadHelper { | |
131 public: | |
132 explicit PageLoadHelper(testing::StrictMock<MockIEEventSink>* ie_mock) | |
133 : received_acc_load_(false), | |
134 received_on_load_(false), | |
135 ie_mock_(ie_mock) { | |
136 EXPECT_CALL(*ie_mock_, OnLoad(_, _)) | |
137 .Times(testing::AnyNumber()) | |
138 .WillRepeatedly(testing::InvokeWithoutArgs( | |
139 this, &PageLoadHelper::HandleOnLoad)); | |
140 EXPECT_CALL(acc_observer_, OnAccDocLoad(_)) | |
141 .Times(testing::AnyNumber()) | |
142 .WillRepeatedly(testing::Invoke(this, &PageLoadHelper::HandleAccLoad)); | |
143 } | |
144 | |
145 void HandleAccLoad(HWND hwnd) { | |
146 ReconcileHwnds(hwnd, &acc_loaded_hwnds_, &on_loaded_hwnds_); | |
147 } | |
148 | |
149 void HandleOnLoad() { | |
150 HWND hwnd = ie_mock_->event_sink()->GetRendererWindow(); | |
151 ReconcileHwnds(hwnd, &on_loaded_hwnds_, &acc_loaded_hwnds_); | |
152 } | |
153 | |
154 MOCK_METHOD0(OnLoadComplete, void()); | |
155 | |
156 private: | |
157 void ReconcileHwnds(HWND signaled_hwnd, | |
158 std::set<HWND>* signaled_hwnd_set, | |
159 std::set<HWND>* other_hwnd_set) { | |
160 if (other_hwnd_set->erase(signaled_hwnd) != 0) { | |
161 OnLoadComplete(); | |
162 } else { | |
163 signaled_hwnd_set->insert(signaled_hwnd); | |
164 } | |
165 } | |
166 std::set<HWND> acc_loaded_hwnds_; | |
167 std::set<HWND> on_loaded_hwnds_; | |
168 bool received_acc_load_; | |
169 bool received_on_load_; | |
170 testing::StrictMock<MockIEEventSink>* ie_mock_; | |
171 testing::NiceMock<MockAccEventObserver> acc_observer_; | |
172 }; | |
173 | |
174 TEST_F(DeleteBrowsingHistoryTest, DISABLED_CFDeleteBrowsingHistory) { | |
175 if (GetInstalledIEVersion() < IE_8) { | |
176 LOG(ERROR) << "Test does not apply to IE versions < 8."; | |
177 return; | |
178 } | |
179 | |
180 PageLoadHelper load_helper(&ie_mock_); | |
181 PageLoadHelper load_helper2(&ie_mock2_); | |
182 PageLoadHelper load_helper3(&ie_mock3_); | |
183 | |
184 delete_browsing_history_window_observer_mock_.WatchWindow( | |
185 "Delete Browsing History", ""); | |
186 | |
187 // For some reason, this page is occasionally being cached, so we randomize | |
188 // its name to ensure that, at least the first time we request it, it is | |
189 // retrieved. | |
190 std::wstring top_name = RandomChars(32); | |
191 std::wstring top_url = server_mock_.Resolve(top_name); | |
192 std::wstring top_path = L"/" + top_name; | |
193 | |
194 // Even still, it might not be hit the second or third time, so let's just | |
195 // not worry about how often or whether it's called | |
196 EXPECT_CALL(server_mock_, Get(_, testing::StrEq(top_path), _)) | |
197 .Times(testing::AnyNumber()) | |
198 .WillRepeatedly(SendFast(kHtmlHttpHeaders, topHtml)); | |
199 | |
200 testing::InSequence expect_in_sequence_for_scope; | |
201 | |
202 // First launch will hit the server, requesting top.html and then image_path_ | |
203 EXPECT_CALL(server_mock_, Get(_, testing::StrEq(image_path_), _)) | |
204 .WillOnce(SendFast(kBlankPngResponse[0], | |
205 std::string(kBlankPngResponse[1], | |
206 kBlankPngFileLength))); | |
207 | |
208 // top.html contains a form. Fill in the username field and submit, causing | |
209 // the value to be stored in Chrome's form data DB. | |
210 EXPECT_CALL(load_helper, OnLoadComplete()) | |
211 .WillOnce(testing::DoAll( | |
212 AccLeftClickInRenderer(&ie_mock_, AccObjectMatcher(L"username")), | |
213 PostKeyMessagesToRenderer(&ie_mock_, WideToASCII(kFormFieldValue)), | |
214 AccLeftClickInRenderer(&ie_mock_, AccObjectMatcher(L"Submit")))); | |
215 | |
216 EXPECT_CALL(server_mock_, Post(_, testing::StrEq(L"/form"), _)) | |
217 .WillOnce(SendFast(kHtmlHttpHeaders, kFormResultHtml)); | |
218 | |
219 // OnLoad of the result page from form submission. Now close the browser. | |
220 EXPECT_CALL(load_helper, OnLoadComplete()) | |
221 .WillOnce(testing::DoAll( | |
222 WatchRendererProcess(&ie_process_exit_watcher_mock_, &ie_mock_), | |
223 CloseBrowserMock(&ie_mock_))); | |
224 | |
225 EXPECT_CALL(ie_mock_, OnQuit()); | |
226 | |
227 // Wait until the process is gone, so that the Chrome databases are unlocked. | |
228 // Verify that the submitted username is in the database, then launch a new | |
229 // IE instance. | |
230 EXPECT_CALL(ie_process_exit_watcher_mock_, OnObjectSignaled(_)) | |
231 .WillOnce(testing::DoAll( | |
232 ExpectFormValuesForElementNameMatch( | |
233 kFormFieldName, testing::Contains(kFormFieldValue)), | |
234 LaunchThisIEAndNavigate(&ie_mock2_, top_url))); | |
235 | |
236 // Second launch won't load the image due to the cache. | |
237 | |
238 // We do the delete private data twice, each time toggling the state of the | |
239 // 'Delete form data' and 'Delete temporary files' options. | |
240 // That's because we have no way to know their initial states. Using this, | |
241 // trick we are guaranteed to run it exactly once with each option turned on. | |
242 // Running it once with the option turned off is harmless. | |
243 | |
244 // Proceed to open up the "Safety" menu for the first time through the loop. | |
245 EXPECT_CALL(load_helper2, OnLoadComplete()) | |
246 .WillOnce(AccDoDefaultActionInBrowser(&ie_mock2_, | |
247 AccObjectMatcher(L"Safety"))); | |
248 | |
249 // Store the dialog and progress_bar HWNDs for each iteration | |
250 // in order to distinguish between the OnClose of each. | |
251 HWND dialog[] = {NULL, NULL}; | |
252 HWND progress_bar[] = {NULL, NULL}; | |
253 | |
254 for (int i = 0; i < 2; ++i) { | |
255 // Watch for the popup menu, click 'Delete Browsing History...' | |
256 EXPECT_CALL(acc_observer_, OnMenuPopup(_)) | |
257 .WillOnce( | |
258 AccLeftClick(AccObjectMatcher(L"Delete Browsing History...*"))); | |
259 | |
260 // When it shows up, toggle the options and click "Delete". | |
261 EXPECT_CALL(delete_browsing_history_window_observer_mock_, OnWindowOpen(_)) | |
262 .WillOnce(testing::DoAll( | |
263 testing::SaveArg<0>(&dialog[i]), | |
264 AccLeftClick(AccObjectMatcher(L"Temporary Internet files")), | |
265 AccLeftClick(AccObjectMatcher(L"Form data")), | |
266 AccLeftClick(AccObjectMatcher(L"Delete")))); | |
267 | |
268 // The configuration dialog closes. | |
269 // This is not reliably ordered with respect to the following OnWindowOpen. | |
270 // Specifying 'AnyNumber' of times allows us to disregard it, although we | |
271 // can't avoid receiving the call. | |
272 EXPECT_CALL(delete_browsing_history_window_observer_mock_, | |
273 OnWindowClose(testing::Eq(testing::ByRef(dialog[i])))) | |
274 .Times(testing::AnyNumber()); | |
275 | |
276 // The progress dialog that pops up has the same caption. | |
277 EXPECT_CALL(delete_browsing_history_window_observer_mock_, | |
278 OnWindowOpen(_)).WillOnce(testing::SaveArg<0>(&progress_bar[i])); | |
279 | |
280 // Watch for it to go away, then either do the "Delete History" again or | |
281 // close the browser. | |
282 // In either case, validate the contents of the renderer to ensure that | |
283 // we didn't cause Chrome to crash. | |
284 if (i == 0) { | |
285 EXPECT_CALL(delete_browsing_history_window_observer_mock_, | |
286 OnWindowClose(testing::Eq(testing::ByRef(progress_bar[i])))) | |
287 .WillOnce(testing::DoAll( | |
288 AccExpectInRenderer(&ie_mock2_, | |
289 AccObjectMatcher(L"Blank image.")), | |
290 AccDoDefaultActionInBrowser(&ie_mock2_, | |
291 AccObjectMatcher(L"Safety")))); | |
292 } else { | |
293 EXPECT_CALL(delete_browsing_history_window_observer_mock_, | |
294 OnWindowClose(testing::Eq(testing::ByRef(progress_bar[i])))) | |
295 .WillOnce(testing::DoAll( | |
296 AccExpectInRenderer(&ie_mock2_, | |
297 AccObjectMatcher(L"Blank image.")), | |
298 WatchRendererProcess(&ie_process_exit_watcher_mock_, | |
299 &ie_mock2_), | |
300 CloseBrowserMock(&ie_mock2_))); | |
301 } | |
302 } | |
303 | |
304 EXPECT_CALL(ie_mock2_, OnQuit()); | |
305 | |
306 // When the process is actually exited, and the DB has been released, verify | |
307 // that the remembered form data is not in the form data DB. | |
308 EXPECT_CALL(ie_process_exit_watcher_mock_, OnObjectSignaled(_)) | |
309 .WillOnce(testing::DoAll( | |
310 ExpectFormValuesForElementNameMatch( | |
311 kFormFieldName, testing::Not(testing::Contains(kFormFieldValue))), | |
312 LaunchThisIEAndNavigate(&ie_mock3_, top_url))); | |
313 | |
314 // Now that the cache is cleared, final session should load the image from the | |
315 // server. | |
316 EXPECT_CALL(server_mock_, Get(_, testing::StrEq(image_path_), _)) | |
317 .WillOnce( | |
318 SendFast(kBlankPngResponse[0], std::string(kBlankPngResponse[1], | |
319 kBlankPngFileLength))); | |
320 | |
321 EXPECT_CALL(load_helper3, OnLoadComplete()) | |
322 .WillOnce(CloseBrowserMock(&ie_mock3_)); | |
323 | |
324 EXPECT_CALL(ie_mock3_, OnQuit()) | |
325 .WillOnce(QUIT_LOOP(loop_)); | |
326 | |
327 // Start it up. Everything else is triggered as mock actions. | |
328 ASSERT_HRESULT_SUCCEEDED( | |
329 ie_mock_.event_sink()->LaunchIEAndNavigate(top_url, &ie_mock_)); | |
330 | |
331 // 3 navigations + 2 invocations of delete browser history == 5 | |
332 loop_.RunFor(kChromeFrameLongNavigationTimeout * 5); | |
333 } | |
334 | |
335 } // namespace chrome_frame_test | |
OLD | NEW |