зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1448057 - Asincify some Places tests and add a test for favicons on bookmark redirects. r=standard8
Async-ify some tests. Moves some tests from browser-chrome to xpcshell. Due to the move, I found out that we are fetching icons from network even when we are not supposed to, so fix this bug (automatically tested by xpcshell through disallowing remote network access). Add a missing test for bookmark redirects, to cover the moved around code. MozReview-Commit-ID: EB2Z0huovJh --HG-- rename : toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage.js => toolkit/components/places/tests/favicons/test_setAndFetchFaviconForPage.js rename : toolkit/components/places/tests/browser/browser_favicon_setAndFetchFaviconForPage_failures.js => toolkit/components/places/tests/favicons/test_setAndFetchFaviconForPage_failures.js extra : rebase_source : 5289551f205bea9c5f2c6e68bbc70ce421b77311
This commit is contained in:
Родитель
f443774ffa
Коммит
8b76afe3e5
|
@ -4,8 +4,6 @@
|
|||
|
||||
// This test make sure that the favicon of the private browsing is isolated.
|
||||
|
||||
const CC = Components.Constructor;
|
||||
|
||||
const TEST_SITE = "http://mochi.test:8888";
|
||||
const TEST_CACHE_SITE = "http://www.example.com";
|
||||
const TEST_DIRECTORY = "/browser/browser/components/privatebrowsing/test/browser/";
|
||||
|
@ -184,21 +182,17 @@ async function openTab(aBrowser, aURL) {
|
|||
return {tab, browser};
|
||||
}
|
||||
|
||||
// A clean up function to prevent affecting other tests.
|
||||
registerCleanupFunction(() => {
|
||||
// Clear all cookies.
|
||||
registerCleanupFunction(async () => {
|
||||
Services.cookies.removeAll();
|
||||
|
||||
// Clear all image caches and network caches.
|
||||
clearAllImageCaches();
|
||||
|
||||
Services.cache2.clear();
|
||||
await PlacesUtils.history.clear();
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
});
|
||||
|
||||
add_task(async function test_favicon_privateBrowsing() {
|
||||
// Clear all image caches before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
// Clear all favicons in Places.
|
||||
await clearAllPlacesFavicons();
|
||||
|
||||
|
@ -221,10 +215,16 @@ add_task(async function test_favicon_privateBrowsing() {
|
|||
// Add the observer earlier in case we don't capture events in time.
|
||||
let promiseObserveFavicon = observeFavicon(true, cookies[0], pageURI);
|
||||
|
||||
// The page must be bookmarked for favicon requests to go through in PB mode.
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: TEST_PAGE
|
||||
});
|
||||
|
||||
// Open a tab for the private window.
|
||||
let tabInfo = await openTab(privateWindow.gBrowser, TEST_PAGE);
|
||||
|
||||
// Waiting until favicon requests are all made.
|
||||
info("Waiting until favicon requests are all made in private window.");
|
||||
await promiseObserveFavicon;
|
||||
|
||||
// Close the tab.
|
||||
|
@ -239,7 +239,7 @@ add_task(async function test_favicon_privateBrowsing() {
|
|||
// Open a tab for the non-private window.
|
||||
tabInfo = await openTab(gBrowser, TEST_PAGE);
|
||||
|
||||
// Waiting until favicon requests are all made.
|
||||
info("Waiting until favicon requests are all made in non-private window.");
|
||||
await promiseObserveFavicon;
|
||||
|
||||
// Close the tab.
|
||||
|
@ -248,7 +248,7 @@ add_task(async function test_favicon_privateBrowsing() {
|
|||
});
|
||||
|
||||
add_task(async function test_favicon_cache_privateBrowsing() {
|
||||
// Clear all image cahces and network cache before running the test.
|
||||
// Clear all image caches and network cache before running the test.
|
||||
clearAllImageCaches();
|
||||
|
||||
Services.cache2.clear();
|
||||
|
@ -274,6 +274,12 @@ add_task(async function test_favicon_cache_privateBrowsing() {
|
|||
// Create a private browsing window.
|
||||
let privateWindow = await BrowserTestUtils.openNewBrowserWindow({ private: true });
|
||||
|
||||
// The page must be bookmarked for favicon requests to go through in PB mode.
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: TEST_CACHE_PAGE
|
||||
});
|
||||
|
||||
// Open a tab for the private window.
|
||||
let tabInfoPrivate = await openTab(privateWindow.gBrowser, TEST_CACHE_PAGE);
|
||||
|
||||
|
|
|
@ -53,30 +53,36 @@ FetchPageInfo(const RefPtr<Database>& aDB,
|
|||
MOZ_ASSERT(_page.spec.Length(), "Must have a non-empty spec!");
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
// This query finds the bookmarked uri we want to set the icon for,
|
||||
// walking up to two redirect levels.
|
||||
// The subquery finds the bookmarked uri we want to set the icon for,
|
||||
// walking up redirects.
|
||||
nsCString query = nsPrintfCString(
|
||||
"SELECT h.id, pi.id, h.guid, ( "
|
||||
"SELECT h.url FROM moz_bookmarks b WHERE b.fk = h.id "
|
||||
"UNION ALL " // Union not directly bookmarked pages.
|
||||
"SELECT url FROM moz_places WHERE id = ( "
|
||||
"SELECT COALESCE(grandparent.place_id, parent.place_id) as r_place_id "
|
||||
"FROM moz_historyvisits dest "
|
||||
"LEFT JOIN moz_historyvisits parent ON parent.id = dest.from_visit "
|
||||
"AND dest.visit_type IN (%d, %d) "
|
||||
"LEFT JOIN moz_historyvisits grandparent ON parent.from_visit = grandparent.id "
|
||||
"AND parent.visit_type IN (%d, %d) "
|
||||
"WHERE dest.place_id = h.id "
|
||||
"AND EXISTS(SELECT 1 FROM moz_bookmarks b WHERE b.fk = r_place_id) "
|
||||
"LIMIT 1 "
|
||||
"WITH RECURSIVE "
|
||||
"destinations(visit_type, from_visit, place_id, rev_host, bm) AS ( "
|
||||
"SELECT v.visit_type, v.from_visit, p.id, p.rev_host, b.id "
|
||||
"FROM moz_places p "
|
||||
"LEFT JOIN moz_historyvisits v ON v.place_id = p.id "
|
||||
"LEFT JOIN moz_bookmarks b ON b.fk = p.id "
|
||||
"WHERE p.id = h.id "
|
||||
"UNION "
|
||||
"SELECT src.visit_type, src.from_visit, src.place_id, p.rev_host, b.id "
|
||||
"FROM moz_places p "
|
||||
"JOIN moz_historyvisits src ON src.place_id = p.id "
|
||||
"JOIN destinations dest ON dest.from_visit = src.id AND dest.visit_type IN (%d, %d) "
|
||||
"LEFT JOIN moz_bookmarks b ON b.fk = src.place_id "
|
||||
"WHERE instr(p.rev_host, dest.rev_host) = 1 "
|
||||
"OR instr(dest.rev_host, p.rev_host) = 1 "
|
||||
") "
|
||||
"SELECT url "
|
||||
"FROM moz_places p "
|
||||
"JOIN destinations r ON r.place_id = p.id "
|
||||
"WHERE bm NOTNULL "
|
||||
"LIMIT 1 "
|
||||
"), fixup_url(get_unreversed_host(h.rev_host)) AS host "
|
||||
"FROM moz_places h "
|
||||
"LEFT JOIN moz_pages_w_icons pi ON page_url_hash = hash(:page_url) AND page_url = :page_url "
|
||||
"WHERE h.url_hash = hash(:page_url) AND h.url = :page_url",
|
||||
nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
|
||||
nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY,
|
||||
nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
|
||||
nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
|
||||
);
|
||||
|
||||
|
@ -542,6 +548,19 @@ AsyncFetchAndSetIconForPage::Run()
|
|||
bool fetchIconFromNetwork = mIcon.fetchMode == FETCH_ALWAYS ||
|
||||
(mIcon.fetchMode == FETCH_IF_MISSING && isInvalidIcon);
|
||||
|
||||
// Check if we can associate the icon to this page.
|
||||
rv = FetchPageInfo(DB, mPage);
|
||||
if (NS_FAILED(rv)) {
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE) {
|
||||
// We have never seen this page. If we can add the page to history,
|
||||
// we will try to do it later, otherwise just bail out.
|
||||
if (!mPage.canAddToHistory) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!fetchIconFromNetwork) {
|
||||
// There is already a valid icon or we don't want to fetch a new one,
|
||||
// directly proceed with association.
|
||||
|
@ -827,20 +846,9 @@ NS_IMETHODIMP
|
|||
AsyncAssociateIconToPage::Run()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
RefPtr<Database> DB = Database::GetDatabase();
|
||||
NS_ENSURE_STATE(DB);
|
||||
nsresult rv = FetchPageInfo(DB, mPage);
|
||||
if (rv == NS_ERROR_NOT_AVAILABLE){
|
||||
// We have never seen this page. If we can add the page to history,
|
||||
// we will try to do it later, otherwise just bail out.
|
||||
if (!mPage.canAddToHistory) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
MOZ_ASSERT(!mPage.guid.IsEmpty(), "Page info should have been fetched already");
|
||||
MOZ_ASSERT(mPage.canAddToHistory || !mPage.bookmarkedSpec.IsEmpty(),
|
||||
"The page should be addable to history or a bookmark");
|
||||
|
||||
bool shouldUpdateIcon = mIcon.status & ICON_STATUS_CHANGED;
|
||||
if (!shouldUpdateIcon) {
|
||||
|
@ -853,9 +861,11 @@ AsyncAssociateIconToPage::Run()
|
|||
}
|
||||
}
|
||||
|
||||
RefPtr<Database> DB = Database::GetDatabase();
|
||||
NS_ENSURE_STATE(DB);
|
||||
mozStorageTransaction transaction(DB->MainConn(), false,
|
||||
mozIStorageConnection::TRANSACTION_IMMEDIATE);
|
||||
|
||||
nsresult rv;
|
||||
if (shouldUpdateIcon) {
|
||||
rv = SetIconInfo(DB, mIcon);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -954,6 +964,23 @@ AsyncAssociateIconToPage::Run()
|
|||
rv = NS_DispatchToMainThread(event);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// If there is a bookmarked page that redirects to this one, try to update its
|
||||
// icon as well.
|
||||
if (!mPage.bookmarkedSpec.IsEmpty() &&
|
||||
!mPage.bookmarkedSpec.Equals(mPage.spec)) {
|
||||
// Create a new page struct to avoid polluting it with old data.
|
||||
PageData bookmarkedPage;
|
||||
bookmarkedPage.spec = mPage.bookmarkedSpec;
|
||||
RefPtr<Database> DB = Database::GetDatabase();
|
||||
if (DB && NS_SUCCEEDED(FetchPageInfo(DB, bookmarkedPage))) {
|
||||
// This will be silent, so be sure to not pass in the current callback.
|
||||
nsMainThreadPtrHandle<nsIFaviconDataCallback> nullCallback;
|
||||
RefPtr<AsyncAssociateIconToPage> event =
|
||||
new AsyncAssociateIconToPage(mIcon, bookmarkedPage, nullCallback);
|
||||
Unused << event->Run();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1128,7 +1155,15 @@ NotifyIconObservers::Run()
|
|||
// Notify observers only if something changed.
|
||||
if (mIcon.status & ICON_STATUS_SAVED ||
|
||||
mIcon.status & ICON_STATUS_ASSOCIATED) {
|
||||
SendGlobalNotifications(iconURI);
|
||||
nsCOMPtr<nsIURI> pageURI;
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(pageURI), mPage.spec));
|
||||
if (pageURI) {
|
||||
nsFaviconService* favicons = nsFaviconService::GetFaviconService();
|
||||
MOZ_ASSERT(favicons);
|
||||
if (favicons) {
|
||||
(void)favicons->SendFaviconNotifications(pageURI, iconURI, mPage.guid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1147,38 +1182,6 @@ NotifyIconObservers::Run()
|
|||
EmptyCString(), 0);
|
||||
}
|
||||
|
||||
void
|
||||
NotifyIconObservers::SendGlobalNotifications(nsIURI* aIconURI)
|
||||
{
|
||||
nsCOMPtr<nsIURI> pageURI;
|
||||
MOZ_ALWAYS_SUCCEEDS(NS_NewURI(getter_AddRefs(pageURI), mPage.spec));
|
||||
if (pageURI) {
|
||||
nsFaviconService* favicons = nsFaviconService::GetFaviconService();
|
||||
MOZ_ASSERT(favicons);
|
||||
if (favicons) {
|
||||
(void)favicons->SendFaviconNotifications(pageURI, aIconURI, mPage.guid);
|
||||
}
|
||||
}
|
||||
|
||||
// If the page is bookmarked and the bookmarked url is different from the
|
||||
// updated one, start a new task to update its icon as well.
|
||||
if (!mPage.bookmarkedSpec.IsEmpty() &&
|
||||
!mPage.bookmarkedSpec.Equals(mPage.spec)) {
|
||||
// Create a new page struct to avoid polluting it with old data.
|
||||
PageData bookmarkedPage;
|
||||
bookmarkedPage.spec = mPage.bookmarkedSpec;
|
||||
|
||||
RefPtr<Database> DB = Database::GetDatabase();
|
||||
if (!DB)
|
||||
return;
|
||||
// This will be silent, so be sure to not pass in the current callback.
|
||||
nsMainThreadPtrHandle<nsIFaviconDataCallback> nullCallback;
|
||||
RefPtr<AsyncAssociateIconToPage> event =
|
||||
new AsyncAssociateIconToPage(mIcon, bookmarkedPage, nullCallback);
|
||||
DB->DispatchToAsyncThread(event);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// FetchAndConvertUnsupportedPayloads
|
||||
|
||||
|
|
|
@ -327,8 +327,6 @@ private:
|
|||
nsMainThreadPtrHandle<nsIFaviconDataCallback> mCallback;
|
||||
IconData mIcon;
|
||||
PageData mPage;
|
||||
|
||||
void SendGlobalNotifications(nsIURI* aIconURI);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -13,8 +13,6 @@ support-files =
|
|||
[browser_colorAnalyzer.js]
|
||||
[browser_double_redirect.js]
|
||||
[browser_favicon_privatebrowsing_perwindowpb.js]
|
||||
[browser_favicon_setAndFetchFaviconForPage.js]
|
||||
[browser_favicon_setAndFetchFaviconForPage_failures.js]
|
||||
[browser_history_post.js]
|
||||
[browser_notfound.js]
|
||||
[browser_onvisit_title_null_for_navigation.js]
|
||||
|
|
|
@ -1,152 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This file tests the normal operation of setAndFetchFaviconForPage.
|
||||
function test() {
|
||||
// Initialization
|
||||
waitForExplicitFinish();
|
||||
let windowsToClose = [];
|
||||
let favIconLocation =
|
||||
"http://example.org/tests/toolkit/components/places/tests/browser/favicon-normal32.png";
|
||||
let favIconURI = NetUtil.newURI(favIconLocation);
|
||||
let favIconMimeType = "image/png";
|
||||
let pageURI;
|
||||
let favIconData;
|
||||
|
||||
function testOnWindow(aOptions, aCallback) {
|
||||
whenNewWindowLoaded(aOptions, function(aWin) {
|
||||
windowsToClose.push(aWin);
|
||||
executeSoon(() => aCallback(aWin));
|
||||
});
|
||||
}
|
||||
|
||||
// This function is called after calling finish() on the test.
|
||||
registerCleanupFunction(function() {
|
||||
windowsToClose.forEach(function(aWin) {
|
||||
aWin.close();
|
||||
});
|
||||
});
|
||||
|
||||
function getIconFile(aCallback) {
|
||||
NetUtil.asyncFetch({
|
||||
uri: favIconLocation,
|
||||
loadUsingSystemPrincipal: true,
|
||||
contentPolicyType: Ci.nsIContentPolicy.TYPE_INTERNAL_IMAGE_FAVICON
|
||||
}, function(inputStream, status) {
|
||||
if (!Components.isSuccessCode(status)) {
|
||||
ok(false, "Could not get the icon file");
|
||||
// Handle error.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the returned size versus the expected size.
|
||||
let size = inputStream.available();
|
||||
favIconData = NetUtil.readInputStreamToString(inputStream, size);
|
||||
is(size, favIconData.length, "Check correct icon size");
|
||||
// Check that the favicon loaded correctly before starting the actual tests.
|
||||
is(favIconData.length, 344, "Check correct icon length (344)");
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testNormal(aWindow, aCallback) {
|
||||
pageURI = NetUtil.newURI("http://example.com/normal");
|
||||
waitForFaviconChanged(pageURI, favIconURI, aWindow,
|
||||
function testNormalCallback() {
|
||||
checkFaviconDataForPage(pageURI, favIconMimeType, favIconData, aWindow,
|
||||
aCallback);
|
||||
}
|
||||
);
|
||||
|
||||
addVisits({uri: pageURI, transition: TRANSITION_TYPED}, aWindow,
|
||||
function() {
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, favIconURI,
|
||||
true, aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function testAboutURIBookmarked(aWindow, aCallback) {
|
||||
pageURI = NetUtil.newURI("about:testAboutURI_bookmarked");
|
||||
waitForFaviconChanged(pageURI, favIconURI, aWindow,
|
||||
function testAboutURIBookmarkedCallback() {
|
||||
checkFaviconDataForPage(pageURI, favIconMimeType, favIconData, aWindow,
|
||||
aCallback);
|
||||
}
|
||||
);
|
||||
|
||||
aWindow.PlacesUtils.bookmarks.insertBookmark(
|
||||
aWindow.PlacesUtils.unfiledBookmarksFolderId, pageURI,
|
||||
aWindow.PlacesUtils.bookmarks.DEFAULT_INDEX, pageURI.spec);
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, favIconURI,
|
||||
true, aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
}
|
||||
|
||||
function testPrivateBrowsingBookmarked(aWindow, aCallback) {
|
||||
pageURI = NetUtil.newURI("http://example.com/privateBrowsing_bookmarked");
|
||||
waitForFaviconChanged(pageURI, favIconURI, aWindow,
|
||||
function testPrivateBrowsingBookmarkedCallback() {
|
||||
checkFaviconDataForPage(pageURI, favIconMimeType, favIconData, aWindow,
|
||||
aCallback);
|
||||
}
|
||||
);
|
||||
|
||||
aWindow.PlacesUtils.bookmarks.insertBookmark(
|
||||
aWindow.PlacesUtils.unfiledBookmarksFolderId, pageURI,
|
||||
aWindow.PlacesUtils.bookmarks.DEFAULT_INDEX, pageURI.spec);
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, favIconURI,
|
||||
true, aWindow.PlacesUtils.favicons.FAVICON_LOAD_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
}
|
||||
|
||||
function testDisabledHistoryBookmarked(aWindow, aCallback) {
|
||||
pageURI = NetUtil.newURI("http://example.com/disabledHistory_bookmarked");
|
||||
waitForFaviconChanged(pageURI, favIconURI, aWindow,
|
||||
function testDisabledHistoryBookmarkedCallback() {
|
||||
checkFaviconDataForPage(pageURI, favIconMimeType, favIconData, aWindow,
|
||||
aCallback);
|
||||
}
|
||||
);
|
||||
|
||||
// Disable history while changing the favicon.
|
||||
aWindow.Services.prefs.setBoolPref("places.history.enabled", false);
|
||||
|
||||
aWindow.PlacesUtils.bookmarks.insertBookmark(
|
||||
aWindow.PlacesUtils.unfiledBookmarksFolderId, pageURI,
|
||||
aWindow.PlacesUtils.bookmarks.DEFAULT_INDEX, pageURI.spec);
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, favIconURI,
|
||||
true, aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
// The setAndFetchFaviconForPage function calls CanAddURI synchronously, thus
|
||||
// we can set the preference back to true immediately. We don't clear the
|
||||
// preference because not all products enable Places by default.
|
||||
aWindow.Services.prefs.setBoolPref("places.history.enabled", true);
|
||||
}
|
||||
|
||||
getIconFile(function() {
|
||||
testOnWindow({}, function(aWin) {
|
||||
testNormal(aWin, function() {
|
||||
testOnWindow({}, function(aWin2) {
|
||||
testAboutURIBookmarked(aWin2, function() {
|
||||
testOnWindow({private: true}, function(aWin3) {
|
||||
testPrivateBrowsingBookmarked(aWin3, function() {
|
||||
testOnWindow({}, function(aWin4) {
|
||||
testDisabledHistoryBookmarked(aWin4, finish);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,263 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/* eslint max-nested-callbacks: ["warn", 17] */
|
||||
|
||||
/**
|
||||
* This file tests setAndFetchFaviconForPage when it is called with invalid
|
||||
* arguments, and when no favicon is stored for the given arguments.
|
||||
*/
|
||||
function test() {
|
||||
// Initialization
|
||||
waitForExplicitFinish();
|
||||
let windowsToClose = [];
|
||||
let favIcon16Location =
|
||||
"http://example.org/tests/toolkit/components/places/tests/browser/favicon-normal16.png";
|
||||
let favIcon32Location =
|
||||
"http://example.org/tests/toolkit/components/places/tests/browser/favicon-normal32.png";
|
||||
let favIcon16URI = NetUtil.newURI(favIcon16Location);
|
||||
let favIcon32URI = NetUtil.newURI(favIcon32Location);
|
||||
let lastPageURI = NetUtil.newURI("http://example.com/verification");
|
||||
// This error icon must stay in sync with FAVICON_ERRORPAGE_URL in
|
||||
// nsIFaviconService.idl, aboutCertError.xhtml and netError.xhtml.
|
||||
let favIconErrorPageURI =
|
||||
NetUtil.newURI("chrome://global/skin/icons/warning-16.png");
|
||||
let favIconsResultCount = 0;
|
||||
|
||||
function testOnWindow(aOptions, aCallback) {
|
||||
whenNewWindowLoaded(aOptions, function(aWin) {
|
||||
windowsToClose.push(aWin);
|
||||
executeSoon(() => aCallback(aWin));
|
||||
});
|
||||
}
|
||||
|
||||
// This function is called after calling finish() on the test.
|
||||
registerCleanupFunction(function() {
|
||||
windowsToClose.forEach(function(aWin) {
|
||||
aWin.close();
|
||||
});
|
||||
});
|
||||
|
||||
function checkFavIconsDBCount(aCallback) {
|
||||
let stmt = DBConn().createAsyncStatement("SELECT icon_url FROM moz_icons");
|
||||
stmt.executeAsync({
|
||||
handleResult: function final_handleResult(aResultSet) {
|
||||
while (aResultSet.getNextRow()) {
|
||||
favIconsResultCount++;
|
||||
}
|
||||
},
|
||||
handleError: function final_handleError(aError) {
|
||||
throw ("Unexpected error (" + aError.result + "): " + aError.message);
|
||||
},
|
||||
handleCompletion: function final_handleCompletion(aReason) {
|
||||
// begin testing
|
||||
info("Previous records in moz_icons: " + favIconsResultCount);
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}
|
||||
});
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
function testNullPageURI(aWindow, aCallback) {
|
||||
try {
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(null, favIcon16URI,
|
||||
true, aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
throw ("Exception expected because aPageURI is null.");
|
||||
} catch (ex) {
|
||||
// We expected an exception.
|
||||
ok(true, "Exception expected because aPageURI is null");
|
||||
}
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}
|
||||
|
||||
function testNullFavIconURI(aWindow, aCallback) {
|
||||
try {
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
NetUtil.newURI("http://example.com/null_faviconURI"), null,
|
||||
true, aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
null, Services.scriptSecurityManager.getSystemPrincipal());
|
||||
throw ("Exception expected because aFaviconURI is null.");
|
||||
} catch (ex) {
|
||||
// We expected an exception.
|
||||
ok(true, "Exception expected because aFaviconURI is null.");
|
||||
}
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}
|
||||
|
||||
function testAboutURI(aWindow, aCallback) {
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
NetUtil.newURI("about:testAboutURI"), favIcon16URI,
|
||||
true, aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
null, Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}
|
||||
|
||||
function testPrivateBrowsingNonBookmarkedURI(aWindow, aCallback) {
|
||||
let pageURI = NetUtil.newURI("http://example.com/privateBrowsing");
|
||||
addVisits({ uri: pageURI, transitionType: TRANSITION_TYPED }, aWindow,
|
||||
function() {
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI,
|
||||
favIcon16URI, true,
|
||||
aWindow.PlacesUtils.favicons.FAVICON_LOAD_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testDisabledHistory(aWindow, aCallback) {
|
||||
let pageURI = NetUtil.newURI("http://example.com/disabledHistory");
|
||||
addVisits({ uri: pageURI, transition: TRANSITION_TYPED }, aWindow,
|
||||
function() {
|
||||
aWindow.Services.prefs.setBoolPref("places.history.enabled", false);
|
||||
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI,
|
||||
favIcon16URI, true,
|
||||
aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
// The setAndFetchFaviconForPage function calls CanAddURI synchronously, thus
|
||||
// we can set the preference back to true immediately . We don't clear the
|
||||
// preference because not all products enable Places by default.
|
||||
aWindow.Services.prefs.setBoolPref("places.history.enabled", true);
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testErrorIcon(aWindow, aCallback) {
|
||||
let pageURI = NetUtil.newURI("http://example.com/errorIcon");
|
||||
addVisits({ uri: pageURI, transition: TRANSITION_TYPED }, aWindow,
|
||||
function() {
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI,
|
||||
favIconErrorPageURI, true,
|
||||
aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testNonExistingPage(aWindow, aCallback) {
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
NetUtil.newURI("http://example.com/nonexistingPage"), favIcon16URI,
|
||||
true, aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}
|
||||
|
||||
function testFinalVerification(aWindow, aCallback) {
|
||||
// Only the last test should raise the onPageChanged notification,
|
||||
// executing the waitForFaviconChanged callback.
|
||||
waitForFaviconChanged(lastPageURI, favIcon32URI, aWindow,
|
||||
function final_callback() {
|
||||
// Check that only one record corresponding to the last favicon is present.
|
||||
let resultCount = 0;
|
||||
let stmt = DBConn().createAsyncStatement("SELECT icon_url FROM moz_icons");
|
||||
stmt.executeAsync({
|
||||
handleResult: function final_handleResult(aResultSet) {
|
||||
|
||||
// If the moz_icons DB had been previously loaded (before our
|
||||
// test began), we should focus only in the URI we are testing and
|
||||
// skip the URIs not related to our test.
|
||||
if (favIconsResultCount > 0) {
|
||||
for (let row; (row = aResultSet.getNextRow()); ) {
|
||||
if (favIcon32URI.spec === row.getResultByIndex(0)) {
|
||||
is(favIcon32URI.spec, row.getResultByIndex(0),
|
||||
"Check equal favicons");
|
||||
resultCount++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (let row; (row = aResultSet.getNextRow()); ) {
|
||||
is(favIcon32URI.spec, row.getResultByIndex(0),
|
||||
"Check equal favicons");
|
||||
resultCount++;
|
||||
}
|
||||
}
|
||||
},
|
||||
handleError: function final_handleError(aError) {
|
||||
throw ("Unexpected error (" + aError.result + "): " + aError.message);
|
||||
},
|
||||
handleCompletion: function final_handleCompletion(aReason) {
|
||||
is(Ci.mozIStorageStatementCallback.REASON_FINISHED, aReason,
|
||||
"Check reasons are equal");
|
||||
is(1, resultCount, "Check result count");
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}
|
||||
});
|
||||
stmt.finalize();
|
||||
});
|
||||
|
||||
// This is the only test that should cause the waitForFaviconChanged
|
||||
// callback to be invoked. In turn, the callback will invoke
|
||||
// finish() causing the tests to finish.
|
||||
addVisits({ uri: lastPageURI, transition: TRANSITION_TYPED }, aWindow,
|
||||
function() {
|
||||
aWindow.PlacesUtils.favicons.setAndFetchFaviconForPage(lastPageURI,
|
||||
favIcon32URI, true,
|
||||
aWindow.PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
});
|
||||
}
|
||||
|
||||
checkFavIconsDBCount(function() {
|
||||
testOnWindow({}, function(aWin) {
|
||||
testNullPageURI(aWin, function() {
|
||||
testOnWindow({}, function(aWin2) {
|
||||
testNullFavIconURI(aWin2, function() {
|
||||
testOnWindow({}, function(aWin3) {
|
||||
testAboutURI(aWin3, function() {
|
||||
testOnWindow({private: true}, function(aWin4) {
|
||||
testPrivateBrowsingNonBookmarkedURI(aWin4, function() {
|
||||
testOnWindow({}, function(aWin5) {
|
||||
testDisabledHistory(aWin5, function() {
|
||||
testOnWindow({}, function(aWin6) {
|
||||
testErrorIcon(aWin6, function() {
|
||||
testOnWindow({}, function(aWin7) {
|
||||
testNonExistingPage(aWin7, function() {
|
||||
testOnWindow({}, function(aWin8) {
|
||||
testFinalVerification(aWin8, function() {
|
||||
finish();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -89,43 +89,6 @@ NavHistoryObserver.prototype = {
|
|||
])
|
||||
};
|
||||
|
||||
/**
|
||||
* Waits for the first OnPageChanged notification for ATTRIBUTE_FAVICON, and
|
||||
* verifies that it matches the expected page URI and associated favicon URI.
|
||||
*
|
||||
* This function also double-checks the GUID parameter of the notification.
|
||||
*
|
||||
* @param aExpectedPageURI
|
||||
* nsIURI object of the page whose favicon should change.
|
||||
* @param aExpectedFaviconURI
|
||||
* nsIURI object of the newly associated favicon.
|
||||
* @param aCallback
|
||||
* This function is called after the check finished.
|
||||
*/
|
||||
function waitForFaviconChanged(aExpectedPageURI, aExpectedFaviconURI, aWindow,
|
||||
aCallback) {
|
||||
let historyObserver = {
|
||||
__proto__: NavHistoryObserver.prototype,
|
||||
onPageChanged: function WFFC_onPageChanged(aURI, aWhat, aValue, aGUID) {
|
||||
if (aWhat != Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
|
||||
return;
|
||||
}
|
||||
aWindow.PlacesUtils.history.removeObserver(this);
|
||||
|
||||
ok(aURI.equals(aExpectedPageURI),
|
||||
"Check URIs are equal for the page which favicon changed");
|
||||
is(aValue, aExpectedFaviconURI.spec,
|
||||
"Check changed favicon URI is the expected");
|
||||
checkGuidForURI(aURI, aGUID);
|
||||
|
||||
if (aCallback) {
|
||||
aCallback();
|
||||
}
|
||||
}
|
||||
};
|
||||
aWindow.PlacesUtils.history.addObserver(historyObserver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously adds visits to a page, invoking a callback function when done.
|
||||
*
|
||||
|
@ -183,139 +146,7 @@ function addVisits(aPlaceInfo, aWindow, aCallback, aStack) {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the favicon for the given page matches the provided data.
|
||||
*
|
||||
* @param aPageURI
|
||||
* nsIURI object for the page to check.
|
||||
* @param aExpectedMimeType
|
||||
* Expected MIME type of the icon, for example "image/png".
|
||||
* @param aExpectedData
|
||||
* Expected icon data, expressed as an array of byte values.
|
||||
* @param aCallback
|
||||
* This function is called after the check finished.
|
||||
*/
|
||||
function checkFaviconDataForPage(aPageURI, aExpectedMimeType, aExpectedData,
|
||||
aWindow, aCallback) {
|
||||
aWindow.PlacesUtils.favicons.getFaviconDataForPage(aPageURI,
|
||||
function(aURI, aDataLen, aData, aMimeType) {
|
||||
is(aExpectedMimeType, aMimeType, "Check expected MimeType");
|
||||
is(aExpectedData.length, aData.length,
|
||||
"Check favicon data for the given page matches the provided data");
|
||||
checkGuidForURI(aPageURI);
|
||||
aCallback();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a guid was set in moz_places for a given uri.
|
||||
*
|
||||
* @param aURI
|
||||
* The uri to check.
|
||||
* @param [optional] aGUID
|
||||
* The expected guid in the database.
|
||||
*/
|
||||
function checkGuidForURI(aURI, aGUID) {
|
||||
let guid = doGetGuidForURI(aURI);
|
||||
if (aGUID) {
|
||||
doCheckValidPlacesGuid(aGUID);
|
||||
is(guid, aGUID, "Check equal guid for URIs");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the guid for a given uri.
|
||||
*
|
||||
* @param aURI
|
||||
* The uri to check.
|
||||
* @return the associated the guid.
|
||||
*/
|
||||
function doGetGuidForURI(aURI) {
|
||||
let stmt = DBConn().createStatement(
|
||||
`SELECT guid
|
||||
FROM moz_places
|
||||
WHERE url_hash = hash(:url) AND url = :url`
|
||||
);
|
||||
stmt.params.url = aURI.spec;
|
||||
ok(stmt.executeStep(), "Check get guid for uri from moz_places");
|
||||
let guid = stmt.row.guid;
|
||||
stmt.finalize();
|
||||
doCheckValidPlacesGuid(guid);
|
||||
return guid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if a given guid is valid for use in Places or not.
|
||||
*
|
||||
* @param aGuid
|
||||
* The guid to test.
|
||||
*/
|
||||
function doCheckValidPlacesGuid(aGuid) {
|
||||
ok(/^[a-zA-Z0-9\-_]{12}$/.test(aGuid), "Check guid for valid places");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database connection. If the Places connection is invalid it will
|
||||
* try to create a new connection.
|
||||
*
|
||||
* @param [optional] aForceNewConnection
|
||||
* Forces creation of a new connection to the database. When a
|
||||
* connection is asyncClosed it cannot anymore schedule async statements,
|
||||
* though connectionReady will keep returning true (Bug 726990).
|
||||
*
|
||||
* @return The database connection or null if unable to get one.
|
||||
*/
|
||||
function DBConn(aForceNewConnection) {
|
||||
let gDBConn;
|
||||
if (!aForceNewConnection) {
|
||||
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
|
||||
.DBConnection;
|
||||
if (db.connectionReady)
|
||||
return db;
|
||||
}
|
||||
|
||||
// If the Places database connection has been closed, create a new connection.
|
||||
if (!gDBConn || aForceNewConnection) {
|
||||
let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
file.append("places.sqlite");
|
||||
let dbConn = gDBConn = Services.storage.openDatabase(file);
|
||||
|
||||
// Be sure to cleanly close this connection.
|
||||
Services.obs.addObserver(function DBCloseCallback(aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(DBCloseCallback, aTopic);
|
||||
dbConn.asyncClose();
|
||||
}, "profile-before-change");
|
||||
}
|
||||
|
||||
return gDBConn.connectionReady ? gDBConn : null;
|
||||
}
|
||||
|
||||
function whenNewWindowLoaded(aOptions, aCallback) {
|
||||
BrowserTestUtils.waitForNewWindow().then(aCallback);
|
||||
OpenBrowserWindow(aOptions);
|
||||
}
|
||||
|
||||
function waitForCondition(condition, nextTest, errorMsg) {
|
||||
let tries = 0;
|
||||
let interval = setInterval(function() {
|
||||
if (tries >= 30) {
|
||||
ok(false, errorMsg);
|
||||
moveOn();
|
||||
}
|
||||
let conditionPassed;
|
||||
try {
|
||||
conditionPassed = condition();
|
||||
} catch (e) {
|
||||
ok(false, e + "\n" + e.stack);
|
||||
conditionPassed = false;
|
||||
}
|
||||
if (conditionPassed) {
|
||||
moveOn();
|
||||
}
|
||||
tries++;
|
||||
}, 200);
|
||||
function moveOn() {
|
||||
clearInterval(interval);
|
||||
nextTest();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This file tests the normal operation of setAndFetchFaviconForPage.
|
||||
|
||||
let gTests = [
|
||||
{
|
||||
desc: "Normal test",
|
||||
href: "http://example.com/normal",
|
||||
loadType: PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
async setup() {
|
||||
await PlacesTestUtils.addVisits({uri: this.href, transition: TRANSITION_TYPED});
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Bookmarked about: uri",
|
||||
href: "about:testAboutURI_bookmarked",
|
||||
loadType: PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
async setup() {
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: this.href
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Bookmarked in private window",
|
||||
href: "http://example.com/privateBrowsing_bookmarked",
|
||||
loadType: PlacesUtils.favicons.FAVICON_LOAD_PRIVATE,
|
||||
async setup() {
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: this.href
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
desc: "Bookmarked with disabled history",
|
||||
href: "http://example.com/disabledHistory_bookmarked",
|
||||
loadType: PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
async setup() {
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: this.href
|
||||
});
|
||||
Services.prefs.setBoolPref("places.history.enabled", false);
|
||||
},
|
||||
clean() {
|
||||
Services.prefs.setBoolPref("places.history.enabled", true);
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
add_task(async function() {
|
||||
let faviconURI = SMALLPNG_DATA_URI;
|
||||
let faviconMimeType = "image/png";
|
||||
|
||||
registerCleanupFunction(async function() {
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
await PlacesUtils.history.clear();
|
||||
});
|
||||
|
||||
for (let test of gTests) {
|
||||
info(test.desc);
|
||||
let pageURI = Services.io.newURI(test.href);
|
||||
|
||||
await test.setup();
|
||||
|
||||
let pageGuid;
|
||||
let promise = PlacesTestUtils.waitForNotification("onPageChanged", (uri, prop, value, guid) => {
|
||||
pageGuid = guid;
|
||||
return prop == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
uri.equals(pageURI) &&
|
||||
value == faviconURI.spec;
|
||||
}, "history");
|
||||
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, faviconURI,
|
||||
true, test.private, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
await promise;
|
||||
|
||||
Assert.equal(pageGuid, await PlacesTestUtils.fieldInDB(pageURI, "guid"),
|
||||
"Page guid is correct");
|
||||
let {dataLen, data, mimeType} = await PlacesUtils.promiseFaviconData(pageURI.spec);
|
||||
Assert.equal(faviconMimeType, mimeType, "Check expected MimeType");
|
||||
Assert.equal(SMALLPNG_DATA_LEN, data.length,
|
||||
"Check favicon data for the given page matches the provided data");
|
||||
Assert.equal(dataLen, data.length,
|
||||
"Check favicon dataLen for the given page matches the provided data");
|
||||
|
||||
if (test.clean) {
|
||||
await test.clean();
|
||||
}
|
||||
}
|
||||
});
|
|
@ -0,0 +1,97 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* This file tests setAndFetchFaviconForPage when it is called with invalid
|
||||
* arguments, and when no favicon is stored for the given arguments.
|
||||
*/
|
||||
|
||||
let faviconURI = Services.io.newURI("http://example.org/tests/toolkit/components/places/tests/browser/favicon-normal16.png");
|
||||
add_task(async function() {
|
||||
registerCleanupFunction(async function() {
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
await PlacesUtils.history.clear();
|
||||
});
|
||||
|
||||
// We'll listen for favicon changes for the whole test, to ensure only the
|
||||
// last one will send a notification. Due to thread serialization, at that
|
||||
// point we can be sure previous calls didn't send a notification.
|
||||
let lastPageURI = Services.io.newURI("http://example.com/verification");
|
||||
let promiseIconChanged = PlacesTestUtils.waitForNotification("onPageChanged", (uri, prop, value) => {
|
||||
return prop == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
uri.equals(lastPageURI) &&
|
||||
value == SMALLPNG_DATA_URI.spec;
|
||||
}, "history");
|
||||
|
||||
info("Test null page uri");
|
||||
Assert.throws(() => {
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(null, faviconURI,
|
||||
true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
}, /NS_ERROR_ILLEGAL_VALUE/, "Exception expected because aPageURI is null");
|
||||
|
||||
info("Test null favicon uri");
|
||||
Assert.throws(() => {
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
Services.io.newURI("http://example.com/null_faviconURI"), null,
|
||||
true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
null, Services.scriptSecurityManager.getSystemPrincipal());
|
||||
}, /NS_ERROR_ILLEGAL_VALUE/, "Exception expected because aFaviconURI is null.");
|
||||
|
||||
info("Test about uri");
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
Services.io.newURI("about:testAboutURI"), faviconURI,
|
||||
true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
|
||||
null, Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
info("Test private browsing non bookmarked uri");
|
||||
let pageURI = Services.io.newURI("http://example.com/privateBrowsing");
|
||||
await PlacesTestUtils.addVisits({ uri: pageURI, transitionType: TRANSITION_TYPED });
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI, faviconURI, true,
|
||||
PlacesUtils.favicons.FAVICON_LOAD_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
info("Test disabled history");
|
||||
pageURI = Services.io.newURI("http://example.com/disabledHistory");
|
||||
await PlacesTestUtils.addVisits({ uri: pageURI, transition: TRANSITION_TYPED });
|
||||
Services.prefs.setBoolPref("places.history.enabled", false);
|
||||
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI,
|
||||
faviconURI, true,
|
||||
PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
// The setAndFetchFaviconForPage function calls CanAddURI synchronously, thus
|
||||
// we can set the preference back to true immediately.
|
||||
Services.prefs.setBoolPref("places.history.enabled", true);
|
||||
|
||||
info("Test error icon");
|
||||
// This error icon must stay in sync with FAVICON_ERRORPAGE_URL in
|
||||
// nsIFaviconService.idl, aboutCertError.xhtml and netError.xhtml.
|
||||
let faviconErrorPageURI =
|
||||
Services.io.newURI("chrome://global/skin/icons/warning-16.png");
|
||||
pageURI = Services.io.newURI("http://example.com/errorIcon");
|
||||
await PlacesTestUtils.addVisits({ uri: pageURI, transition: TRANSITION_TYPED });
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(pageURI,
|
||||
faviconErrorPageURI, true,
|
||||
PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
info("Test nonexisting page");
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(
|
||||
Services.io.newURI("http://example.com/nonexistingPage"), faviconURI,
|
||||
true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
info("Final sanity check");
|
||||
// This is the only test that should cause the waitForFaviconChanged
|
||||
// callback to be invoked.
|
||||
await PlacesTestUtils.addVisits({ uri: lastPageURI, transition: TRANSITION_TYPED });
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(lastPageURI,
|
||||
SMALLPNG_DATA_URI, true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
await promiseIconChanged;
|
||||
|
||||
});
|
|
@ -0,0 +1,71 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// This file tests setAndFetchFaviconForPage on bookmarked redirects.
|
||||
|
||||
add_task(async function same_host_redirect() {
|
||||
// Add a bookmarked page that redirects to another page, set a favicon on the
|
||||
// latter and check the former gets it too, if they are in the same host.
|
||||
let srcUrl = "http://bookmarked.com/";
|
||||
let destUrl = "https://other.bookmarked.com/";
|
||||
await PlacesTestUtils.addVisits([
|
||||
{ uri: srcUrl, transition: TRANSITION_LINK },
|
||||
{ uri: destUrl, transition: TRANSITION_REDIRECT_TEMPORARY, referrer: srcUrl }
|
||||
]);
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: srcUrl
|
||||
});
|
||||
|
||||
registerCleanupFunction(async function() {
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
await PlacesUtils.history.clear();
|
||||
});
|
||||
|
||||
let promise = PlacesTestUtils.waitForNotification("onPageChanged", (uri, prop, value, guid) => {
|
||||
return prop == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
uri.spec == srcUrl &&
|
||||
value == SMALLPNG_DATA_URI.spec;
|
||||
}, "history");
|
||||
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(Services.io.newURI(destUrl),
|
||||
SMALLPNG_DATA_URI, true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
await promise;
|
||||
|
||||
// The favicon should be set also on the bookmarked url that redirected.
|
||||
let {dataLen} = await PlacesUtils.promiseFaviconData(srcUrl);
|
||||
Assert.equal(dataLen, SMALLPNG_DATA_LEN, "Check favicon dataLen");
|
||||
});
|
||||
|
||||
add_task(async function other_host_redirect() {
|
||||
// Add a bookmarked page that redirects to another page, set a favicon on the
|
||||
// latter and check the former gets it too, if they are in the same host.
|
||||
let srcUrl = "http://first.com/";
|
||||
let destUrl = "https://notfirst.com/";
|
||||
await PlacesTestUtils.addVisits([
|
||||
{ uri: srcUrl, transition: TRANSITION_LINK },
|
||||
{ uri: destUrl, transition: TRANSITION_REDIRECT_TEMPORARY, referrer: srcUrl }
|
||||
]);
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: srcUrl
|
||||
});
|
||||
|
||||
let promise = Promise.race([
|
||||
PlacesTestUtils.waitForNotification("onPageChanged", (uri, prop, value, guid) => {
|
||||
return prop == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON &&
|
||||
uri.spec == srcUrl &&
|
||||
value == SMALLPNG_DATA_URI.spec;
|
||||
}, "history"),
|
||||
new Promise((resolve, reject) => do_timeout(300, () => reject(new Error("timeout"))))
|
||||
]);
|
||||
|
||||
PlacesUtils.favicons.setAndFetchFaviconForPage(Services.io.newURI(destUrl),
|
||||
SMALLPNG_DATA_URI, true, PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
await Assert.rejects(promise, /timeout/);
|
||||
});
|
|
@ -41,4 +41,7 @@ support-files =
|
|||
[test_replaceFaviconData.js]
|
||||
[test_replaceFaviconDataFromDataURL.js]
|
||||
[test_root_icons.js]
|
||||
[test_setAndFetchFaviconForPage.js]
|
||||
[test_setAndFetchFaviconForPage_failures.js]
|
||||
[test_setAndFetchFaviconForPage_redirects.js]
|
||||
[test_svg_favicon.js]
|
||||
|
|
|
@ -47,6 +47,8 @@ XPCOMUtils.defineLazyGetter(this, "SMALLPNG_DATA_URI", function() {
|
|||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAA" +
|
||||
"AAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==");
|
||||
});
|
||||
const SMALLPNG_DATA_LEN = 67;
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "SMALLSVG_DATA_URI", function() {
|
||||
return NetUtil.newURI(
|
||||
"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy5" +
|
||||
|
|
|
@ -31,11 +31,11 @@ add_task(async function test_remove_single() {
|
|||
let removeArg = await filter(uri);
|
||||
|
||||
if (options.addBookmark) {
|
||||
PlacesUtils.bookmarks.insertBookmark(
|
||||
PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"test bookmark");
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: uri,
|
||||
title: "test bookmark"
|
||||
});
|
||||
}
|
||||
|
||||
let shouldRemove = !options.addBookmark;
|
||||
|
|
|
@ -44,11 +44,11 @@ add_task(async function test_remove_many() {
|
|||
await PlacesTestUtils.addVisits(page);
|
||||
page.guid = do_get_guid_for_uri(uri);
|
||||
if (hasBookmark) {
|
||||
PlacesUtils.bookmarks.insertBookmark(
|
||||
PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"test bookmark " + i);
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: uri,
|
||||
title: "test bookmark " + i
|
||||
});
|
||||
}
|
||||
Assert.ok(page_in_database(uri), "Page added");
|
||||
}
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const JS_NOW = Date.now();
|
||||
const DB_NOW = JS_NOW * 1000;
|
||||
const TEST_URI = uri("http://example.com/");
|
||||
|
@ -64,11 +67,11 @@ add_task(async function remove_visits_outside_bookmarked_uri() {
|
|||
}
|
||||
await PlacesTestUtils.addVisits(visits);
|
||||
info("Bookmark the URI.");
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
TEST_URI,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"bookmark title");
|
||||
await PlacesTestUtils.promiseAsyncUpdates();
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: TEST_URI,
|
||||
title: "bookmark title"
|
||||
});
|
||||
|
||||
info("Remove visits using timerange outside the URI's visits.");
|
||||
let filter = {
|
||||
|
@ -160,11 +163,11 @@ add_task(async function remove_visits_bookmarked_uri() {
|
|||
}
|
||||
await PlacesTestUtils.addVisits(visits);
|
||||
info("Bookmark the URI.");
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
TEST_URI,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"bookmark title");
|
||||
await PlacesTestUtils.promiseAsyncUpdates();
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: TEST_URI,
|
||||
title: "bookmark title"
|
||||
});
|
||||
|
||||
info("Remove the 5 most recent visits.");
|
||||
let filter = {
|
||||
|
@ -248,10 +251,11 @@ add_task(async function remove_all_visits_bookmarked_uri() {
|
|||
}
|
||||
await PlacesTestUtils.addVisits(visits);
|
||||
info("Bookmark the URI.");
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
TEST_URI,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
"bookmark title");
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: TEST_URI,
|
||||
title: "bookmark title"
|
||||
});
|
||||
await PlacesTestUtils.promiseAsyncUpdates();
|
||||
let initialFrecency = frecencyForUrl(TEST_URI);
|
||||
|
||||
|
|
|
@ -145,41 +145,43 @@ add_task(function visits_searchterm_query() {
|
|||
});
|
||||
});
|
||||
|
||||
add_task(function pages_searchterm_is_tag_query() {
|
||||
add_task(async function pages_searchterm_is_tag_query() {
|
||||
let [query, options] = newQueryWithOptions();
|
||||
query.searchTerms = "test-tag";
|
||||
testQueryContents(query, options, function(root) {
|
||||
compareArrayToResult([], root);
|
||||
gTestData.forEach(function(data) {
|
||||
let uri = NetUtil.newURI(data.uri);
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
data.title);
|
||||
PlacesUtils.tagging.tagURI(uri, ["test-tag"]);
|
||||
compareArrayToResult([data], root);
|
||||
PlacesUtils.tagging.untagURI(uri, ["test-tag"]);
|
||||
compareArrayToResult([], root);
|
||||
let root;
|
||||
testQueryContents(query, options, rv => root = rv);
|
||||
compareArrayToResult([], root);
|
||||
for (let data of gTestData) {
|
||||
let uri = NetUtil.newURI(data.uri);
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: uri,
|
||||
title: data.title
|
||||
});
|
||||
});
|
||||
PlacesUtils.tagging.tagURI(uri, ["test-tag"]);
|
||||
compareArrayToResult([data], root);
|
||||
PlacesUtils.tagging.untagURI(uri, ["test-tag"]);
|
||||
compareArrayToResult([], root);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function visits_searchterm_is_tag_query() {
|
||||
add_task(async function visits_searchterm_is_tag_query() {
|
||||
let [query, options] = newQueryWithOptions();
|
||||
query.searchTerms = "test-tag";
|
||||
options.resultType = Ci.nsINavHistoryQueryOptions.RESULTS_AS_VISIT;
|
||||
testQueryContents(query, options, function(root) {
|
||||
compareArrayToResult([], root);
|
||||
gTestData.forEach(function(data) {
|
||||
let uri = NetUtil.newURI(data.uri);
|
||||
PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
|
||||
uri,
|
||||
PlacesUtils.bookmarks.DEFAULT_INDEX,
|
||||
data.title);
|
||||
PlacesUtils.tagging.tagURI(uri, ["test-tag"]);
|
||||
compareArrayToResult([data], root);
|
||||
PlacesUtils.tagging.untagURI(uri, ["test-tag"]);
|
||||
compareArrayToResult([], root);
|
||||
let root;
|
||||
testQueryContents(query, options, rv => root = rv);
|
||||
compareArrayToResult([], root);
|
||||
for (let data of gTestData) {
|
||||
let uri = NetUtil.newURI(data.uri);
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
url: uri,
|
||||
title: data.title
|
||||
});
|
||||
});
|
||||
PlacesUtils.tagging.tagURI(uri, ["test-tag"]);
|
||||
compareArrayToResult([data], root);
|
||||
PlacesUtils.tagging.untagURI(uri, ["test-tag"]);
|
||||
compareArrayToResult([], root);
|
||||
}
|
||||
});
|
||||
|
|
Загрузка…
Ссылка в новой задаче