Dactyloidae/toolkit/components/places/tests/PlacesTestUtils.jsm

163 lines
5.5 KiB
JavaScript

"use strict";
this.EXPORTED_SYMBOLS = [
"PlacesTestUtils",
];
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.importGlobalProperties(["URL"]);
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Task",
"resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
this.PlacesTestUtils = Object.freeze({
/**
* Asynchronously adds visits to a page.
*
* @param aPlaceInfo
* Can be an nsIURI, in such a case a single LINK visit will be added.
* Otherwise can be an object describing the visit to add, or an array
* of these objects:
* { uri: nsIURI of the page,
* [optional] transition: one of the TRANSITION_* from nsINavHistoryService,
* [optional] title: title of the page,
* [optional] visitDate: visit date, either in microseconds from the epoch or as a date object
* [optional] referrer: nsIURI of the referrer for this visit
* }
*
* @return {Promise}
* @resolves When all visits have been added successfully.
* @rejects JavaScript exception.
*/
addVisits: Task.async(function* (placeInfo) {
let places = [];
let infos = [];
if (placeInfo instanceof Ci.nsIURI ||
placeInfo instanceof URL ||
typeof placeInfo == "string") {
places.push({ uri: placeInfo });
}
else if (Array.isArray(placeInfo)) {
places = places.concat(placeInfo);
} else if (typeof placeInfo == "object" && placeInfo.uri) {
places.push(placeInfo)
} else {
throw new Error("Unsupported type passed to addVisits");
}
// Create a PageInfo for each entry.
for (let place of places) {
let info = {url: place.uri};
info.title = (typeof place.title === "string") ? place.title : "test visit for " + info.url.spec ;
if (typeof place.referrer == "string") {
place.referrer = NetUtil.newURI(place.referrer);
} else if (place.referrer && place.referrer instanceof URL) {
place.referrer = NetUtil.newURI(place.referrer.href);
}
let visitDate = place.visitDate;
if (visitDate) {
if (!(visitDate instanceof Date)) {
visitDate = PlacesUtils.toDate(visitDate);
}
} else {
visitDate = new Date();
}
info.visits = [{
transition: place.transition,
date: visitDate,
referrer: place.referrer
}];
infos.push(info);
}
return PlacesUtils.history.insertMany(infos);
}),
/**
* Clear all history.
*
* @return {Promise}
* @resolves When history was cleared successfully.
* @rejects JavaScript exception.
*/
clearHistory() {
let expirationFinished = new Promise(resolve => {
Services.obs.addObserver(function observe(subj, topic, data) {
Services.obs.removeObserver(observe, topic);
resolve();
}, PlacesUtils.TOPIC_EXPIRATION_FINISHED, false);
});
return Promise.all([expirationFinished, PlacesUtils.history.clear()]);
},
/**
* Waits for all pending async statements on the default connection.
*
* @return {Promise}
* @resolves When all pending async statements finished.
* @rejects Never.
*
* @note The result is achieved by asynchronously executing a query requiring
* a write lock. Since all statements on the same connection are
* serialized, the end of this write operation means that all writes are
* complete. Note that WAL makes so that writers don't block readers, but
* this is a problem only across different connections.
*/
promiseAsyncUpdates() {
return PlacesUtils.withConnectionWrapper("promiseAsyncUpdates", Task.async(function* (db) {
try {
yield db.executeCached("BEGIN EXCLUSIVE");
yield db.executeCached("COMMIT");
} catch (ex) {
// If we fail to start a transaction, it's because there is already one.
// In such a case we should not try to commit the existing transaction.
}
}));
},
/**
* Asynchronously checks if an address is found in the database.
* @param aURI
* nsIURI or address to look for.
*
* @return {Promise}
* @resolves Returns true if the page is found.
* @rejects JavaScript exception.
*/
isPageInDB: Task.async(function* (aURI) {
let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
let db = yield PlacesUtils.promiseDBConnection();
let rows = yield db.executeCached(
"SELECT id FROM moz_places WHERE url_hash = hash(:url) AND url = :url",
{ url });
return rows.length > 0;
}),
/**
* Asynchronously checks how many visits exist for a specified page.
* @param aURI
* nsIURI or address to look for.
*
* @return {Promise}
* @resolves Returns the number of visits found.
* @rejects JavaScript exception.
*/
visitsInDB: Task.async(function* (aURI) {
let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
let db = yield PlacesUtils.promiseDBConnection();
let rows = yield db.executeCached(
`SELECT count(*) FROM moz_historyvisits v
JOIN moz_places h ON h.id = v.place_id
WHERE url_hash = hash(:url) AND url = :url`,
{ url });
return rows[0].getResultByIndex(0);
})
});