toolkit/components/places/tests/cpp/test_IHistory.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
     3  * This Source Code Form is subject to the terms of the Mozilla Public
     4  * License, v. 2.0. If a copy of the MPL was not distributed with this
     5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     7 #include "places_test_harness.h"
     8 #include "nsIPrefService.h"
     9 #include "nsIPrefBranch.h"
    10 #include "mozilla/Attributes.h"
    12 #include "mock_Link.h"
    13 using namespace mozilla;
    14 using namespace mozilla::dom;
    16 /**
    17  * This file tests the IHistory interface.
    18  */
    20 ////////////////////////////////////////////////////////////////////////////////
    21 //// Helper Methods
    23 void
    24 expect_visit(nsLinkState aState)
    25 {
    26   do_check_true(aState == eLinkState_Visited);
    27 }
    29 void
    30 expect_no_visit(nsLinkState aState)
    31 {
    32   do_check_true(aState == eLinkState_Unvisited);
    33 }
    35 already_AddRefed<nsIURI>
    36 new_test_uri()
    37 {
    38   // Create a unique spec.
    39   static int32_t specNumber = 0;
    40   nsAutoCString spec = NS_LITERAL_CSTRING("http://mozilla.org/");
    41   spec.AppendInt(specNumber++);
    43   // Create the URI for the spec.
    44   nsCOMPtr<nsIURI> testURI;
    45   nsresult rv = NS_NewURI(getter_AddRefs(testURI), spec);
    46   do_check_success(rv);
    47   return testURI.forget();
    48 }
    50 class VisitURIObserver MOZ_FINAL : public nsIObserver
    51 {
    52 public:
    53   NS_DECL_ISUPPORTS
    55   VisitURIObserver(int aExpectedVisits = 1) :
    56     mVisits(0),
    57     mExpectedVisits(aExpectedVisits)
    58   {
    59     nsCOMPtr<nsIObserverService> observerService =
    60       do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
    61     do_check_true(observerService);
    62     (void)observerService->AddObserver(this,
    63                                        "uri-visit-saved",
    64                                        false);
    65   }
    67   void WaitForNotification()
    68   {
    69     while (mVisits < mExpectedVisits) {
    70       (void)NS_ProcessNextEvent();
    71     }
    72   }
    74   NS_IMETHOD Observe(nsISupports* aSubject,
    75                      const char* aTopic,
    76                      const char16_t* aData)
    77   {
    78     mVisits++;
    80     if (mVisits == mExpectedVisits) {
    81       nsCOMPtr<nsIObserverService> observerService =
    82         do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
    83       (void)observerService->RemoveObserver(this, "uri-visit-saved");
    84     }
    86     return NS_OK;
    87   }
    88 private:
    89   int mVisits;
    90   int mExpectedVisits;
    91 };
    92 NS_IMPL_ISUPPORTS(
    93   VisitURIObserver,
    94   nsIObserver
    95 )
    97 ////////////////////////////////////////////////////////////////////////////////
    98 //// Test Functions
   100 void
   101 test_set_places_enabled()
   102 {
   103   // Ensure places is enabled for everyone.
   104   nsresult rv;
   105   nsCOMPtr<nsIPrefBranch> prefBranch =
   106     do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
   107   do_check_success(rv);
   109   rv = prefBranch->SetBoolPref("places.history.enabled", true);
   110   do_check_success(rv);
   112   // Run the next test.
   113   run_next_test();
   114 }
   117 void
   118 test_wait_checkpoint()
   119 {
   120   // This "fake" test is here to wait for the initial WAL checkpoint we force
   121   // after creating the database schema, since that may happen at any time,
   122   // and cause concurrent readers to access an older checkpoint.
   123   nsCOMPtr<mozIStorageConnection> db = do_get_db();
   124   nsCOMPtr<mozIStorageAsyncStatement> stmt;
   125   db->CreateAsyncStatement(NS_LITERAL_CSTRING("SELECT 1"),
   126                            getter_AddRefs(stmt));
   127   nsRefPtr<AsyncStatementSpinner> spinner = new AsyncStatementSpinner();
   128   nsCOMPtr<mozIStoragePendingStatement> pending;
   129   (void)stmt->ExecuteAsync(spinner, getter_AddRefs(pending));
   130   spinner->SpinUntilCompleted();
   132   // Run the next test.
   133   run_next_test();
   134 }
   136 // These variables are shared between part 1 and part 2 of the test.  Part 2
   137 // sets the nsCOMPtr's to nullptr, freeing the reference.
   138 namespace test_unvisited_does_not_notify {
   139   nsCOMPtr<nsIURI> testURI;
   140   nsRefPtr<Link> testLink;
   141 }
   142 void
   143 test_unvisited_does_not_notify_part1()
   144 {
   145   using namespace test_unvisited_does_not_notify;
   147   // This test is done in two parts.  The first part registers for a URI that
   148   // should not be visited.  We then run another test that will also do a
   149   // lookup and will be notified.  Since requests are answered in the order they
   150   // are requested (at least as long as the same URI isn't asked for later), we
   151   // will know that the Link was not notified.
   153   // First, we need a test URI.
   154   testURI = new_test_uri();
   156   // Create our test Link.
   157   testLink = new mock_Link(expect_no_visit);
   159   // Now, register our Link to be notified.
   160   nsCOMPtr<IHistory> history = do_get_IHistory();
   161   nsresult rv = history->RegisterVisitedCallback(testURI, testLink);
   162   do_check_success(rv);
   164   // Run the next test.
   165   run_next_test();
   166 }
   168 void
   169 test_visited_notifies()
   170 {
   171   // First, we add our test URI to history.
   172   nsCOMPtr<nsIURI> testURI = new_test_uri();
   173   addURI(testURI);
   175   // Create our test Link.  The callback function will release the reference we
   176   // have on the Link.
   177   nsRefPtr<Link> link = new mock_Link(expect_visit);
   179   // Now, register our Link to be notified.
   180   nsCOMPtr<IHistory> history = do_get_IHistory();
   181   nsresult rv = history->RegisterVisitedCallback(testURI, link);
   182   do_check_success(rv);
   184   // Note: test will continue upon notification.
   185 }
   187 void
   188 test_unvisited_does_not_notify_part2()
   189 {
   190   using namespace test_unvisited_does_not_notify;
   192   // We would have had a failure at this point had the content node been told it
   193   // was visited.  Therefore, it is safe to unregister our content node.
   194   nsCOMPtr<IHistory> history = do_get_IHistory();
   195   nsresult rv = history->UnregisterVisitedCallback(testURI, testLink);
   196   do_check_success(rv);
   198   // Clear the stored variables now.
   199   testURI = nullptr;
   200   testLink = nullptr;
   202   // Run the next test.
   203   run_next_test();
   204 }
   206 void
   207 test_same_uri_notifies_both()
   208 {
   209   // First, we add our test URI to history.
   210   nsCOMPtr<nsIURI> testURI = new_test_uri();
   211   addURI(testURI);
   213   // Create our two test Links.  The callback function will release the
   214   // reference we have on the Links.  Only the second Link should run the next
   215   // test!
   216   nsRefPtr<Link> link1 = new mock_Link(expect_visit, false);
   217   nsRefPtr<Link> link2 = new mock_Link(expect_visit);
   219   // Now, register our Link to be notified.
   220   nsCOMPtr<IHistory> history = do_get_IHistory();
   221   nsresult rv = history->RegisterVisitedCallback(testURI, link1);
   222   do_check_success(rv);
   223   rv = history->RegisterVisitedCallback(testURI, link2);
   224   do_check_success(rv);
   226   // Note: test will continue upon notification.
   227 }
   229 void
   230 test_unregistered_visited_does_not_notify()
   231 {
   232   // This test must have a test that has a successful notification after it.
   233   // The Link would have been notified by now if we were buggy and notified
   234   // unregistered Links (due to request serialization).
   236   nsCOMPtr<nsIURI> testURI = new_test_uri();
   237   nsRefPtr<Link> link = new mock_Link(expect_no_visit);
   239   // Now, register our Link to be notified.
   240   nsCOMPtr<IHistory> history(do_get_IHistory());
   241   nsresult rv = history->RegisterVisitedCallback(testURI, link);
   242   do_check_success(rv);
   244   // Unregister the Link.
   245   rv = history->UnregisterVisitedCallback(testURI, link);
   246   do_check_success(rv);
   248   // And finally add a visit for the URI.
   249   addURI(testURI);
   251   // If history tries to notify us, we'll either crash because the Link will
   252   // have been deleted (we are the only thing holding a reference to it), or our
   253   // expect_no_visit call back will produce a failure.  Either way, the test
   254   // will be reported as a failure.
   256   // Run the next test.
   257   run_next_test();
   258 }
   260 void
   261 test_new_visit_notifies_waiting_Link()
   262 {
   263   // Create our test Link.  The callback function will release the reference we
   264   // have on the link.
   265   nsRefPtr<Link> link = new mock_Link(expect_visit);
   267   // Now, register our content node to be notified.
   268   nsCOMPtr<nsIURI> testURI = new_test_uri();
   269   nsCOMPtr<IHistory> history = do_get_IHistory();
   270   nsresult rv = history->RegisterVisitedCallback(testURI, link);
   271   do_check_success(rv);
   273   // Add ourselves to history.
   274   addURI(testURI);
   276   // Note: test will continue upon notification.
   277 }
   279 void
   280 test_RegisterVisitedCallback_returns_before_notifying()
   281 {
   282   // Add a URI so that it's already in history.
   283   nsCOMPtr<nsIURI> testURI = new_test_uri();
   284   addURI(testURI);
   286   // Create our test Link.
   287   nsRefPtr<Link> link = new mock_Link(expect_no_visit);
   289   // Now, register our content node to be notified.  It should not be notified.
   290   nsCOMPtr<IHistory> history = do_get_IHistory();
   291   nsresult rv = history->RegisterVisitedCallback(testURI, link);
   292   do_check_success(rv);
   294   // Remove ourselves as an observer.  We would have failed if we had been
   295   // notified.
   296   rv = history->UnregisterVisitedCallback(testURI, link);
   297   do_check_success(rv);
   299   run_next_test();
   300 }
   302 namespace test_observer_topic_dispatched_helpers {
   303   #define URI_VISITED "visited"
   304   #define URI_NOT_VISITED "not visited"
   305   #define URI_VISITED_RESOLUTION_TOPIC "visited-status-resolution"
   306   class statusObserver MOZ_FINAL : public nsIObserver
   307   {
   308   public:
   309     NS_DECL_ISUPPORTS
   311     statusObserver(nsIURI* aURI,
   312                    const bool aExpectVisit,
   313                    bool& _notified)
   314     : mURI(aURI)
   315     , mExpectVisit(aExpectVisit)
   316     , mNotified(_notified)
   317     {
   318       nsCOMPtr<nsIObserverService> observerService =
   319         do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   320       do_check_true(observerService);
   321       (void)observerService->AddObserver(this,
   322                                          URI_VISITED_RESOLUTION_TOPIC,
   323                                          false);
   324     }
   326     NS_IMETHOD Observe(nsISupports* aSubject,
   327                        const char* aTopic,
   328                        const char16_t* aData)
   329     {
   330       // Make sure we got notified of the right topic.
   331       do_check_false(strcmp(aTopic, URI_VISITED_RESOLUTION_TOPIC));
   333       // If this isn't for our URI, do not do anything.
   334       nsCOMPtr<nsIURI> notifiedURI = do_QueryInterface(aSubject);
   335       do_check_true(notifiedURI);
   337       bool isOurURI;
   338       nsresult rv = notifiedURI->Equals(mURI, &isOurURI);
   339       do_check_success(rv);
   340       if (!isOurURI) {
   341         return NS_OK;
   342       }
   344       // Check that we have either the visited or not visited string.
   345       bool visited = !!NS_LITERAL_STRING(URI_VISITED).Equals(aData);
   346       bool notVisited = !!NS_LITERAL_STRING(URI_NOT_VISITED).Equals(aData);
   347       do_check_true(visited || notVisited);
   349       // Check to make sure we got the state we expected.
   350       do_check_eq(visited, mExpectVisit);
   352       // Indicate that we've been notified.
   353       mNotified = true;
   355       // Remove ourselves as an observer.
   356       nsCOMPtr<nsIObserverService> observerService =
   357         do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
   358       (void)observerService->RemoveObserver(this,
   359                                             URI_VISITED_RESOLUTION_TOPIC);
   360       return NS_OK;
   361     }
   362   private:
   363     nsCOMPtr<nsIURI> mURI;
   364     const bool mExpectVisit;
   365     bool& mNotified;
   366   };
   367   NS_IMPL_ISUPPORTS(
   368     statusObserver,
   369     nsIObserver
   370   )
   371 }
   372 void
   373 test_observer_topic_dispatched()
   374 {
   375   using namespace test_observer_topic_dispatched_helpers;
   377   // Create two URIs, making sure only one is in history.
   378   nsCOMPtr<nsIURI> visitedURI = new_test_uri();
   379   nsCOMPtr<nsIURI> notVisitedURI = new_test_uri();
   380   bool urisEqual;
   381   nsresult rv = visitedURI->Equals(notVisitedURI, &urisEqual);
   382   do_check_success(rv);
   383   do_check_false(urisEqual);
   384   addURI(visitedURI);
   386   // Need two Link objects as well - one for each URI.
   387   nsRefPtr<Link> visitedLink = new mock_Link(expect_visit, false);
   388   nsRefPtr<Link> visitedLinkCopy = visitedLink;
   389   nsRefPtr<Link> notVisitedLink = new mock_Link(expect_no_visit);
   391   // Add the right observers for the URIs to check results.
   392   bool visitedNotified = false;
   393   nsCOMPtr<nsIObserver> visitedObs =
   394     new statusObserver(visitedURI, true, visitedNotified);
   395   bool notVisitedNotified = false;
   396   nsCOMPtr<nsIObserver> unvisitedObs =
   397     new statusObserver(notVisitedURI, false, notVisitedNotified);
   399   // Register our Links to be notified.
   400   nsCOMPtr<IHistory> history = do_get_IHistory();
   401   rv = history->RegisterVisitedCallback(visitedURI, visitedLink);
   402   do_check_success(rv);
   403   rv = history->RegisterVisitedCallback(notVisitedURI, notVisitedLink);
   404   do_check_success(rv);
   406   // Spin the event loop as long as we have not been properly notified.
   407   while (!visitedNotified || !notVisitedNotified) {
   408     (void)NS_ProcessNextEvent();
   409   }
   411   // Unregister our observer that would not have been released.
   412   rv = history->UnregisterVisitedCallback(notVisitedURI, notVisitedLink);
   413   do_check_success(rv);
   415   run_next_test();
   416 }
   418 void
   419 test_visituri_inserts()
   420 {
   421   nsCOMPtr<IHistory> history = do_get_IHistory();
   422   nsCOMPtr<nsIURI> lastURI = new_test_uri();
   423   nsCOMPtr<nsIURI> visitedURI = new_test_uri();
   425   history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
   427   nsRefPtr<VisitURIObserver> finisher = new VisitURIObserver();
   428   finisher->WaitForNotification();
   430   PlaceRecord place;
   431   do_get_place(visitedURI, place);
   433   do_check_true(place.id > 0);
   434   do_check_false(place.hidden);
   435   do_check_false(place.typed);
   436   do_check_eq(place.visitCount, 1);
   438   run_next_test();
   439 }
   441 void
   442 test_visituri_updates()
   443 {
   444   nsCOMPtr<IHistory> history = do_get_IHistory();
   445   nsCOMPtr<nsIURI> lastURI = new_test_uri();
   446   nsCOMPtr<nsIURI> visitedURI = new_test_uri();
   447   nsRefPtr<VisitURIObserver> finisher;
   449   history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
   450   finisher = new VisitURIObserver();
   451   finisher->WaitForNotification();
   453   history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
   454   finisher = new VisitURIObserver();
   455   finisher->WaitForNotification();
   457   PlaceRecord place;
   458   do_get_place(visitedURI, place);
   460   do_check_eq(place.visitCount, 2);
   462   run_next_test();
   463 }
   465 void
   466 test_visituri_preserves_shown_and_typed()
   467 {
   468   nsCOMPtr<IHistory> history = do_get_IHistory();
   469   nsCOMPtr<nsIURI> lastURI = new_test_uri();
   470   nsCOMPtr<nsIURI> visitedURI = new_test_uri();
   472   history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
   473   // this simulates the uri visit happening in a frame.  Normally frame
   474   // transitions would be hidden unless it was previously loaded top-level
   475   history->VisitURI(visitedURI, lastURI, 0);
   477   nsRefPtr<VisitURIObserver> finisher = new VisitURIObserver(2);
   478   finisher->WaitForNotification();
   480   PlaceRecord place;
   481   do_get_place(visitedURI, place);
   482   do_check_false(place.hidden);
   484   run_next_test();
   485 }
   487 void
   488 test_visituri_creates_visit()
   489 {
   490   nsCOMPtr<IHistory> history = do_get_IHistory();
   491   nsCOMPtr<nsIURI> lastURI = new_test_uri();
   492   nsCOMPtr<nsIURI> visitedURI = new_test_uri();
   494   history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
   495   nsRefPtr<VisitURIObserver> finisher = new VisitURIObserver();
   496   finisher->WaitForNotification();
   498   PlaceRecord place;
   499   VisitRecord visit;
   500   do_get_place(visitedURI, place);
   501   do_get_lastVisit(place.id, visit);
   503   do_check_true(visit.id > 0);
   504   do_check_eq(visit.lastVisitId, 0);
   505   do_check_eq(visit.transitionType, nsINavHistoryService::TRANSITION_LINK);
   507   run_next_test();
   508 }
   510 void
   511 test_visituri_transition_typed()
   512 {
   513   nsCOMPtr<nsINavHistoryService> navHistory = do_get_NavHistory();
   514   nsCOMPtr<IHistory> history = do_get_IHistory();
   515   nsCOMPtr<nsIURI> lastURI = new_test_uri();
   516   nsCOMPtr<nsIURI> visitedURI = new_test_uri();
   518   navHistory->MarkPageAsTyped(visitedURI);
   519   history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
   520   nsRefPtr<VisitURIObserver> finisher = new VisitURIObserver();
   521   finisher->WaitForNotification();
   523   PlaceRecord place;
   524   VisitRecord visit;
   525   do_get_place(visitedURI, place);
   526   do_get_lastVisit(place.id, visit);
   528   do_check_true(visit.transitionType == nsINavHistoryService::TRANSITION_TYPED);
   530   run_next_test();
   531 }
   533 void
   534 test_visituri_transition_embed()
   535 {
   536   nsCOMPtr<IHistory> history = do_get_IHistory();
   537   nsCOMPtr<nsIURI> lastURI = new_test_uri();
   538   nsCOMPtr<nsIURI> visitedURI = new_test_uri();
   540   history->VisitURI(visitedURI, lastURI, 0);
   541   nsRefPtr<VisitURIObserver> finisher = new VisitURIObserver();
   542   finisher->WaitForNotification();
   544   PlaceRecord place;
   545   VisitRecord visit;
   546   do_get_place(visitedURI, place);
   547   do_get_lastVisit(place.id, visit);
   549   do_check_eq(place.id, 0);
   550   do_check_eq(visit.id, 0);
   552   run_next_test();
   553 }
   555 void
   556 test_new_visit_adds_place_guid()
   557 {
   558   // First, add a visit and wait.  This will also add a place.
   559   nsCOMPtr<nsIURI> visitedURI = new_test_uri();
   560   nsCOMPtr<IHistory> history = do_get_IHistory();
   561   nsresult rv = history->VisitURI(visitedURI, nullptr,
   562                                   mozilla::IHistory::TOP_LEVEL);
   563   do_check_success(rv);
   564   nsRefPtr<VisitURIObserver> finisher = new VisitURIObserver();
   565   finisher->WaitForNotification();
   567   // Check that we have a guid for our visit.
   568   PlaceRecord place;
   569   do_get_place(visitedURI, place);
   570   do_check_eq(place.visitCount, 1);
   571   do_check_eq(place.guid.Length(), 12);
   573   run_next_test();
   574 }
   576 ////////////////////////////////////////////////////////////////////////////////
   577 //// IPC-only Tests
   579 void
   580 test_two_null_links_same_uri()
   581 {
   582   // Tests that we do not crash when we have had two nullptr Links passed to
   583   // RegisterVisitedCallback and then the visit occurs (bug 607469).  This only
   584   // happens in IPC builds.
   585   nsCOMPtr<nsIURI> testURI = new_test_uri();
   587   nsCOMPtr<IHistory> history = do_get_IHistory();
   588   nsresult rv = history->RegisterVisitedCallback(testURI, nullptr);
   589   do_check_success(rv);
   590   rv = history->RegisterVisitedCallback(testURI, nullptr);
   591   do_check_success(rv);
   593   rv = history->VisitURI(testURI, nullptr, mozilla::IHistory::TOP_LEVEL);
   594   do_check_success(rv);
   596   nsRefPtr<VisitURIObserver> finisher = new VisitURIObserver();
   597   finisher->WaitForNotification();
   599   run_next_test();
   600 }
   602 ////////////////////////////////////////////////////////////////////////////////
   603 //// Test Harness
   605 /**
   606  * Note: for tests marked "Order Important!", please see the test for details.
   607  */
   608 Test gTests[] = {
   609   TEST(test_set_places_enabled), // Must come first!
   610   TEST(test_wait_checkpoint), // Must come second!
   611   TEST(test_unvisited_does_not_notify_part1), // Order Important!
   612   TEST(test_visited_notifies),
   613   TEST(test_unvisited_does_not_notify_part2), // Order Important!
   614   TEST(test_same_uri_notifies_both),
   615   TEST(test_unregistered_visited_does_not_notify), // Order Important!
   616   TEST(test_new_visit_notifies_waiting_Link),
   617   TEST(test_RegisterVisitedCallback_returns_before_notifying),
   618   TEST(test_observer_topic_dispatched),
   619   TEST(test_visituri_inserts),
   620   TEST(test_visituri_updates),
   621   TEST(test_visituri_preserves_shown_and_typed),
   622   TEST(test_visituri_creates_visit),
   623   TEST(test_visituri_transition_typed),
   624   TEST(test_visituri_transition_embed),
   625   TEST(test_new_visit_adds_place_guid),
   627   // The rest of these tests are tests that are only run in IPC builds.
   628   TEST(test_two_null_links_same_uri),
   629 };
   631 const char* file = __FILE__;
   632 #define TEST_NAME "IHistory"
   633 #define TEST_FILE file
   634 #include "places_test_harness_tail.h"

mercurial