Bug 693906 - Parse and use new compatibility ranges in AMO metadata ping. r=dtownsend

This commit is contained in:
Blair McBride 2011-12-02 15:28:15 +13:00
parent de766e6f69
commit 993f3e5da9
13 changed files with 1248 additions and 50 deletions

View File

@ -50,8 +50,11 @@ const PREF_EM_LAST_PLATFORM_VERSION = "extensions.lastPlatformVersion";
const PREF_EM_AUTOUPDATE_DEFAULT = "extensions.update.autoUpdateDefault";
const PREF_EM_STRICT_COMPATIBILITY = "extensions.strictCompatibility";
// Note: This has to be kept in sync with the same constant in AddonRepository.jsm
const STRICT_COMPATIBILITY_DEFAULT = true;
const TOOLKIT_ID = "toolkit@mozilla.org";
const VALID_TYPES_REGEXP = /^[\w\-]+$/;
Components.utils.import("resource://gre/modules/Services.jsm");
@ -235,6 +238,67 @@ AddonScreenshot.prototype = {
}
}
/**
* This represents a compatibility override for an addon.
*
* @param aType
* Overrride type - "compatible" or "incompatible"
* @param aMinVersion
* Minimum version of the addon to match
* @param aMaxVersion
* Maximum version of the addon to match
* @param aAppID
* Application ID used to match appMinVersion and appMaxVersion
* @param aAppMinVersion
* Minimum version of the application to match
* @param aAppMaxVersion
* Maximum version of the application to match
*/
function AddonCompatibilityOverride(aType, aMinVersion, aMaxVersion, aAppID,
aAppMinVersion, aAppMaxVersion) {
this.type = aType;
this.minVersion = aMinVersion;
this.maxVersion = aMaxVersion;
this.appID = aAppID;
this.appMinVersion = aAppMinVersion;
this.appMaxVersion = aAppMaxVersion;
}
AddonCompatibilityOverride.prototype = {
/**
* Type of override - "incompatible" or "compatible".
* Only "incompatible" is supported for now.
*/
type: null,
/**
* Min version of the addon to match.
*/
minVersion: null,
/**
* Max version of the addon to match.
*/
maxVersion: null,
/**
* Application ID to match.
*/
appID: null,
/**
* Min version of the application to match.
*/
appMinVersion: null,
/**
* Max version of the application to match.
*/
appMaxVersion: null
};
/**
* A type of add-on, used by the UI to determine how to display different types
* of add-ons.
@ -555,8 +619,13 @@ var AddonManagerInternal = {
let pendingUpdates = 1;
function notifyComplete() {
if (--pendingUpdates == 0)
Services.obs.notifyObservers(null, "addons-background-update-complete", null);
if (--pendingUpdates == 0) {
AddonManagerInternal.updateAddonRepositoryData(function BUC_updateAddonCallback() {
Services.obs.notifyObservers(null,
"addons-background-update-complete",
null);
});
}
}
let scope = {};
@ -715,7 +784,31 @@ var AddonManagerInternal = {
callProvider(provider, "updateAddonAppDisabledStates");
});
},
/**
* Notifies all providers that the repository has updated its data for
* installed add-ons.
*
* @param aCallback
* Function to call when operation is complete.
*/
updateAddonRepositoryData: function AMI_updateAddonRepositoryData(aCallback) {
if (!aCallback)
throw Components.Exception("Must specify aCallback",
Cr.NS_ERROR_INVALID_ARG);
new AsyncObjectCaller(this.providers, "updateAddonRepositoryData", {
nextObject: function(aCaller, aProvider) {
callProvider(aProvider,
"updateAddonRepositoryData",
null,
aCaller.callNext.bind(aCaller));
},
noMoreObjects: function(aCaller) {
safeCall(aCallback);
}
});
},
/**
* Asynchronously gets an AddonInstall for a URL.
*
@ -1225,6 +1318,8 @@ var AddonManagerPrivate = {
AddonScreenshot: AddonScreenshot,
AddonCompatibilityOverride: AddonCompatibilityOverride,
AddonType: AddonType
};

View File

@ -21,6 +21,7 @@
# Contributor(s):
# Dave Townsend <dtownsend@oxymoronical.com>
# Ben Parr <bparr@bparr.com>
# Blair McBride <bmcbride@mozilla.com>
#
# Alternatively, the contents of this file may be used under the terms of
# either the GNU General Public License Version 2 or later (the "GPL"), or
@ -74,6 +75,10 @@ XPCOMUtils.defineLazyGetter(this, "PREF_CHECK_COMPATIBILITY", function () {
#endif
});
const PREF_EM_STRICT_COMPATIBILITY = "extensions.strictCompatibility";
// Note: This has to be kept in sync with the same constant in AddonManager.jsm
const STRICT_COMPATIBILITY_DEFAULT = true;
const XMLURI_PARSE_ERROR = "http://www.mozilla.org/newlayout/xml/parsererror.xml";
const API_VERSION = "1.5";
@ -81,7 +86,9 @@ const DEFAULT_CACHE_TYPES = "extension,theme,locale,dictionary";
const KEY_PROFILEDIR = "ProfD";
const FILE_DATABASE = "addons.sqlite";
const DB_SCHEMA = 2;
const DB_SCHEMA = 3;
const TOOLKIT_ID = "toolkit@mozilla.org";
["LOG", "WARN", "ERROR"].forEach(function(aName) {
this.__defineGetter__(aName, function() {
@ -356,6 +363,12 @@ AddonSearchResult.prototype = {
*/
isPlatformCompatible: true,
/**
* Array of AddonCompatibilityOverride objects, that describe overrides for
* compatibility with an application versions.
**/
compatibilityOverrides: null,
/**
* True if the add-on has a secure means of updating
*/
@ -609,8 +622,8 @@ var AddonRepository = {
getAddonsToCache(aIds, function(aAddons) {
// Completely remove cache if there are no add-ons to cache
if (aAddons.length == 0) {
this._addons = null;
this._pendingCallbacks = null;
self._addons = null;
self._pendingCallbacks = null;
AddonDatabase.delete(aCallback);
return;
}
@ -744,12 +757,12 @@ var AddonRepository = {
let url = this._formatURLPref(PREF_GETADDONS_BYIDS, params);
let self = this;
function handleResults(aElements, aTotalResults) {
function handleResults(aElements, aTotalResults, aCompatData) {
// Don't use this._parseAddons() so that, for example,
// incompatible add-ons are not filtered out
let results = [];
for (let i = 0; i < aElements.length && results.length < self._maxResults; i++) {
let result = self._parseAddon(aElements[i]);
let result = self._parseAddon(aElements[i], null, aCompatData);
if (result == null)
continue;
@ -763,6 +776,24 @@ var AddonRepository = {
ids.splice(idIndex, 1);
}
// Include any compatibility overrides for addons not hosted by the
// remote repository.
for each (let addonCompat in aCompatData) {
if (addonCompat.hosted)
continue;
let addon = new AddonSearchResult(addonCompat.id);
// Compatibility overrides can only be for extensions.
addon.type = "extension";
addon.compatibilityOverrides = addonCompat.compatRanges;
let result = {
addon: addon,
xpiURL: null,
xpiHash: null
};
results.push(result);
}
// aTotalResults irrelevant
self._reportSuccess(results, -1);
}
@ -865,6 +896,14 @@ var AddonRepository = {
return (elementsList.length == 1) ? elementsList[0] : null;
},
// Get direct descendant by unique tag name.
// Returns null if not unique tag name.
_getUniqueDirectDescendant: function(aElement, aTagName) {
let elementsList = Array.filter(aElement.children,
function(aChild) aChild.tagName == aTagName);
return (elementsList.length == 1) ? elementsList[0] : null;
},
// Parse out trimmed text content. Returns null if text content empty.
_getTextContent: function(aElement) {
let textContent = aElement.textContent.trim();
@ -878,6 +917,14 @@ var AddonRepository = {
return (descendant != null) ? this._getTextContent(descendant) : null;
},
// Parse out trimmed text content of a direct descendant with the specified
// tag name.
// Returns null if the parsing unsuccessful.
_getDirectDescendantTextContent: function(aElement, aTagName) {
let descendant = this._getUniqueDirectDescendant(aElement, aTagName);
return (descendant != null) ? this._getTextContent(descendant) : null;
},
/*
* Creates an AddonSearchResult by parsing an <addon> element
*
@ -885,10 +932,13 @@ var AddonRepository = {
* The <addon> element to parse
* @param aSkip
* Object containing ids and sourceURIs of add-ons to skip.
* @param aCompatData
* Array of parsed addon_compatibility elements to accosiate with the
* resulting AddonSearchResult. Optional.
* @return Result object containing the parsed AddonSearchResult, xpiURL and
* xpiHash if the parsing was successful. Otherwise returns null.
*/
_parseAddon: function(aElement, aSkip) {
_parseAddon: function(aElement, aSkip, aCompatData) {
let skipIDs = (aSkip && aSkip.ids) ? aSkip.ids : [];
let skipSourceURIs = (aSkip && aSkip.sourceURIs) ? aSkip.sourceURIs : [];
@ -903,6 +953,9 @@ var AddonRepository = {
xpiHash: null
};
if (aCompatData && guid in aCompatData)
addon.compatibilityOverrides = aCompatData[guid].compatRanges;
let self = this;
for (let node = aElement.firstChild; node; node = node.nextSibling) {
if (!(node instanceof Ci.nsIDOMElement))
@ -1095,6 +1148,11 @@ var AddonRepository = {
checkCompatibility = Services.prefs.getBoolPref(PREF_CHECK_COMPATIBILITY);
} catch(e) { }
let strictCompatibility = STRICT_COMPATIBILITY_DEFAULT;
try {
strictCompatibility = Services.prefs.getBoolPref(PREF_EM_STRICT_COMPATIBILITY);
} catch (e) {}
function isSameApplication(aAppNode) {
return self._getTextContent(aAppNode) == Services.appinfo.ID;
}
@ -1119,7 +1177,8 @@ var AddonRepository = {
let currentVersion = Services.appinfo.version;
return (Services.vc.compare(minVersion, currentVersion) <= 0 &&
Services.vc.compare(currentVersion, maxVersion) <= 0);
((!strictCompatibility) ||
Services.vc.compare(currentVersion, maxVersion) <= 0));
});
// Ignore add-ons not compatible with this Application
@ -1131,7 +1190,9 @@ var AddonRepository = {
continue;
}
// Add-on meets all requirements, so parse out data
// Add-on meets all requirements, so parse out data.
// Don't pass in compatiblity override data, because that's only returned
// in GUID searches, which don't use _parseAddons().
let result = this._parseAddon(element, aSkip);
if (result == null)
continue;
@ -1186,6 +1247,83 @@ var AddonRepository = {
});
},
// Parses addon_compatibility nodes, that describe compatibility overrides.
_parseAddonCompatElement: function(aResultObj, aElement) {
let guid = this._getDescendantTextContent(aElement, "guid");
if (!guid)
return;
let compat = {id: guid};
compat.hosted = aElement.getAttribute("hosted") != "false";
function findMatchingAppRange(aNodes) {
let toolkitAppRange = null;
for (let i = 0; i < aNodes.length; i++) {
let node = aNodes[i];
let appID = this._getDescendantTextContent(node, "appID");
if (appID != Services.appinfo.ID && appID != TOOLKIT_ID)
continue;
let minVersion = this._getDescendantTextContent(node, "min_version");
let maxVersion = this._getDescendantTextContent(node, "max_version");
if (minVersion == null || maxVersion == null)
continue;
let appRange = { appID: appID,
appMinVersion: minVersion,
appMaxVersion: maxVersion };
// Only use Toolkit app ranges if no ranges match the application ID.
if (appID == TOOLKIT_ID)
toolkitAppRange = appRange;
else
return appRange;
}
return toolkitAppRange;
}
function parseRangeNode(aNode) {
let type = aNode.getAttribute("type");
// Only "incompatible" (blacklisting) is supported for now.
if (type != "incompatible")
return null;
let override = new AddonManagerPrivate.AddonCompatibilityOverride(type);
override.minVersion = this._getDirectDescendantTextContent(aNode, "min_version");
override.maxVersion = this._getDirectDescendantTextContent(aNode, "max_version");
if (!override.minVersion || !override.maxVersion)
return null;
let appRanges = aNode.querySelectorAll("compatible_applications > application");
let appRange = findMatchingAppRange.bind(this)(appRanges);
if (!appRange)
return null;
override.appID = appRange.appID;
override.appMinVersion = appRange.appMinVersion;
override.appMaxVersion = appRange.appMaxVersion;
return override;
}
let rangeNodes = aElement.querySelectorAll("version_ranges > version_range");
compat.compatRanges = Array.map(rangeNodes, parseRangeNode.bind(this))
.filter(function(aItem) !!aItem);
if (compat.compatRanges.length == 0)
return;
aResultObj[compat.id] = compat;
},
// Parses addon_compatibility elements.
_parseAddonCompatData: function(aElements) {
let compatData = {};
Array.forEach(aElements, this._parseAddonCompatElement.bind(this, compatData));
return compatData;
},
// Begins a new search if one isn't currently executing
_beginSearch: function(aURI, aMaxResults, aCallback, aHandleResults) {
if (this._searching || aURI == null || aMaxResults <= 0) {
@ -1227,7 +1365,10 @@ var AddonRepository = {
if (parsedTotalResults >= totalResults)
totalResults = parsedTotalResults;
aHandleResults(elements, totalResults);
let compatElements = documentElement.getElementsByTagName("addon_compatibility");
let compatData = self._parseAddonCompatData(compatElements);
aHandleResults(elements, totalResults, compatData);
}, false);
this._request.send(null);
},
@ -1271,7 +1412,31 @@ var AddonRepository = {
});
return Services.urlFormatter.formatURL(url);
},
// Find a AddonCompatibilityOverride that matches a given aAddonVersion and
// application/platform version.
findMatchingCompatOverride: function AR_findMatchingCompatOverride(aAddonVersion,
aCompatOverrides) {
for (let i = 0; i < aCompatOverrides.length; i++) {
let override = aCompatOverrides[i];
let appVersion = null;
if (override.appID == TOOLKIT_ID)
appVersion = Services.appinfo.platformVersion;
else
appVersion = Services.appinfo.version;
if (Services.vc.compare(override.minVersion, aAddonVersion) <= 0 &&
Services.vc.compare(aAddonVersion, override.maxVersion) <= 0 &&
Services.vc.compare(override.appMinVersion, appVersion) <= 0 &&
Services.vc.compare(appVersion, override.appMaxVersion) <= 0) {
return override;
}
}
return null;
}
};
AddonRepository.initialize();
@ -1300,6 +1465,11 @@ var AddonDatabase = {
"thumbnailURL, thumbnailWidth, thumbnailHeight, caption " +
"FROM screenshot ORDER BY addon_internal_id, num",
getAllCompatOverrides: "SELECT addon_internal_id, type, minVersion, " +
"maxVersion, appID, appMinVersion, appMaxVersion " +
"FROM compatibility_override " +
"ORDER BY addon_internal_id, num",
insertAddon: "INSERT INTO addon VALUES (NULL, :id, :type, :name, :version, " +
":creator, :creatorURL, :description, :fullDescription, " +
":developerComments, :eula, :iconURL, :homepageURL, :supportURL, " +
@ -1319,6 +1489,11 @@ var AddonDatabase = {
":num, :url, :width, :height, :thumbnailURL, " +
":thumbnailWidth, :thumbnailHeight, :caption)",
insertCompatibilityOverride: "INSERT INTO compatibility_override VALUES " +
"(:addon_internal_id, :num, :type, " +
":minVersion, :maxVersion, :appID, " +
":appMinVersion, :appMaxVersion)",
emptyAddon: "DELETE FROM addon"
},
@ -1384,29 +1559,42 @@ var AddonDatabase = {
if (dbMissing)
this._createSchema();
switch (this.connection.schemaVersion) {
case 0:
this._createSchema();
break;
case 1:
try {
try {
switch (this.connection.schemaVersion) {
case 0:
LOG("Recreating database schema");
this._createSchema();
break;
case 1:
LOG("Upgrading database schema");
this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN width INTEGER");
this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN height INTEGER");
this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN thumbnailWidth INTEGER");
this.connection.executeSimpleSQL("ALTER TABLE screenshot ADD COLUMN thumbnailHeight INTEGER");
this._createIndices();
this.connection.schemaVersion = DB_SCHEMA;
} catch (e) {
ERROR("Failed to create database schema", e);
this.logSQLError(this.connection.lastError, this.connection.lastErrorString);
this.connection.rollbackTransaction();
case 2:
this.connection.createTable("compatibility_override",
"addon_internal_id INTEGER, " +
"num INTEGER, " +
"type TEXT, " +
"minVersion TEXT, " +
"maxVersion TEXT, " +
"appID TEXT, " +
"appMinVersion TEXT, " +
"appMaxVersion TEXT, " +
"PRIMARY KEY (addon_internal_id, num)");
this._createIndices();
this._createTriggers();
this.connection.schemaVersion = DB_SCHEMA;
case 3:
break;
default:
return tryAgain();
}
break;
case 2:
break;
default:
return tryAgain();
}
} catch (e) {
ERROR("Failed to create database schema", e);
this.logSQLError(this.connection.lastError, this.connection.lastErrorString);
this.connection.rollbackTransaction();
return tryAgain();
}
return this.connection;
@ -1595,6 +1783,38 @@ var AddonDatabase = {
return;
}
getAllCompatOverrides();
}
});
}
function getAllCompatOverrides() {
self.getAsyncStatement("getAllCompatOverrides").executeAsync({
handleResult: function(aResults) {
let row = null;
while (row = aResults.getNextRow()) {
let addon_internal_id = row.getResultByName("addon_internal_id");
if (!(addon_internal_id in addons)) {
WARN("Found a compatibility override not linked to an add-on in database");
continue;
}
let addon = addons[addon_internal_id];
if (!addon.compatibilityOverrides)
addon.compatibilityOverrides = [];
addon.compatibilityOverrides.push(self._makeCompatOverrideFromAsyncRow(row));
}
},
handleError: self.asyncErrorLogger,
handleCompletion: function(aReason) {
if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) {
ERROR("Error retrieving compatibility overrides from database. Returning empty results");
aCallback({});
return;
}
let returnedAddons = {};
for each (let addon in addons)
returnedAddons[addon.id] = addon;
@ -1677,8 +1897,9 @@ var AddonDatabase = {
let internal_id = null;
this.connection.beginTransaction();
// Simultaneously insert the developers and screenshots of the add-on
function insertDevelopersAndScreenshots() {
// Simultaneously insert the developers, screenshots, and compatibility
// overrides of the add-on.
function insertAdditionalData() {
let stmts = [];
// Initialize statement and parameters for inserting an array
@ -1696,11 +1917,15 @@ var AddonDatabase = {
stmts.push(stmt);
}
// Initialize statements to insert developers and screenshots
// Initialize statements to insert developers, screenshots, and
// compatibility overrides
initializeArrayInsert("insertDeveloper", aAddon.developers,
self._addDeveloperParams);
initializeArrayInsert("insertScreenshot", aAddon.screenshots,
self._addScreenshotParams);
initializeArrayInsert("insertCompatibilityOverride",
aAddon.compatibilityOverrides,
self._addCompatOverrideParams);
// Immediately call callback if nothing to insert
if (stmts.length == 0) {
@ -1714,7 +1939,7 @@ var AddonDatabase = {
handleError: self.asyncErrorLogger,
handleCompletion: function(aReason) {
if (aReason != Ci.mozIStorageStatementCallback.REASON_FINISHED) {
ERROR("Error inserting developers and screenshots into database. Attempting to continue");
ERROR("Error inserting additional addon metadata into database. Attempting to continue");
self.connection.rollbackTransaction();
}
else {
@ -1740,7 +1965,7 @@ var AddonDatabase = {
}
internal_id = self.connection.lastInsertRowID;
insertDevelopersAndScreenshots();
insertAdditionalData();
}
});
},
@ -1826,6 +2051,35 @@ var AddonDatabase = {
aParams.addParams(bp);
},
/**
* Add compatibility override parameters to the specified
* mozIStorageBindingParamsArray.
*
* @param aParams
* The mozIStorageBindingParamsArray to add the parameters to
* @param aInternalID
* The internal_id of the add-on that this override is for
* @param aOverride
* The override to make the parameters from
* @param aIndex
* The index of this override
*/
_addCompatOverrideParams: function AD_addCompatOverrideParams(aParams,
aInternalID,
aOverride,
aIndex) {
let bp = aParams.newBindingParams();
bp.bindByName("addon_internal_id", aInternalID);
bp.bindByName("num", aIndex);
bp.bindByName("type", aOverride.type);
bp.bindByName("minVersion", aOverride.minVersion);
bp.bindByName("maxVersion", aOverride.maxVersion);
bp.bindByName("appID", aOverride.appID);
bp.bindByName("appMinVersion", aOverride.appMinVersion);
bp.bindByName("appMaxVersion", aOverride.appMaxVersion);
aParams.addParams(bp);
},
/**
* Make add-on from an asynchronous row
* Note: This add-on will be lacking both developers and screenshots
@ -1894,6 +2148,28 @@ var AddonDatabase = {
thumbnailWidth, thumbnailHeight, caption);
},
/**
* Make a CompatibilityOverride from an asynchronous row
*
* @param aRow
* The asynchronous row to use
* @return The created CompatibilityOverride
*/
_makeCompatOverrideFromAsyncRow: function AD_makeCompatOverrideFromAsyncRow(aRow) {
let type = aRow.getResultByName("type");
let minVersion = aRow.getResultByName("minVersion");
let maxVersion = aRow.getResultByName("maxVersion");
let appID = aRow.getResultByName("appID");
let appMinVersion = aRow.getResultByName("appMinVersion");
let appMaxVersion = aRow.getResultByName("appMaxVersion");
return new AddonManagerPrivate.AddonCompatibilityOverride(type,
minVersion,
maxVersion,
appID,
appMinVersion,
appMaxVersion);
},
/**
* Synchronously creates the schema in the database.
*/
@ -1950,13 +2226,19 @@ var AddonDatabase = {
"caption TEXT, " +
"PRIMARY KEY (addon_internal_id, num)");
this._createIndices();
this.connection.createTable("compatibility_override",
"addon_internal_id INTEGER, " +
"num INTEGER, " +
"type TEXT, " +
"minVersion TEXT, " +
"maxVersion TEXT, " +
"appID TEXT, " +
"appMinVersion TEXT, " +
"appMaxVersion TEXT, " +
"PRIMARY KEY (addon_internal_id, num)");
this.connection.executeSimpleSQL("CREATE TRIGGER delete_addon AFTER DELETE " +
"ON addon BEGIN " +
"DELETE FROM developer WHERE addon_internal_id=old.internal_id; " +
"DELETE FROM screenshot WHERE addon_internal_id=old.internal_id; " +
"END");
this._createIndices();
this._createTriggers();
this.connection.schemaVersion = DB_SCHEMA;
this.connection.commitTransaction();
@ -1968,6 +2250,19 @@ var AddonDatabase = {
}
},
/**
* Synchronously creates the triggers in the database.
*/
_createTriggers: function AD__createTriggers() {
this.connection.executeSimpleSQL("DROP TRIGGER IF EXISTS delete_addon");
this.connection.executeSimpleSQL("CREATE TRIGGER delete_addon AFTER DELETE " +
"ON addon BEGIN " +
"DELETE FROM developer WHERE addon_internal_id=old.internal_id; " +
"DELETE FROM screenshot WHERE addon_internal_id=old.internal_id; " +
"DELETE FROM compatibility_override WHERE addon_internal_id=old.internal_id; " +
"END");
},
/**
* Synchronously creates the indices in the database.
*/
@ -1976,5 +2271,7 @@ var AddonDatabase = {
"ON developer (addon_internal_id)");
this.connection.executeSimpleSQL("CREATE INDEX IF NOT EXISTS screenshot_idx " +
"ON screenshot (addon_internal_id)");
this.connection.executeSimpleSQL("CREATE INDEX IF NOT EXISTS compatibility_override_idx " +
"ON compatibility_override (addon_internal_id)");
}
};

View File

@ -3346,6 +3346,36 @@ var XPIProvider = {
}, this);
},
/**
* Update the repositoryAddon property for all add-ons.
*
* @param aCallback
* Function to call when operation is complete.
*/
updateAddonRepositoryData: function XPI_updateAddonRepositoryData(aCallback) {
let self = this;
XPIDatabase.getVisibleAddons(null, function UARD_getVisibleAddonsCallback(aAddons) {
let pending = aAddons.length;
function notifyComplete() {
if (--pending == 0)
aCallback();
}
aAddons.forEach(function UARD_forEachCallback(aAddon) {
AddonRepository.getCachedAddonByID(aAddon.id,
function UARD_getCachedAddonCallback(aRepoAddon) {
if (aRepoAddon) {
aAddon._repositoryAddon = aRepoAddon;
aAddon.compatibilityOverrides = aRepoAddon.compatibilityOverrides;
self.updateAddonDisabledState(aAddon);
}
notifyComplete();
});
});
});
},
/**
* When the previously selected theme is removed this method will be called
* to enable the default theme.
@ -4052,6 +4082,9 @@ AsyncAddonListCallback.prototype = {
XPIDatabase.makeAddonFromRowAsync(row, function(aAddon) {
function completeAddon(aRepositoryAddon) {
aAddon._repositoryAddon = aRepositoryAddon;
aAddon.compatibilityOverrides = aRepositoryAddon ?
aRepositoryAddon.compatibilityOverrides :
null;
self.addons.push(aAddon);
if (self.complete && self.addons.length == self.count)
self.callback(self.addons);
@ -6152,6 +6185,7 @@ AddonInstall.prototype = {
AddonRepository.getCachedAddonByID(aAddon.id, function(aRepoAddon) {
if (aRepoAddon) {
aAddon._repositoryAddon = aRepoAddon;
aAddon.compatibilityOverrides = aRepoAddon.compatibilityOverrides;
aCallback();
return;
}
@ -6160,6 +6194,9 @@ AddonInstall.prototype = {
AddonRepository.cacheAddons([aAddon.id], function() {
AddonRepository.getCachedAddonByID(aAddon.id, function(aRepoAddon) {
aAddon._repositoryAddon = aRepoAddon;
aAddon.compatibilityOverrides = aRepoAddon ?
aRepoAddon.compatibilityOverrides :
null;
aCallback();
});
});
@ -7149,6 +7186,17 @@ AddonInternal.prototype = {
if (this.type == "extension" && !AddonManager.strictCompatibility &&
!this.strictCompatibility && !this.hasBinaryComponents) {
// The repository can specify compatibility overrides.
// Note: For now, only blacklisting is supported by overrides.
if (this._repositoryAddon &&
this._repositoryAddon.compatibilityOverrides) {
let overrides = this._repositoryAddon.compatibilityOverrides;
let override = AddonRepository.findMatchingCompatOverride(this.version,
overrides);
if (override && override.type == "incompatible")
return false;
}
// Extremely old extensions should not be compatible by default.
let minCompatVersion;
if (app.id == Services.appinfo.ID)
@ -7252,7 +7300,7 @@ AddonInternal.prototype = {
importMetadata: function(aObj) {
["targetApplications", "userDisabled", "softDisabled", "existingAddonID",
"sourceURI", "releaseNotesURI", "installDate", "updateDate",
"applyBackgroundUpdates"].forEach(function(aProp) {
"applyBackgroundUpdates", "compatibilityOverrides"].forEach(function(aProp) {
if (!(aProp in aObj))
return;
@ -7368,7 +7416,7 @@ function AddonWrapper(aAddon) {
["id", "syncGUID", "version", "type", "isCompatible", "isPlatformCompatible",
"providesUpdatesSecurely", "blocklistState", "blocklistURL", "appDisabled",
"softDisabled", "skinnable", "size", "foreignInstall", "hasBinaryComponents",
"strictCompatibility"].forEach(function(aProp) {
"strictCompatibility", "compatibilityOverrides"].forEach(function(aProp) {
this.__defineGetter__(aProp, function() aAddon[aProp]);
}, this);

View File

@ -39,6 +39,7 @@ function test() {
requestLongerTimeout(2);
// Turn on searching for this test
Services.prefs.setIntPref(PREF_SEARCH_MAXRESULTS, 15);
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
waitForExplicitFinish();
@ -621,6 +622,28 @@ add_test(function() {
});
});
// Tests that compatible-by-default addons are shown if strict compatibility checking is disabled
add_test(function() {
restart_manager(gManagerWindow, null, function(aWindow) {
gManagerWindow = aWindow;
gCategoryUtilities = new CategoryUtilities(gManagerWindow);
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, false);
search("incompatible", false, function() {
var item = get_addon_item("remote5");
is_element_visible(item, "Incompatible addon should be visible");
isnot(item.getAttribute("notification"), "warning", "Compatibility warning should not be shown");
var item = get_addon_item("remote6");
is(item, null, "Addon incompatible with the product should not be visible");
Services.prefs.setBoolPref(PREF_STRICT_COMPAT, true);
run_next_test();
});
});
});
// Tests that restarting the manager doesn't change search results
add_test(function() {
restart_manager(gManagerWindow, null, function(aWindow) {

View File

@ -115,5 +115,68 @@
</preview>
</previews>
</addon>
<addon_compatibility hosted="true" id="123">
<guid>test_AddonRepository_1@tests.mozilla.org</guid>
<name>PASS</name>
<version_ranges>
<!-- Will be included -->
<version_range type="incompatible">
<min_version>0.1</min_version>
<max_version>0.2</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>3.0</min_version>
<max_version>4.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Will be included -->
<version_range type="incompatible">
<min_version>0.2</min_version>
<max_version>0.3</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>5.0</min_version>
<max_version>6.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Won't be included - invalid type attribute -->
<version_range type="unknown">
<min_version>9</min_version>
<max_version>10</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>10.0</min_version>
<max_version>11.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Won't be included - no matching appID -->
<version_range type="incompatible">
<min_version>0.2</min_version>
<max_version>0.3</max_version>
<compatible_applications>
<application>
<name>Unknown App</name>
<application_id>123</application_id>
<min_version>1.0</min_version>
<max_version>999.0</max_version>
<appID>unknown-app@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
</searchresults>

View File

@ -62,6 +62,69 @@
<install size="5555">http://localhost:4444/addons/test_AddonRepository_2.xpi</install>
</addon>
<addon_compatibility hosted="true" id="123">
<guid>test1@tests.mozilla.org</guid>
<name>PASS</name>
<version_ranges>
<!-- Will be included -->
<version_range type="incompatible">
<min_version>0.1</min_version>
<max_version>0.2</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>3.0</min_version>
<max_version>4.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Will be included -->
<version_range type="incompatible">
<min_version>0.2</min_version>
<max_version>0.3</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>5.0</min_version>
<max_version>6.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Won't be included - invalid type attribute -->
<version_range type="unknown">
<min_version>9</min_version>
<max_version>10</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<application_id>666</application_id>
<min_version>10.0</min_version>
<max_version>11.0</max_version>
<appID>xpcshell@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
<!-- Won't be included - no matching appID -->
<version_range type="incompatible">
<min_version>0.2</min_version>
<max_version>0.3</max_version>
<compatible_applications>
<application>
<name>Unknown App</name>
<application_id>123</application_id>
<min_version>1.0</min_version>
<max_version>999.0</max_version>
<appID>unknown-app@tests.mozilla.org</appID>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<!-- Fails because guid matches previously successful result -->
<addon>
<name>FAIL</name>

View File

@ -0,0 +1,228 @@
<?xml version="1.0" encoding="utf-8" ?>
<searchresults total_results="9">
<addon>
<name>Test addon 2</name>
<type id="1">Extension</type>
<guid>addon2@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon>
<name>Test addon 3</name>
<type id="1">Extension</type>
<guid>addon3@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 3</name>
<guid>addon3@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.9</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 4</name>
<type id="1">Extension</type>
<guid>addon4@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 4</name>
<guid>addon4@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.9</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 5</name>
<type id="1">Extension</type>
<guid>addon5@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 5</name>
<guid>addon5@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.9</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>Unknown App</name>
<appID>unknown-app@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 6</name>
<type id="1">Extension</type>
<guid>addon6@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 6</name>
<guid>addon6@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.5</min_version>
<max_version>0.9</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 7</name>
<type id="1">Extension</type>
<guid>addon7@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 7</name>
<guid>addon7@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.5</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>0.1</min_version>
<max_version>0.9</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon>
<name>Test addon 8</name>
<type id="1">Extension</type>
<guid>addon8@tests.mozilla.org</guid>
<version>1.0</version>
</addon>
<addon_compatibility hosted="true">
<name>Test addon 8</name>
<guid>addon8@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>6</min_version>
<max_version>6.2</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>0.9</min_version>
<max_version>9</max_version>
</application>
</compatible_applications>
</version_range>
<version_range type="incompatible">
<min_version>0.5</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>0.1</min_version>
<max_version>9</max_version>
</application>
<application>
<name>Unknown app</name>
<appID>unknown-app@tests.mozilla.org</appID>
<min_version>0.1</min_version>
<max_version>9</max_version>
</application>
</compatible_applications>
</version_range>
<version_range type="incompatible">
<min_version>0.1</min_version>
<max_version>0.2</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>0.1</min_version>
<max_version>0.9</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon_compatibility hosted="false">
<name>Test addon 9</name>
<guid>addon9@tests.mozilla.org</guid>
<version_ranges>
<version_range type="incompatible">
<min_version>0.5</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
<addon_compatibility hosted="false">
<name>Test addon 10</name>
<guid>addon10@tests.mozilla.org</guid>
<version_ranges>
<version_range type="compatible">
<min_version>0.5</min_version>
<max_version>1.0</max_version>
<compatible_applications>
<application>
<name>XPCShell</name>
<appID>xpcshell@tests.mozilla.org</appID>
<min_version>1</min_version>
<max_version>2</max_version>
</application>
</compatible_applications>
</version_range>
</version_ranges>
</addon_compatibility>
</searchresults>

View File

@ -244,6 +244,12 @@ function do_check_addon(aActualAddon, aExpectedAddon, aProperties) {
do_check_eq(actualValue.getTime(), expectedValue.getTime());
break;
case "compatibilityOverrides":
do_check_eq(actualValue.length, expectedValue.length);
for (let i = 0; i < actualValue.length; i++)
do_check_compatibilityoverride(actualValue[i], expectedValue[i]);
break;
default:
if (actualValue !== expectedValue)
do_throw("Failed for " + aProperty + " for add-on " + aExpectedAddon.id +
@ -285,6 +291,24 @@ function do_check_screenshot(aActual, aExpected) {
do_check_eq(aActual.caption, aExpected.caption);
}
/**
* Check that the actual compatibility override is the same as the expected
* compatibility override.
*
* @param aAction
* The actual compatibility override to check.
* @param aExpected
* The expected compatibility override to check against.
*/
function do_check_compatibilityoverride(aActual, aExpected) {
do_check_eq(aActual.type, aExpected.type);
do_check_eq(aActual.minVersion, aExpected.minVersion);
do_check_eq(aActual.maxVersion, aExpected.maxVersion);
do_check_eq(aActual.appID, aExpected.appID);
do_check_eq(aActual.appMinVersion, aExpected.appMinVersion);
do_check_eq(aActual.appMaxVersion, aExpected.appMaxVersion);
}
/**
* Starts up the add-on manager as if it was started by the application.
*

View File

@ -36,7 +36,8 @@ var ADDON_PROPERTIES = ["id", "type", "version", "creator", "developers",
"averageRating", "reviewCount", "reviewURL",
"totalDownloads", "weeklyDownloads", "dailyUsers",
"sourceURI", "repositoryStatus", "size", "updateDate",
"purchaseURL", "purchaseAmount", "purchaseDisplayAmount"];
"purchaseURL", "purchaseAmount", "purchaseDisplayAmount",
"compatibilityOverrides"];
// Results of getAddonsByIDs
var GET_RESULTS = [{
@ -82,7 +83,22 @@ var GET_RESULTS = [{
sourceURI: BASE_URL + INSTALL_URL2,
repositoryStatus: 8,
size: 5555,
updateDate: new Date(1265033045000)
updateDate: new Date(1265033045000),
compatibilityOverrides: [{
type: "incompatible",
minVersion: 0.1,
maxVersion: 0.2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 3.0,
appMaxVersion: 4.0
}, {
type: "incompatible",
minVersion: 0.2,
maxVersion: 0.3,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 5.0,
appMaxVersion: 6.0
}]
}, {
id: "test_AddonRepository_1@tests.mozilla.org",
version: "1.4",
@ -176,7 +192,8 @@ var SEARCH_RESULTS = [{
sourceURI: BASE_URL + "/test3.xpi",
repositoryStatus: 8,
size: 5555,
updateDate: new Date(1265033045000)
updateDate: new Date(1265033045000),
}, {
id: "purchase1@tests.mozilla.org",
type: "extension",

View File

@ -39,7 +39,8 @@ const ADDON_PROPERTIES = ["id", "type", "name", "version", "creator",
"optionsURL", "aboutURL", "contributionURL",
"contributionAmount", "averageRating", "reviewCount",
"reviewURL", "totalDownloads", "weeklyDownloads",
"dailyUsers", "sourceURI", "repositoryStatus"];
"dailyUsers", "sourceURI", "repositoryStatus",
"compatibilityOverrides"];
// The size and updateDate properties are annoying to test for XPI add-ons.
// However, since we only care about whether the repository value vs. the
@ -90,7 +91,22 @@ const REPOSITORY_ADDONS = [{
weeklyDownloads: 3331,
dailyUsers: 4441,
sourceURI: BASE_URL + "/repo/1/install.xpi",
repositoryStatus: 4
repositoryStatus: 4,
compatibilityOverrides: [{
type: "incompatible",
minVersion: 0.1,
maxVersion: 0.2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 3.0,
appMaxVersion: 4.0
}, {
type: "incompatible",
minVersion: 0.2,
maxVersion: 0.3,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 5.0,
appMaxVersion: 6.0
}]
}, {
id: ADDON_IDS[1],
type: "theme",
@ -222,7 +238,22 @@ const WITH_CACHE = [{
weeklyDownloads: 3331,
dailyUsers: 4441,
sourceURI: NetUtil.newURI(ADDON_FILES[0]).spec,
repositoryStatus: 4
repositoryStatus: 4,
compatibilityOverrides: [{
type: "incompatible",
minVersion: 0.1,
maxVersion: 0.2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 3.0,
appMaxVersion: 4.0
}, {
type: "incompatible",
minVersion: 0.2,
maxVersion: 0.3,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 5.0,
appMaxVersion: 6.0
}]
}, {
id: ADDON_IDS[1],
type: "theme",
@ -319,7 +350,22 @@ const WITH_EXTENSION_CACHE = [{
weeklyDownloads: 3331,
dailyUsers: 4441,
sourceURI: NetUtil.newURI(ADDON_FILES[0]).spec,
repositoryStatus: 4
repositoryStatus: 4,
compatibilityOverrides: [{
type: "incompatible",
minVersion: 0.1,
maxVersion: 0.2,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 3.0,
appMaxVersion: 4.0
}, {
type: "incompatible",
minVersion: 0.2,
maxVersion: 0.3,
appID: "xpcshell@tests.mozilla.org",
appMinVersion: 5.0,
appMaxVersion: 6.0
}]
}, {
id: ADDON_IDS[1],
type: "theme",

View File

@ -0,0 +1,275 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests compatibility overrides, for when strict compatibility checking is
// disabled. See bug 693906.
const PREF_GETADDONS_CACHE_ENABLED = "extensions.getAddons.cache.enabled";
const PREF_GETADDONS_BYIDS = "extensions.getAddons.get.url";
const PORT = 4444;
const BASE_URL = "http://localhost:" + PORT;
const DEFAULT_URL = "about:blank";
const REQ_URL = "/data.xml";
Services.prefs.setBoolPref(PREF_EM_STRICT_COMPATIBILITY, false);
Services.prefs.setBoolPref(PREF_GETADDONS_CACHE_ENABLED, true);
Services.prefs.setCharPref(PREF_GETADDONS_BYIDS,
BASE_URL + REQ_URL);
do_load_httpd_js();
var gServer;
// Not hosted, no overrides
var addon1 = {
id: "addon1@tests.mozilla.org",
version: "1.0",
name: "Test addon 1",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, no overrides
var addon2 = {
id: "addon2@tests.mozilla.org",
version: "1.0",
name: "Test addon 2",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, matching override
var addon3 = {
id: "addon3@tests.mozilla.org",
version: "1.0",
name: "Test addon 3",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, matching override, wouldn't be compatible if strict chekcing is enabled
var addon4 = {
id: "addon4@tests.mozilla.org",
version: "1.0",
name: "Test addon 4",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "0.1",
maxVersion: "0.2"
}]
};
// Hosted, app ID doesn't match in override
var addon5 = {
id: "addon5@tests.mozilla.org",
version: "1.0",
name: "Test addon 5",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, addon version range doesn't match in override
var addon6 = {
id: "addon6@tests.mozilla.org",
version: "1.0",
name: "Test addon 6",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, app version range doesn't match in override
var addon7 = {
id: "addon7@tests.mozilla.org",
version: "1.0",
name: "Test addon 7",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Hosted, multiple overrides
var addon8 = {
id: "addon8@tests.mozilla.org",
version: "1.0",
name: "Test addon 8",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Not hosted, matching override
var addon9 = {
id: "addon9@tests.mozilla.org",
version: "1.0",
name: "Test addon 9",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
// Not hosted, override is of unsupported type (compatible)
var addon10 = {
id: "addon10@tests.mozilla.org",
version: "1.0",
name: "Test addon 10",
targetApplications: [{
id: "xpcshell@tests.mozilla.org",
minVersion: "1",
maxVersion: "1"
}]
};
const profileDir = gProfD.clone();
profileDir.append("extensions");
/*
* Trigger an AddonManager background update check
*
* @param aCallback
* Callback to call once the background update is complete
*/
function trigger_background_update(aCallback) {
Services.obs.addObserver({
observe: function(aSubject, aTopic, aData) {
Services.obs.removeObserver(this, "addons-background-update-complete");
aCallback();
}
}, "addons-background-update-complete", false);
gInternalManager.notify(null);
}
function run_test() {
do_test_pending();
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "2");
writeInstallRDFForExtension(addon1, profileDir);
writeInstallRDFForExtension(addon2, profileDir);
writeInstallRDFForExtension(addon3, profileDir);
writeInstallRDFForExtension(addon4, profileDir);
writeInstallRDFForExtension(addon5, profileDir);
writeInstallRDFForExtension(addon6, profileDir);
writeInstallRDFForExtension(addon7, profileDir);
writeInstallRDFForExtension(addon8, profileDir);
writeInstallRDFForExtension(addon9, profileDir);
writeInstallRDFForExtension(addon10, profileDir);
gServer = new nsHttpServer();
gServer.registerFile(REQ_URL, do_get_file("data/test_compatoverrides.xml"));
gServer.start(PORT);
startupManager();
trigger_background_update(run_test_1);
}
function end_test() {
gServer.stop(do_test_finished);
}
function check_compat_status(aCallback) {
AddonManager.getAddonsByIDs(["addon1@tests.mozilla.org",
"addon2@tests.mozilla.org",
"addon3@tests.mozilla.org",
"addon4@tests.mozilla.org",
"addon5@tests.mozilla.org",
"addon6@tests.mozilla.org",
"addon7@tests.mozilla.org",
"addon8@tests.mozilla.org",
"addon9@tests.mozilla.org",
"addon10@tests.mozilla.org"],
function([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]) {
do_check_neq(a1, null);
do_check_eq(a1.compatibilityOverrides, null);
do_check_true(a1.isCompatible);
do_check_false(a1.appDisabled);
do_check_neq(a2, null);
do_check_eq(a2.compatibilityOverrides, null);
do_check_true(a2.isCompatible);
do_check_false(a2.appDisabled);
do_check_neq(a3, null);
do_check_neq(a3.compatibilityOverrides, null);
do_check_eq(a3.compatibilityOverrides.length, 1);
do_check_false(a3.isCompatible);
do_check_true(a3.appDisabled);
do_check_neq(a4, null);
do_check_neq(a4.compatibilityOverrides, null);
do_check_eq(a4.compatibilityOverrides.length, 1);
do_check_false(a4.isCompatible);
do_check_true(a4.appDisabled);
do_check_neq(a5, null);
do_check_eq(a5.compatibilityOverrides, null);
do_check_true(a5.isCompatible);
do_check_false(a5.appDisabled);
do_check_neq(a6, null);
do_check_neq(a6.compatibilityOverrides, null);
do_check_eq(a6.compatibilityOverrides.length, 1);
do_check_true(a6.isCompatible);
do_check_false(a6.appDisabled);
do_check_neq(a7, null);
do_check_neq(a7.compatibilityOverrides, null);
do_check_eq(a7.compatibilityOverrides.length, 1);
do_check_true(a7.isCompatible);
do_check_false(a7.appDisabled);
do_check_neq(a8, null);
do_check_neq(a8.compatibilityOverrides, null);
do_check_eq(a8.compatibilityOverrides.length, 3);
do_check_false(a8.isCompatible);
do_check_true(a8.appDisabled);
do_check_neq(a9, null);
do_check_neq(a9.compatibilityOverrides, null);
do_check_eq(a9.compatibilityOverrides.length, 1);
do_check_false(a9.isCompatible);
do_check_true(a9.appDisabled);
do_check_neq(a10, null);
do_check_eq(a10.compatibilityOverrides, null);
do_check_true(a10.isCompatible);
do_check_false(a10.appDisabled);
aCallback();
});
}
function run_test_1() {
check_compat_status(run_test_2);
}
function run_test_2() {
restartManager();
check_compat_status(end_test);
}

View File

@ -2,7 +2,7 @@
* http://creativecommons.org/publicdomain/zero/1.0/
*/
const EXPECTED_SCHEMA_VERSION = 2;
const EXPECTED_SCHEMA_VERSION = 3;
let dbfile;
function run_test() {
@ -88,6 +88,24 @@ function run_test() {
do_check_eq(db.schemaVersion, EXPECTED_SCHEMA_VERSION);
do_check_true(db.indexExists("developer_idx"));
do_check_true(db.indexExists("screenshot_idx"));
do_check_true(db.indexExists("compatibility_override_idx"));
do_check_true(db.tableExists("compatibility_override"));
// Check the trigger is working
db.executeSimpleSQL("INSERT INTO addon (id, type, name) VALUES('test_addon', 'extension', 'Test Addon')");
let internalID = db.lastInsertRowID;
db.executeSimpleSQL("INSERT INTO compatibility_override (addon_internal_id, num, type) VALUES('" + internalID + "', '1', 'incompatible')");
let stmt = db.createStatement("SELECT COUNT(*) AS count FROM compatibility_override");
stmt.executeStep();
do_check_eq(stmt.row.count, 1);
stmt.reset();
db.executeSimpleSQL("DELETE FROM addon");
stmt.executeStep();
do_check_eq(stmt.row.count, 0);
stmt.finalize();
db.close();
run_test_2();
}

View File

@ -127,6 +127,7 @@ fail-if = os == "android"
[test_cacheflush.js]
[test_checkcompatibility.js]
[test_ChromeManifestParser.js]
[test_compatoverrides.js]
[test_corrupt.js]
[test_corrupt_strictcompat.js]
[test_dictionary.js]