Home | History | Annotate | Download | only in test
      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<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
    336