Bug 1312591 - Remove DOM/resourcestats and related code. r=jst

MozReview-Commit-ID: 8WOXOvtxjxt

--HG--
extra : rebase_source : 692d4e964bd7103ba83e883400e7012951f1b184
This commit is contained in:
Michelangelo De Simone 2016-10-24 16:35:04 -07:00
parent e636b54dfb
commit 2c9eba2c9a
23 changed files with 0 additions and 4256 deletions

View File

@ -407,11 +407,6 @@ pref("dom.mozNetworkStats.enabled", true);
pref("dom.webapps.firstRunWithSIM", true);
#endif
// ResourceStats
#ifdef MOZ_WIDGET_GONK
pref("dom.resource_stats.enabled", true);
#endif
#ifdef MOZ_B2G_RIL
// SingleVariant
pref("dom.mozApps.single_variant_sourcedir", "/persist/svoperapps");

View File

@ -442,14 +442,6 @@
@RESPATH@/components/TetheringManager.manifest
#endif
; ResourceStats
#ifdef MOZ_WIDGET_GONK
@RESPATH@/components/ResourceStats.js
@RESPATH@/components/ResourceStats.manifest
@RESPATH@/components/ResourceStatsManager.js
@RESPATH@/components/ResourceStatsManager.manifest
#endif // MOZ_WIDGET_GONK
; RIL
#if defined(MOZ_WIDGET_GONK) && defined(MOZ_B2G_RIL)
@RESPATH@/components/CellBroadcastService.js

View File

@ -238,11 +238,6 @@ this.PermissionsTable = { geolocation: {
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
"resourcestats-manage": {
app: DENY_ACTION,
privileged: DENY_ACTION,
certified: ALLOW_ACTION
},
"wifi-manage": {
app: DENY_ACTION,
privileged: DENY_ACTION,

View File

@ -101,7 +101,6 @@ DIRS += [
'xml',
'xslt',
'xul',
'resourcestats',
'manifest',
'vr',
'newapps',

View File

@ -1,538 +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/.
*/
"use strict";
this.EXPORTED_SYMBOLS = ['ResourceStatsDB'];
const DEBUG = false;
function debug(s) { dump("-*- ResourceStatsDB: " + s + "\n"); }
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/IndexedDBHelper.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.importGlobalProperties(["indexedDB"]);
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
"@mozilla.org/AppsService;1",
"nsIAppsService");
const DB_NAME = "resource_stats";
const DB_VERSION = 1;
const POWER_STATS_STORE = "power_stats_store";
const NETWORK_STATS_STORE = "network_stats_store";
const ALARM_STORE = "alarm_store";
const statsStoreNames = {
power: POWER_STATS_STORE,
network: NETWORK_STATS_STORE
};
// Constant defining the sampling rate.
const SAMPLE_RATE = 24 * 60 * 60 * 1000; // 1 day.
// Constant defining the MAX age of stored stats.
const MAX_STORAGE_AGE = 180 * SAMPLE_RATE; // 180 days.
this.ResourceStatsDB = function ResourceStatsDB() {
if (DEBUG) {
debug("Constructor()");
}
this.initDBHelper(DB_NAME, DB_VERSION,
[POWER_STATS_STORE, NETWORK_STATS_STORE, ALARM_STORE]);
};
ResourceStatsDB.prototype = {
__proto__: IndexedDBHelper.prototype,
_dbNewTxn: function(aStoreName, aTxnType, aCallback, aTxnCb) {
function successCb(aResult) {
aTxnCb(null, aResult);
}
function errorCb(aError) {
aTxnCb(aError, null);
}
return this.newTxn(aTxnType, aStoreName, aCallback, successCb, errorCb);
},
upgradeSchema: function(aTransaction, aDb, aOldVersion, aNewVersion) {
if (DEBUG) {
debug("Upgrade DB from ver." + aOldVersion + " to ver." + aNewVersion);
}
let objectStore;
// Create PowerStatsStore.
objectStore = aDb.createObjectStore(POWER_STATS_STORE, {
keyPath: ["appId", "serviceType", "component", "timestamp"]
});
objectStore.createIndex("component", "component", { unique: false });
// Create NetworkStatsStore.
objectStore = aDb.createObjectStore(NETWORK_STATS_STORE, {
keyPath: ["appId", "serviceType", "component", "timestamp"]
});
objectStore.createIndex("component", "component", { unique: false });
// Create AlarmStore.
objectStore = aDb.createObjectStore(ALARM_STORE, {
keyPath: "alarmId",
autoIncrement: true
});
objectStore.createIndex("type", "type", { unique: false });
// Index for resource control target.
objectStore.createIndex("controlTarget",
["type", "manifestURL", "serviceType", "component"],
{ unique: false });
},
// Convert to UTC according to the current timezone and the filter timestamp
// to get SAMPLE_RATE precission.
_normalizeTime: function(aTime, aOffset) {
let time = Math.floor((aTime - aOffset) / SAMPLE_RATE) * SAMPLE_RATE;
return time;
},
/**
* aRecordArray contains an array of json objects storing network stats.
* The structure of the json object =
* {
* appId: XX,
* serviceType: "XX",
* componentStats: {
* "component_1": { receivedBytes: XX, sentBytes: XX },
* "component_2": { receivedBytes: XX, sentBytes: XX },
* ...
* },
* }
*/
saveNetworkStats: function(aRecordArray, aTimestamp, aResultCb) {
if (DEBUG) {
debug("saveNetworkStats()");
}
let offset = (new Date()).getTimezoneOffset() * 60 * 1000;
let timestamp = this._normalizeTime(aTimestamp, offset);
this._dbNewTxn(NETWORK_STATS_STORE, "readwrite", function(aTxn, aStore) {
aRecordArray.forEach(function(aRecord) {
let stats = {
appId: aRecord.appId,
serviceType: aRecord.serviceType,
component: "",
timestamp: timestamp,
receivedBytes: 0,
sentBytes: 0
};
let totalReceivedBytes = 0;
let totalSentBytes = 0;
// Save stats of each component.
let data = aRecord.componentStats;
for (let component in data) {
// Save stats to database.
stats.component = component;
stats.receivedBytes = data[component].receivedBytes;
stats.sentBytes = data[component].sentBytes;
aStore.put(stats);
if (DEBUG) {
debug("Save network stats: " + JSON.stringify(stats));
}
// Accumulated to tatal stats.
totalReceivedBytes += stats.receivedBytes;
totalSentBytes += stats.sentBytes;
}
// Save total stats.
stats.component = "";
stats.receivedBytes = totalReceivedBytes;
stats.sentBytes = totalSentBytes;
aStore.put(stats);
if (DEBUG) {
debug("Save network stats: " + JSON.stringify(stats));
}
});
}, aResultCb);
},
/**
* aRecordArray contains an array of json objects storing power stats.
* The structure of the json object =
* {
* appId: XX,
* serviceType: "XX",
* componentStats: {
* "component_1": XX, // consumedPower
* "component_2": XX,
* ...
* },
* }
*/
savePowerStats: function(aRecordArray, aTimestamp, aResultCb) {
if (DEBUG) {
debug("savePowerStats()");
}
let offset = (new Date()).getTimezoneOffset() * 60 * 1000;
let timestamp = this._normalizeTime(aTimestamp, offset);
this._dbNewTxn(POWER_STATS_STORE, "readwrite", function(aTxn, aStore) {
aRecordArray.forEach(function(aRecord) {
let stats = {
appId: aRecord.appId,
serviceType: aRecord.serviceType,
component: "",
timestamp: timestamp,
consumedPower: aRecord.totalStats
};
let totalConsumedPower = 0;
// Save stats of each component to database.
let data = aRecord.componentStats;
for (let component in data) {
// Save stats to database.
stats.component = component;
stats.consumedPower = data[component];
aStore.put(stats);
if (DEBUG) {
debug("Save power stats: " + JSON.stringify(stats));
}
// Accumulated to total stats.
totalConsumedPower += stats.consumedPower;
}
// Save total stats.
stats.component = "";
stats.consumedPower = totalConsumedPower;
aStore.put(stats);
if (DEBUG) {
debug("Save power stats: " + JSON.stringify(stats));
}
});
}, aResultCb);
},
// Get stats from a store.
getStats: function(aType, aManifestURL, aServiceType, aComponent,
aStart, aEnd, aResultCb) {
if (DEBUG) {
debug(aType + "Mgr.getStats()");
}
let offset = (new Date()).getTimezoneOffset() * 60 * 1000;
// Get appId and check whether manifestURL is a valid app.
let appId = 0;
if (aManifestURL) {
appId = appsService.getAppLocalIdByManifestURL(aManifestURL);
if (!appId) {
aResultCb("Invalid manifestURL", null);
return;
}
}
// Get store name.
let storeName = statsStoreNames[aType];
// Normalize start time and end time to SAMPLE_RATE precission.
let start = this._normalizeTime(aStart, offset);
let end = this._normalizeTime(aEnd, offset);
if (DEBUG) {
debug("Query time range: " + start + " to " + end);
debug("[appId, serviceType, component] = [" + appId + ", " + aServiceType
+ ", " + aComponent + "]");
}
// Create filters.
let lowerFilter = [appId, aServiceType, aComponent, start];
let upperFilter = [appId, aServiceType, aComponent, end];
// Execute DB query.
this._dbNewTxn(storeName, "readonly", function(aTxn, aStore) {
let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
let statsData = [];
if (!aTxn.result) {
aTxn.result = Object.create(null);
}
aTxn.result.type = aType;
aTxn.result.component = aComponent;
aTxn.result.serviceType = aServiceType;
aTxn.result.manifestURL = aManifestURL;
aTxn.result.start = start + offset;
aTxn.result.end = end + offset;
// Since ResourceStats() would require SAMPLE_RATE when filling the empty
// entries of statsData array, we append SAMPLE_RATE to the result field
// to save an IPC call.
aTxn.result.sampleRate = SAMPLE_RATE;
let request = aStore.openCursor(range, "prev");
if (aType == "power") {
request.onsuccess = function(aEvent) {
var cursor = aEvent.target.result;
if (cursor) {
if (DEBUG) {
debug("Get " + JSON.stringify(cursor.value));
}
// Covert timestamp to current timezone.
statsData.push({
timestamp: cursor.value.timestamp + offset,
consumedPower: cursor.value.consumedPower
});
cursor.continue();
return;
}
aTxn.result.statsData = statsData;
};
} else if (aType == "network") {
request.onsuccess = function(aEvent) {
var cursor = aEvent.target.result;
if (cursor) {
if (DEBUG) {
debug("Get " + JSON.stringify(cursor.value));
}
// Covert timestamp to current timezone.
statsData.push({
timestamp: cursor.value.timestamp + offset,
receivedBytes: cursor.value.receivedBytes,
sentBytes: cursor.value.sentBytes
});
cursor.continue();
return;
}
aTxn.result.statsData = statsData;
};
}
}, aResultCb);
},
// Delete the stats of a specific app/service (within a specified time range).
clearStats: function(aType, aAppId, aServiceType, aComponent,
aStart, aEnd, aResultCb) {
if (DEBUG) {
debug(aType + "Mgr.clearStats()");
}
let offset = (new Date()).getTimezoneOffset() * 60 * 1000;
// Get store name.
let storeName = statsStoreNames[aType];
// Normalize start and end time to SAMPLE_RATE precission.
let start = this._normalizeTime(aStart, offset);
let end = this._normalizeTime(aEnd, offset);
if (DEBUG) {
debug("Query time range: " + start + " to " + end);
debug("[appId, serviceType, component] = [" + aAppId + ", " + aServiceType
+ ", " + aComponent + "]");
}
// Create filters.
let lowerFilter = [aAppId, aServiceType, aComponent, start];
let upperFilter = [aAppId, aServiceType, aComponent, end];
// Execute clear operation.
this._dbNewTxn(storeName, "readwrite", function(aTxn, aStore) {
let range = IDBKeyRange.bound(lowerFilter, upperFilter, false, false);
let request = aStore.openCursor(range).onsuccess = function(aEvent) {
let cursor = aEvent.target.result;
if (cursor) {
if (DEBUG) {
debug("Delete " + JSON.stringify(cursor.value) + " from database");
}
cursor.delete();
cursor.continue();
return;
}
};
}, aResultCb);
},
// Delete all stats saved in a store.
clearAllStats: function(aType, aResultCb) {
if (DEBUG) {
debug(aType + "Mgr.clearAllStats()");
}
let storeName = statsStoreNames[aType];
// Execute clear operation.
this._dbNewTxn(storeName, "readwrite", function(aTxn, aStore) {
if (DEBUG) {
debug("Clear " + aType + " stats from datastore");
}
aStore.clear();
}, aResultCb);
},
addAlarm: function(aAlarm, aResultCb) {
if (DEBUG) {
debug(aAlarm.type + "Mgr.addAlarm()");
debug("alarm = " + JSON.stringify(aAlarm));
}
this._dbNewTxn(ALARM_STORE, "readwrite", function(aTxn, aStore) {
aStore.put(aAlarm).onsuccess = function setResult(aEvent) {
// Get alarmId.
aTxn.result = aEvent.target.result;
if (DEBUG) {
debug("New alarm ID: " + aTxn.result);
}
};
}, aResultCb);
},
// Convert DB record to alarm object.
_recordToAlarm: function(aRecord) {
let alarm = {
alarmId: aRecord.alarmId,
type: aRecord.type,
component: aRecord.component,
serviceType: aRecord.serviceType,
manifestURL: aRecord.manifestURL,
threshold: aRecord.threshold,
data: aRecord.data
};
return alarm;
},
getAlarms: function(aType, aOptions, aResultCb) {
if (DEBUG) {
debug(aType + "Mgr.getAlarms()");
debug("[appId, serviceType, component] = [" + aOptions.appId + ", "
+ aOptions.serviceType + ", " + aOptions.component + "]");
}
// Execute clear operation.
this._dbNewTxn(ALARM_STORE, "readwrite", function(aTxn, aStore) {
if (!aTxn.result) {
aTxn.result = [];
}
let indexName = null;
let range = null;
if (aOptions) { // Get alarms associated to specified statsOptions.
indexName = "controlTarget";
range = IDBKeyRange.only([aType, aOptions.manifestURL,
aOptions.serviceType, aOptions.component]);
} else { // Get all alarms of the specified type.
indexName = "type";
range = IDBKeyRange.only(aType);
}
let request = aStore.index(indexName).openCursor(range);
request.onsuccess = function onsuccess(aEvent) {
let cursor = aEvent.target.result;
if (cursor) {
aTxn.result.push(this._recordToAlarm(cursor.value));
cursor.continue();
return;
}
}.bind(this);
}.bind(this), aResultCb);
},
removeAlarm: function(aType, aAlarmId, aResultCb) {
if (DEBUG) {
debug("removeAlarms(" + aAlarmId + ")");
}
// Execute clear operation.
this._dbNewTxn(ALARM_STORE, "readwrite", function(aTxn, aStore) {
aStore.get(aAlarmId).onsuccess = function onsuccess(aEvent) {
let alarm = aEvent.target.result;
aTxn.result = false;
if (!alarm || aType !== alarm.type) {
return;
}
if (DEBUG) {
debug("Remove alarm " + JSON.stringify(alarm) + " from datastore");
}
aStore.delete(aAlarmId);
aTxn.result = true;
};
}, aResultCb);
},
removeAllAlarms: function(aType, aResultCb) {
if (DEBUG) {
debug(aType + "Mgr.removeAllAlarms()");
}
// Execute clear operation.
this._dbNewTxn(ALARM_STORE, "readwrite", function(aTxn, aStore) {
if (DEBUG) {
debug("Remove all " + aType + " alarms from datastore.");
}
let range = IDBKeyRange.only(aType);
let request = aStore.index("type").openCursor(range);
request.onsuccess = function onsuccess(aEvent) {
let cursor = aEvent.target.result;
if (cursor) {
if (DEBUG) {
debug("Remove " + JSON.stringify(cursor.value) + " from database.");
}
cursor.delete();
cursor.continue();
return;
}
};
}, aResultCb);
},
// Get all index keys of the component.
getComponents: function(aType, aResultCb) {
if (DEBUG) {
debug(aType + "Mgr.getComponents()");
}
let storeName = statsStoreNames[aType];
this._dbNewTxn(storeName, "readonly", function(aTxn, aStore) {
if (!aTxn.result) {
aTxn.result = [];
}
let request = aStore.index("component").openKeyCursor(null, "nextunique");
request.onsuccess = function onsuccess(aEvent) {
let cursor = aEvent.target.result;
if (cursor) {
aTxn.result.push(cursor.key);
cursor.continue();
return;
}
// Remove "" from the result, which indicates sum of all
// components' stats.
let index = aTxn.result.indexOf("");
if (index > -1) {
aTxn.result.splice(index, 1);
}
};
}, aResultCb);
},
get sampleRate () {
return SAMPLE_RATE;
},
get maxStorageAge() {
return MAX_STORAGE_AGE;
},
};

View File

@ -1,468 +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/.
*/
"use strict";
const DEBUG = false;
function debug(s) { dump("-*- ResourceStatsManager: " + s + "\n"); }
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
// Constant defines supported statistics.
const resourceTypeList = ["network", "power"];
function NetworkStatsData(aStatsData) {
if (DEBUG) {
debug("NetworkStatsData(): " + JSON.stringify(aStatsData));
}
this.receivedBytes = aStatsData.receivedBytes || 0;
this.sentBytes = aStatsData.sentBytes || 0;
this.timestamp = aStatsData.timestamp;
}
NetworkStatsData.prototype = {
classID: Components.ID("{dce5729a-ba92-4185-8854-e29e71b9e8a2}"),
contractID: "@mozilla.org/networkStatsData;1",
QueryInterface: XPCOMUtils.generateQI([])
};
function PowerStatsData(aStatsData) {
if (DEBUG) {
debug("PowerStatsData(): " + JSON.stringify(aStatsData));
}
this.consumedPower = aStatsData.consumedPower || 0;
this.timestamp = aStatsData.timestamp;
}
PowerStatsData.prototype = {
classID: Components.ID("{acb9af6c-8143-4e59-bc18-4bb1736a4004}"),
contractID: "@mozilla.org/powerStatsData;1",
QueryInterface: XPCOMUtils.generateQI([])
};
function ResourceStats(aWindow, aStats) {
if (DEBUG) {
debug("ResourceStats(): " + JSON.stringify(aStats));
}
this._window = aWindow;
this.type = aStats.type;
this.component = aStats.component || null;
this.serviceType = aStats.serviceType || null;
this.manifestURL = aStats.manifestURL || null;
this.start = aStats.start;
this.end = aStats.end;
this.statsData = new aWindow.Array();
// A function creates a StatsData object according to type.
let createStatsDataObject = null;
let self = this;
switch (this.type) {
case "power":
createStatsDataObject = function(aStats) {
let chromeObj = new PowerStatsData(aStats);
return self._window.PowerStatsData._create(self._window, chromeObj);
};
break;
case "network":
createStatsDataObject = function(aStats) {
let chromeObj = new NetworkStatsData(aStats);
return self._window.NetworkStatsData._create(self._window, chromeObj);
};
break;
}
let sampleRate = aStats.sampleRate;
let queryResult = aStats.statsData;
let stats = queryResult.pop(); // Pop out the last element.
let timestamp = this.start;
// Push query result to statsData, and fill empty elements so that:
// 1. the timestamp of the first element of statsData is equal to start;
// 2. the timestamp of the last element of statsData is equal to end;
// 3. the timestamp difference of every neighboring elements is SAMPLE_RATE.
for (; timestamp <= this.end; timestamp += sampleRate) {
if (!stats || stats.timestamp != timestamp) {
// If dataArray is empty or timestamp are not equal, push a dummy object
// (which stats are set to 0) to statsData.
this.statsData.push(createStatsDataObject({ timestamp: timestamp }));
} else {
// Push stats to statsData and pop a new element form queryResult.
this.statsData.push(createStatsDataObject(stats));
stats = queryResult.pop();
}
}
}
ResourceStats.prototype = {
getData: function() {
return this.statsData;
},
classID: Components.ID("{b7c970f2-3d58-4966-9633-2024feb5132b}"),
contractID: "@mozilla.org/resourceStats;1",
QueryInterface: XPCOMUtils.generateQI([])
};
function ResourceStatsAlarm(aWindow, aAlarm) {
if (DEBUG) {
debug("ResourceStatsAlarm(): " + JSON.stringify(aAlarm));
}
this.alarmId = aAlarm.alarmId;
this.type = aAlarm.type;
this.component = aAlarm.component || null;
this.serviceType = aAlarm.serviceType || null;
this.manifestURL = aAlarm.manifestURL || null;
this.threshold = aAlarm.threshold;
// Clone data object using structured clone algorithm.
this.data = null;
if (aAlarm.data) {
this.data = Cu.cloneInto(aAlarm.data, aWindow);
}
}
ResourceStatsAlarm.prototype = {
classID: Components.ID("{e2b66e7a-0ff1-4015-8690-a2a3f6a5b63a}"),
contractID: "@mozilla.org/resourceStatsAlarm;1",
QueryInterface: XPCOMUtils.generateQI([]),
};
function ResourceStatsManager() {
if (DEBUG) {
debug("constructor()");
}
}
ResourceStatsManager.prototype = {
__proto__: DOMRequestIpcHelper.prototype,
// Check time range.
_checkTimeRange: function(aStart, aEnd) {
if (DEBUG) {
debug("_checkTimeRange(): " + aStart + " to " + aEnd);
}
let start = aStart ? aStart : 0;
let end = aEnd ? aEnd : Date.now();
if (start > end) {
throw Cr.NS_ERROR_INVALID_ARG;
}
return { start: start, end: end };
},
getStats: function(aStatsOptions, aStart, aEnd) {
// Check time range.
let { start: start, end: end } = this._checkTimeRange(aStart, aEnd);
// Create Promise.
let self = this;
return this.createPromiseWithId(function(aResolverId) {
self.cpmm.sendAsyncMessage("ResourceStats:GetStats", {
resolverId: aResolverId,
type: self.type,
statsOptions: aStatsOptions,
manifestURL: self._manifestURL,
start: start,
end: end
});
});
},
clearStats: function(aStatsOptions, aStart, aEnd) {
// Check time range.
let {start: start, end: end} = this._checkTimeRange(aStart, aEnd);
// Create Promise.
let self = this;
return this.createPromiseWithId(function(aResolverId) {
self.cpmm.sendAsyncMessage("ResourceStats:ClearStats", {
resolverId: aResolverId,
type: self.type,
statsOptions: aStatsOptions,
manifestURL: self._manifestURL,
start: start,
end: end
});
});
},
clearAllStats: function() {
// Create Promise.
let self = this;
return this.createPromiseWithId(function(aResolverId) {
self.cpmm.sendAsyncMessage("ResourceStats:ClearAllStats", {
resolverId: aResolverId,
type: self.type,
manifestURL: self._manifestURL
});
});
},
addAlarm: function(aThreshold, aStatsOptions, aAlarmOptions) {
if (DEBUG) {
debug("aStatsOptions: " + JSON.stringify(aAlarmOptions));
debug("aAlarmOptions: " + JSON.stringify(aAlarmOptions));
}
// Parse alarm options.
let startTime = aAlarmOptions.startTime || 0;
// Clone data object using structured clone algorithm.
let data = null;
if (aAlarmOptions.data) {
data = Cu.cloneInto(aAlarmOptions.data, this._window);
}
// Create Promise.
let self = this;
return this.createPromiseWithId(function(aResolverId) {
self.cpmm.sendAsyncMessage("ResourceStats:AddAlarm", {
resolverId: aResolverId,
type: self.type,
threshold: aThreshold,
statsOptions: aStatsOptions,
manifestURL: self._manifestURL,
startTime: startTime,
data: data
});
});
},
getAlarms: function(aStatsOptions) {
// Create Promise.
let self = this;
return this.createPromiseWithId(function(aResolverId) {
self.cpmm.sendAsyncMessage("ResourceStats:GetAlarms", {
resolverId: aResolverId,
type: self.type,
statsOptions: aStatsOptions,
manifestURL: self._manifestURL
});
});
},
removeAlarm: function(aAlarmId) {
// Create Promise.
let self = this;
return this.createPromiseWithId(function(aResolverId) {
self.cpmm.sendAsyncMessage("ResourceStats:RemoveAlarm", {
resolverId: aResolverId,
type: self.type,
manifestURL: self._manifestURL,
alarmId: aAlarmId
});
});
},
removeAllAlarms: function() {
// Create Promise.
let self = this;
return this.createPromiseWithId(function(aResolverId) {
self.cpmm.sendAsyncMessage("ResourceStats:RemoveAllAlarms", {
resolverId: aResolverId,
type: self.type,
manifestURL: self._manifestURL
});
});
},
getAvailableComponents: function() {
// Create Promise.
let self = this;
return this.createPromiseWithId(function(aResolverId) {
self.cpmm.sendAsyncMessage("ResourceStats:GetComponents", {
resolverId: aResolverId,
type: self.type,
manifestURL: self._manifestURL
});
});
},
get resourceTypes() {
let types = new this._window.Array();
resourceTypeList.forEach(function(aType) {
types.push(aType);
});
return types;
},
get sampleRate() {
let msg = { manifestURL: this._manifestURL };
return this.cpmm.sendSyncMessage("ResourceStats:SampleRate", msg)[0];
},
get maxStorageAge() {
let msg = { manifestURL: this._manifestURL };
return this.cpmm.sendSyncMessage("ResourceStats:MaxStorageAge", msg)[0];
},
receiveMessage: function(aMessage) {
let data = aMessage.data;
let chromeObj = null;
let webidlObj = null;
let self = this;
if (DEBUG) {
debug("receiveMessage(): " + aMessage.name + " " + data.resolverId);
}
let resolver = this.takePromiseResolver(data.resolverId);
if (!resolver) {
return;
}
switch (aMessage.name) {
case "ResourceStats:GetStats:Resolved":
if (DEBUG) {
debug("data.value = " + JSON.stringify(data.value));
}
chromeObj = new ResourceStats(this._window, data.value);
webidlObj = this._window.ResourceStats._create(this._window, chromeObj);
resolver.resolve(webidlObj);
break;
case "ResourceStats:AddAlarm:Resolved":
if (DEBUG) {
debug("data.value = " + JSON.stringify(data.value));
}
resolver.resolve(data.value); // data.value is alarmId.
break;
case "ResourceStats:GetAlarms:Resolved":
if (DEBUG) {
debug("data.value = " + JSON.stringify(data.value));
}
let alarmArray = this._window.Array();
data.value.forEach(function(aAlarm) {
chromeObj = new ResourceStatsAlarm(self._window, aAlarm);
webidlObj = self._window.ResourceStatsAlarm._create(self._window,
chromeObj);
alarmArray.push(webidlObj);
});
resolver.resolve(alarmArray);
break;
case "ResourceStats:GetComponents:Resolved":
if (DEBUG) {
debug("data.value = " + JSON.stringify(data.value));
}
let components = this._window.Array();
data.value.forEach(function(aComponent) {
components.push(aComponent);
});
resolver.resolve(components);
break;
case "ResourceStats:ClearStats:Resolved":
case "ResourceStats:ClearAllStats:Resolved":
case "ResourceStats:RemoveAlarm:Resolved":
case "ResourceStats:RemoveAllAlarms:Resolved":
if (DEBUG) {
debug("data.value = " + JSON.stringify(data.value));
}
resolver.resolve(data.value);
break;
case "ResourceStats:GetStats:Rejected":
case "ResourceStats:ClearStats:Rejected":
case "ResourceStats:ClearAllStats:Rejected":
case "ResourceStats:AddAlarm:Rejected":
case "ResourceStats:GetAlarms:Rejected":
case "ResourceStats:RemoveAlarm:Rejected":
case "ResourceStats:RemoveAllAlarms:Rejected":
case "ResourceStats:GetComponents:Rejected":
if (DEBUG) {
debug("data.reason = " + JSON.stringify(data.reason));
}
resolver.reject(data.reason);
break;
default:
if (DEBUG) {
debug("Could not find a handler for " + aMessage.name);
}
resolver.reject();
}
},
__init: function(aType) {
if (resourceTypeList.indexOf(aType) < 0) {
if (DEBUG) {
debug("Do not support resource statistics for " + aType);
}
throw Cr.NS_ERROR_INVALID_ARG;
} else {
if (DEBUG) {
debug("Create " + aType + "Mgr");
}
this.type = aType;
}
},
init: function(aWindow) {
if (DEBUG) {
debug("init()");
}
// Get the manifestURL if this is an installed app
let principal = aWindow.document.nodePrincipal;
let appsService = Cc["@mozilla.org/AppsService;1"]
.getService(Ci.nsIAppsService);
this._manifestURL = appsService.getManifestURLByLocalId(principal.appId);
const messages = ["ResourceStats:GetStats:Resolved",
"ResourceStats:ClearStats:Resolved",
"ResourceStats:ClearAllStats:Resolved",
"ResourceStats:AddAlarm:Resolved",
"ResourceStats:GetAlarms:Resolved",
"ResourceStats:RemoveAlarm:Resolved",
"ResourceStats:RemoveAllAlarms:Resolved",
"ResourceStats:GetComponents:Resolved",
"ResourceStats:GetStats:Rejected",
"ResourceStats:ClearStats:Rejected",
"ResourceStats:ClearAllStats:Rejected",
"ResourceStats:AddAlarm:Rejected",
"ResourceStats:GetAlarms:Rejected",
"ResourceStats:RemoveAlarm:Rejected",
"ResourceStats:RemoveAllAlarms:Rejected",
"ResourceStats:GetComponents:Rejected"];
this.initDOMRequestHelper(aWindow, messages);
this.cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
.getService(Ci.nsISyncMessageSender);
},
classID: Components.ID("{101ed1f8-31b3-491c-95ea-04091e6e8027}"),
contractID: "@mozilla.org/resourceStatsManager;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsISupportsWeakReference,
Ci.nsIObserver])
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkStatsData,
PowerStatsData,
ResourceStats,
ResourceStatsAlarm,
ResourceStatsManager]);

View File

@ -1,14 +0,0 @@
component {dce5729a-ba92-4185-8854-e29e71b9e8a2} ResourceStatsManager.js
contract @mozilla.org/networkStatsData;1 {dce5729a-ba92-4185-8854-e29e71b9e8a2}
component {acb9af6c-8143-4e59-bc18-4bb1736a4004} ResourceStatsManager.js
contract @mozilla.org/powerStatsData;1 {acb9af6c-8143-4e59-bc18-4bb1736a4004}
component {b7c970f2-3d58-4966-9633-2024feb5132b} ResourceStatsManager.js
contract @mozilla.org/resourceStats;1 {b7c970f2-3d58-4966-9633-2024feb5132b}
component {e2b66e7a-0ff1-4015-8690-a2a3f6a5b63a} ResourceStatsManager.js
contract @mozilla.org/resourceStatsAlarm;1 {e2b66e7a-0ff1-4015-8690-a2a3f6a5b63a}
component {101ed1f8-31b3-491c-95ea-04091e6e8027} ResourceStatsManager.js
contract @mozilla.org/resourceStatsManager;1 {101ed1f8-31b3-491c-95ea-04091e6e8027}

View File

@ -1,334 +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/.
*/
"use strict";
this.EXPORTED_SYMBOLS = ["ResourceStatsService"];
const DEBUG = false;
function debug(s) { dump("-*- ResourceStatsService: " + s + "\n"); }
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
// Load ResourceStatsDB.
Cu.import("resource://gre/modules/ResourceStatsDB.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gIDBManager",
"@mozilla.org/dom/indexeddb/manager;1",
"nsIIndexedDatabaseManager");
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
"@mozilla.org/parentprocessmessagemanager;1",
"nsIMessageListenerManager");
XPCOMUtils.defineLazyServiceGetter(this, "appsService",
"@mozilla.org/AppsService;1",
"nsIAppsService");
this.ResourceStatsService = {
init: function() {
if (DEBUG) {
debug("Service started");
}
// Set notification to observe.
Services.obs.addObserver(this, "xpcom-shutdown", false);
// Add message listener.
this.messages = ["ResourceStats:GetStats",
"ResourceStats:ClearStats",
"ResourceStats:ClearAllStats",
"ResourceStats:AddAlarm",
"ResourceStats:GetAlarms",
"ResourceStats:RemoveAlarm",
"ResourceStats:RemoveAllAlarms",
"ResourceStats:GetComponents",
"ResourceStats:SampleRate",
"ResourceStats:MaxStorageAge"];
this.messages.forEach(function(aMessageName){
ppmm.addMessageListener(aMessageName, this);
}, this);
// Create indexedDB.
this._db = new ResourceStatsDB();
},
receiveMessage: function(aMessage) {
if (DEBUG) {
debug("receiveMessage(): " + aMessage.name);
}
let mm = aMessage.target;
let data = aMessage.data;
if (DEBUG) {
debug("received aMessage.data = " + JSON.stringify(data));
}
// To prevent the hacked child process from sending commands to parent,
// we need to check its permission and manifest URL.
if (!aMessage.target.assertPermission("resourcestats-manage")) {
return;
}
if (!aMessage.target.assertContainApp(data.manifestURL)) {
if (DEBUG) {
debug("Got msg from a child process containing illegal manifestURL.");
}
return;
}
switch (aMessage.name) {
case "ResourceStats:GetStats":
this.getStats(mm, data);
break;
case "ResourceStats:ClearStats":
this.clearStats(mm, data);
break;
case "ResourceStats:ClearAllStats":
this.clearAllStats(mm, data);
break;
case "ResourceStats:AddAlarm":
this.addAlarm(mm, data);
break;
case "ResourceStats:GetAlarms":
this.getAlarms(mm, data);
break;
case "ResourceStats:RemoveAlarm":
this.removeAlarm(mm, data);
break;
case "ResourceStats:RemoveAllAlarms":
this.removeAllAlarms(mm, data);
break;
case "ResourceStats:GetComponents":
this.getComponents(mm, data);
break;
case "ResourceStats:SampleRate":
// This message is sync.
return this._db.sampleRate;
case "ResourceStats:MaxStorageAge":
// This message is sync.
return this._db.maxStorageAge;
}
},
observe: function(aSubject, aTopic, aData) {
switch (aTopic) {
case "xpcom-shutdown":
if (DEBUG) {
debug("Service shutdown " + aData);
}
this.messages.forEach(function(aMessageName) {
ppmm.removeMessageListener(aMessageName, this);
}, this);
Services.obs.removeObserver(this, "xpcom-shutdown");
break;
default:
return;
}
},
// Closure generates callback function for DB request.
_createDbCallback: function(aMm, aId, aMessage) {
let resolveMsg = aMessage + ":Resolved";
let rejectMsg = aMessage + ":Rejected";
return function(aError, aResult) {
if (aError) {
aMm.sendAsyncMessage(rejectMsg, { resolverId: aId, reason: aError });
return;
}
aMm.sendAsyncMessage(resolveMsg, { resolverId: aId, value: aResult });
};
},
getStats: function(aMm, aData) {
if (DEBUG) {
debug("getStats(): " + JSON.stringify(aData));
}
// Note: we validate the manifestURL in _db.getStats().
let manifestURL = aData.statsOptions.manifestURL || "";
let serviceType = aData.statsOptions.serviceType || "";
let component = aData.statsOptions.component || "";
// Execute DB operation.
let onStatsGot = this._createDbCallback(aMm, aData.resolverId,
"ResourceStats:GetStats");
this._db.getStats(aData.type, manifestURL, serviceType, component,
aData.start, aData.end, onStatsGot);
},
clearStats: function(aMm, aData) {
if (DEBUG) {
debug("clearStats(): " + JSON.stringify(aData));
}
// Get appId and check whether manifestURL is a valid app.
let appId = 0;
let manifestURL = aData.statsOptions.manifestURL || "";
if (manifestURL) {
appId = appsService.getAppLocalIdByManifestURL(manifestURL);
if (!appId) {
aMm.sendAsyncMessage("ResourceStats:GetStats:Rejected", {
resolverId: aData.resolverId,
reason: "Invalid manifestURL"
});
return;
}
}
let serviceType = aData.statsOptions.serviceType || "";
let component = aData.statsOptions.component || "";
// Execute DB operation.
let onStatsCleared = this._createDbCallback(aMm, aData.resolverId,
"ResourceStats:ClearStats");
this._db.clearStats(aData.type, appId, serviceType, component,
aData.start, aData.end, onStatsCleared);
},
clearAllStats: function(aMm, aData) {
if (DEBUG) {
debug("clearAllStats(): " + JSON.stringify(aData));
}
// Execute DB operation.
let onAllStatsCleared = this._createDbCallback(aMm, aData.resolverId,
"ResourceStats:ClearAllStats");
this._db.clearAllStats(aData.type, onAllStatsCleared);
},
addAlarm: function(aMm, aData) {
if (DEBUG) {
debug("addAlarm(): " + JSON.stringify(aData));
}
// Get appId and check whether manifestURL is a valid app.
let manifestURL = aData.statsOptions.manifestURL;
if (manifestURL) {
let appId = appsService.getAppLocalIdByManifestURL(manifestURL);
if (!appId) {
aMm.sendAsyncMessage("ResourceStats:GetStats:Rejected", {
resolverId: aData.resolverId,
reason: "Invalid manifestURL"
});
return;
}
}
// Create an alarm object.
let newAlarm = {
type: aData.type,
component: aData.statsOptions.component || "",
serviceType: aData.statsOptions.serviceType || "",
manifestURL: manifestURL || "",
threshold: aData.threshold,
startTime: aData.startTime,
data: aData.data
};
// Execute DB operation.
let onAlarmAdded = this._createDbCallback(aMm, aData.resolverId,
"ResourceStats:AddAlarm");
this._db.addAlarm(newAlarm, onAlarmAdded);
},
getAlarms: function(aMm, aData) {
if (DEBUG) {
debug("getAlarms(): " + JSON.stringify(aData));
}
let options = null;
let statsOptions = aData.statsOptions;
// If all keys in statsOptions are set to null, treat this call as quering
// all alarms; otherwise, resolve the statsOptions and perform DB query
// according to the resolved result.
if (statsOptions.manifestURL || statsOptions.serviceType ||
statsOptions.component) {
// Validate manifestURL.
let manifestURL = statsOptions.manifestURL || "";
if (manifestURL) {
let appId = appsService.getAppLocalIdByManifestURL(manifestURL);
if (!appId) {
aMm.sendAsyncMessage("ResourceStats:GetStats:Rejected", {
resolverId: aData.resolverId,
reason: "Invalid manifestURL"
});
return;
}
}
options = {
manifestURL: manifestURL,
serviceType: statsOptions.serviceType || "",
component: statsOptions.component || ""
};
}
// Execute DB operation.
let onAlarmsGot = this._createDbCallback(aMm, aData.resolverId,
"ResourceStats:GetAlarms");
this._db.getAlarms(aData.type, options, onAlarmsGot);
},
removeAlarm: function(aMm, aData) {
if (DEBUG) {
debug("removeAlarm(): " + JSON.stringify(aData));
}
// Execute DB operation.
let onAlarmRemoved = function(aError, aResult) {
if (aError) {
aMm.sendAsyncMessage("ResourceStats:RemoveAlarm:Rejected",
{ resolverId: aData.resolverId, reason: aError });
}
if (!aResult) {
aMm.sendAsyncMessage("ResourceStats:RemoveAlarm:Rejected",
{ resolverId: aData.resolverId,
reason: "alarm not existed" });
}
aMm.sendAsyncMessage("ResourceStats:RemoveAlarm:Resolved",
{ resolverId: aData.resolverId, value: aResult });
};
this._db.removeAlarm(aData.type, aData.alarmId, onAlarmRemoved);
},
removeAllAlarms: function(aMm, aData) {
if (DEBUG) {
debug("removeAllAlarms(): " + JSON.stringify(aData));
}
// Execute DB operation.
let onAllAlarmsRemoved = this._createDbCallback(aMm, aData.resolverId,
"ResourceStats:RemoveAllAlarms");
this._db.removeAllAlarms(aData.type, onAllAlarmsRemoved);
},
getComponents: function(aMm, aData) {
if (DEBUG) {
debug("getComponents(): " + JSON.stringify(aData));
}
// Execute DB operation.
let onComponentsGot = this._createDbCallback(aMm, aData.resolverId,
"ResourceStats:GetComponents");
this._db.getComponents(aData.type, onComponentsGot);
},
};
this.ResourceStatsService.init();

View File

@ -1,22 +0,0 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
EXTRA_COMPONENTS += [
'ResourceStatsManager.js',
'ResourceStatsManager.manifest',
]
EXTRA_JS_MODULES += [
'ResourceStatsDB.jsm',
'ResourceStatsService.jsm',
]
FINAL_LIBRARY = 'xul'
if CONFIG['MOZ_B2G_RIL']:
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']

View File

@ -1,16 +0,0 @@
[test_basic.html]
skip-if = toolkit != "gonk"
[test_network_stats.html]
skip-if = toolkit != "gonk"
[test_power_stats.html]
skip-if = toolkit != "gonk"
[test_network_alarm.html]
skip-if = toolkit != "gonk"
[test_power_alarm.html]
skip-if = toolkit != "gonk"
[test_disabled_pref.html]
skip-if = toolkit != "gonk"
[test_no_perm.html]
skip-if = toolkit != "gonk"
[test_not_supported_type.html]
skip-if = toolkit != "gonk"

View File

@ -1,41 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test accessibility of interfaces</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
// Test accessibility of interfaces.
SpecialPowers.addPermission("resourcestats-manage", true, document);
SpecialPowers.pushPrefEnv({ 'set': [
["dom.resource_stats.enabled", true],
["dom.ignore_webidl_scope_checks", true]
]}, function() {
ok(SpecialPowers.hasPermission("resourcestats-manage", document),
"Has permission 'resourcestats-manage'.");
ok(SpecialPowers.getBoolPref("dom.resource_stats.enabled"),
"Preference 'dom.resource_stats.enabled' is true.");
// Check all interfaces are accessible.
ok('ResourceStatsManager' in window, "ResourceStatsManager exist.");
ok('ResourceStatsAlarm' in window, "ResourceStatsAlarm exist.");
ok('ResourceStats' in window, "ResourceStats exist.");
ok('NetworkStatsData' in window, "NetworkStatsData exist.");
ok('PowerStatsData' in window, "PowerStatsData exist.");
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -1,41 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test to ensure interface is not accessible when preference is disabled</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
// Test to ensure interface is not accessible when preference is disabled.
SpecialPowers.addPermission("resourcestats-manage", true, document);
SpecialPowers.pushPrefEnv({ 'set': [
["dom.resource_stats.enabled", false],
["dom.ignore_webidl_scope_checks", true]
]}, function() {
ok(SpecialPowers.hasPermission("resourcestats-manage", document),
"Has permission 'resourcestats-manage'.");
ok(!(SpecialPowers.getBoolPref("dom.resource_stats.enabled")),
"Preference 'dom.resource_stats.enabled' is false.");
// Check accessibility.
is('ResourceStatsManager' in window, false, "ResourceStatsManager should not exist.");
is('ResourceStatsAlarm' in window, false, "ResourceStatsAlarm should not exist.");
is('ResourceStats' in window, false, "ResourceStats should not exist.");
is('NetworkStatsData' in window, false, "NetworkStatsData should not exist.");
is('PowerStatsData' in window, false, "PowerStatsData should not exist.");
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -1,356 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for ResourceStats methods realted to network resource control</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
const invalidManifestURL = "app://invalid.gaiamobile.org/manifest.webapp";
const wifiComponent = "wifi:0";
const mobileComponent = "mobile:1";
var networkStatsMgr = null; // ResourceStatsManager for network statistics.
function errorCb(reason) {
ok(false, reason);
}
// Check the content returned by getAlarms.
function checkAlarmsArray(alarms) {
// Check if data is an array.
if (!Array.isArray(alarms)) {
throw "getAlarms does not return an array.";
} else {
ok(true, "getAlarms returns an array.")
}
// Iterate the array and check the type of each element.
var obj = null;
var message = null; // Message for exception
for (var i = 0; i < alarms.length; i++) {
obj = alarms[i];
// Check if obj is an instance os ResourceStatsAlarm.
if (!(obj instanceof ResourceStatsAlarm)) {
message = "The array contains a non-ResourceStatsAlarm object.";
break;
}
// Check if obj.type is network.
if (obj.type != "network") {
message = "The type of a ResourceStatsAlarm object is not network.";
break;
}
}
if (message) {
throw message;
}
ok(true, "The return is an array of ResourceStatsAlarm objects.");
}
// Test Cases for testing WebIDL methods related to resource control.
var testCases = [
function() {
// Test removeAllAlarms.
var promise = networkStatsMgr.removeAllAlarms();
promise.then(function() {
ok(true, "removeAllAlarms deleted all network alarms.");
testMethods();
}, function() {
ok(false, "removeAllAlarms failed to delete network alarms.");
});
},
function() {
// Test addAlarm.
var threshold = Math.floor(Math.random() * 1000);
var promise = networkStatsMgr.addAlarm(threshold,
{ 'component': wifiComponent },
{ 'startTime': Date.now() });
promise.then(function(value) {
// Check the value (alarmId).
if (value < 0) {
ok(false, "addAlarm failed to create an alarm.");
} else {
ok(true, "addAlarm created an alarm.");
testMethods();
}
}, function() {
ok(false, "addAlarm failed to create an alarm.");
});
},
function() {
// Test addAlarm with negative threshold.
var threshold = -1;
var promise = networkStatsMgr.addAlarm(threshold,
{ 'component': wifiComponent },
{ 'startTime': Date.now() });
promise.then(function() {
// Check the value.
ok(false,
"addAlarm did not throw an exception when negative threshold is set.");
}, function() {
ok(true, "addAlarm threw an exception when negative threshold is set.");
testMethods();
});
},
function() {
// Test addAlarm with no threshold.
var promise = networkStatsMgr.addAlarm();
promise.then(function() {
// Check the value.
ok(false, "addAlarm did not throw an exception when no threshold.");
}, function() {
ok(true, "addAlarm threw an exception when no threshold.");
testMethods();
});
},
function() {
// Test addAlarm with negative startTime.
var threshold = Math.floor(Math.random() * 1000);
var promise = networkStatsMgr.addAlarm(threshold,
{ 'component': wifiComponent },
{ 'startTime': -1 });
promise.then(function() {
// Check the value.
ok(false,
"addAlarm did not throw an exception when negative startTime is set.");
}, function() {
ok(true, "addAlarm threw an exception when negative startTime is set.");
testMethods();
});
},
function() {
// Test addAlarm when manifestURL is invalid.
var threshold = Math.floor(Math.random() * 1000);
var promise = networkStatsMgr.addAlarm(threshold,
{ 'component': wifiComponent,
'manifestURL': invalidManifestURL },
{ 'startTime': Date.now() });
promise.then(function() {
// Check the value.
ok(false, "addAlarm did not throw an exception when manifestURL is invalid.");
}, function() {
ok(true, "addAlarm threw an exception when manifestURL is invalid.");
testMethods();
});
},
function() {
// Test getAlarms.
var alarmId;
var alarms;
var threshold = Math.floor(Math.random() * 1000);
// Execution steps:
// 1. Add a new alarm.
var promise = networkStatsMgr.addAlarm(threshold,
{ 'component': wifiComponent },
{ 'startTime': Date.now() });
// 2. Test getAlarms if new alarm is added.
var runGetAlarms = function(value) {
alarmId = value;
return networkStatsMgr.getAlarms({ 'component': wifiComponent });
};
// 3. Check the content returned by getAlarms.
var checkGetAlarmsReturn = function(value) {
alarms = value;
checkAlarmsArray(value);
};
// 4. Check the alarm added in step 1 is inside the return of getAlarms.
var checkAlarm = function (value) {
// Find the alarm.
var index = alarms.map(function(e) { return e.alarmId; })
.indexOf(alarmId);
if (index < 0) {
throw "getAlarms does not get the alarm added in previous step.";
}
var alarm = alarms[index];
// Evaluate the alarm.
ok(alarm.threshold == threshold, "threshold is equal.");
ok(alarm.component == wifiComponent, "component is equal.");
ok(alarm.serviceType == null, "serviceType should be null.");
ok(alarm.manifestURL == null, "manifestURL should be null.");
};
// Create promise chaining.
promise.then(runGetAlarms)
.then(checkGetAlarmsReturn)
.then(checkAlarm)
.then(testMethods, errorCb); // Execute next test case.
},
function() {
// Test getAlarms with invalid manifestURL.
var threshold = Math.floor(Math.random() * 1000);
var promise = networkStatsMgr.addAlarm(threshold,
{ 'component': wifiComponent,
'manifestURL': invalidManifestURL },
{ 'startTime': Date.now() });
promise.then(function() {
// Check the value.
ok(false, "getAlarms did not throw an exception when manifestURL is invalid.");
}, function() {
ok(true, "getAlarms threw an exception when manifestURL is invalid.");
testMethods();
});
},
function() {
// Test getAlarms with incorrect parameter.
var threshold = Math.floor(Math.random() * 1000);
// Execution steps:
// 1. Add a new alarm.
var promise = networkStatsMgr.addAlarm(threshold,
{ 'component': wifiComponent },
{ 'startTime': Date.now() });
// 2. Call getAlarms with incorrect parameter.
var runGetAlarms = function() {
return networkStatsMgr.getAlarms({ 'component': mobileComponent });
};
// 3. check the content returned by getAlarms.
var checkGetAlarmsReturn = function(value) {
// Check array length
if (value.length) {
throw "getAlarms gets an alarm when using incorrect parameter.";
} else {
ok(true,
"getAlarms returns an empty array when using incorrect parameter.");
}
};
// Create pomise chaining.
promise.then(runGetAlarms)
.then(checkGetAlarmsReturn)
.then(testMethods, errorCb); // Execute next test case.
},
function() {
// Test removeAlarm
var alarmId;
var threshold = Math.floor(Math.random() * 1000);
// Execution steps:
// 1. Add a new alarm.
var promise = networkStatsMgr.addAlarm(threshold,
{ 'component': wifiComponent },
{ 'startTime': Date.now() });
// 2. Try to remove the new alarm.
var runRemoveAlarm = function(value) {
alarmId = value;
return networkStatsMgr.removeAlarm(alarmId);
}
// Create promise chaining.
promise.then(runRemoveAlarm)
.then(function() {
ok(true, "removeAlarm deleted the alarm.");
testMethods();
}, errorCb);
},
function() {
// Test removeAlarm with negative alarmId
var alarmId = -1;
var promise = networkStatsMgr.removeAlarm(alarmId);
promise.then(function() {
ok(false,
"removeAlarm did not throw an exception when negative alarmId is set.");
}, function() {
ok(true, "removeAlarm threw an exception when negative alarmId is set.");
testMethods();
});
},
function() {
// Test removeAlarm with invalid alarmId
var alarmId;
var threshold = Math.floor(Math.random() * 1000);
// Execution steps:
// 1. Add a new alarm.
var promise = networkStatsMgr.addAlarm(threshold,
{ 'component': wifiComponent },
{ 'startTime': Date.now() });
// 2. Try to remove an invalid alarm.
var runRemoveAlarm = function(value) {
alarmId = value;
// Because alarmId is auto-increment, any alarmId larger than the
// latest alarmId should be invalid.
return networkStatsMgr.removeAlarm(alarmId + 10);
}
// Create promise chaining.
promise.then(runRemoveAlarm)
.then(function() {
// Input with incorrect alarmId should not be resolved.
throw "removeAlarm should fail with invalid alarmId.";
}, function(reason) {
if (reason == "alarm not existed") {
ok(true, "removeAlarm with invalid alarmId should fail.")
} else {
throw reason;
}
})
.then(testMethods, errorCb);
}
];
// Test WebIDL methods related stats operation.
function testMethods() {
if (!testCases.length) {
ok(true, "Done.");
SpecialPowers.removePermission("resourcestats-manage", document);
SimpleTest.finish();
return;
}
var testCase = testCases.shift();
testCase();
}
function startTest() {
// Create an instance of ResourceStatsManager for network.
networkStatsMgr = new ResourceStatsManager("network");
ok(networkStatsMgr, "Create networkStatsMgr.");
// Test WebIDL methods related to resource control.
testMethods();
}
SimpleTest.waitForExplicitFinish();
// Enable permission and preference.
SpecialPowers.addPermission("resourcestats-manage", true, document);
SpecialPowers.pushPrefEnv({ 'set': [
["dom.resource_stats.enabled", true],
["dom.ignore_webidl_scope_checks", true]
]}, startTest);
</script>
</pre>
</body>
</html>

View File

@ -1,345 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for ResourceStats methods realted to network statistics</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
const invalidManifestURL = "app://invalid.gaiamobile.org/manifest.webapp";
var networkStatsMgr = null; // ResourceStatsManager for network statistics.
var sampleRate = 0;
// Test WebIDL attributes.
function testAttributes() {
// Test sampleRate.
ok('sampleRate' in networkStatsMgr,
"sampleRate should be a ResourceStatsManager attribute.");
sampleRate = networkStatsMgr.sampleRate;
ok(sampleRate > 0, "sampleRate is greater than 0.");
// Test maxStorageAge.
ok('maxStorageAge' in networkStatsMgr,
"maxStorageAge should be a ResourceStatsManager attribute.");
ok(networkStatsMgr.maxStorageAge > 0,
"maxStorageAge is greater than 0.");
// Test whether "network" in resourceTypes array.
ok('resourceTypes' in networkStatsMgr,
"resourceTypes should be a ResourceStatsManager attribute.");
ok(Array.isArray(networkStatsMgr.resourceTypes),
"networkStatsMgr.resourceTypes is an array.");
ok(networkStatsMgr.resourceTypes.indexOf("network") > -1,
"'network' is an element of networkStatsMgr.resourceTypes.");
}
// Check the content returned by ResourceStats.getData().
function checkData(data, start, end) {
// Check if data is an array.
if (!Array.isArray(data)) {
ok(false, "getData does not return an array.")
return;
} else {
ok(true, "getData returns an array.")
}
// Iterate the array and check the timestamp and type of each element.
var success = true;
var obj = null;
var timestamp = start;
var i = 0;
var length = data.length;
do {
obj = data[i++];
// Check object type.
if (!(obj instanceof NetworkStatsData)) {
success = false;
ok(false, "The array contains a non-NetworkStatsData object.");
break;
}
// Check if the timestamp is continuous.
if (obj.timestamp !== timestamp) {
success = false;
ok(false, "The timestamp of NetworkStatsData object is correct.");
break;
}
timestamp += sampleRate;
} while (i < length);
if (!success) {
return;
}
// Check the timestamp of the last element is equal to end.
if (obj.timestamp != end) {
ok(false,
"The timestamp of the last element of the array is equal to end.");
return;
}
// Execute next test case.
ok(true, "The return of getData is an array of NetworkStatsData objects.");
testMethods();
}
// Test Cases for testing WebIDL methods.
var testCases = [
function() {
// Test clearAllStats.
var promise = networkStatsMgr.clearAllStats();
promise.then(function() {
ok(true, "clearAllStats clears the network store.");
testMethods();
}, function() {
ok(false, "clearAllStats fails to clear the network store.");
});
},
function() {
// Test clearStats.
var promise = networkStatsMgr.clearStats();
promise.then(function() {
ok(true, "clearStats clears the network store.");
testMethods();
}, function() {
ok(false, "clearStats fails to clear the network store.");
});
},
function() {
// Check if clearStats throw exception when start is great than end.
var end = Date.now();
var start = end + 1000;
var promise = networkStatsMgr.clearStats(null, start, end);
promise.then(function() {
ok(false,
"clearStats does not throw exception when start is great than end.");
}, function() {
ok(true, "clearStats throw exception when start is great than end.");
testMethods();
});
},
function() {
// Check if clearStats throw exception when start is less than 0.
var end = Date.now();
var start = -1;
var promise = networkStatsMgr.clearStats(null, start, end);
promise.then(function() {
ok(false,
"clearStats dose not throw exception when start is less than 0.");
}, function() {
ok(true, "clearStats throw exception when start is less than 0.");
testMethods();
});
},
function() {
// Check if clearStats throw exception when manifestURL is invalid.
var options = {manifestURL: invalidManifestURL};
var promise = networkStatsMgr.clearStats(options);
promise.then(function() {
ok(false,
"clearStats does not throw exception when manifestURL is invalid.");
}, function() {
ok(true, "clearStats throw exception when manifestURL is invalid.");
testMethods();
});
},
function() {
// Test getAvailableComponents.
var promise = networkStatsMgr.getAvailableComponents();
promise.then(function(value) {
if (Array.isArray(value)) {
ok(true, "getAvailableComponents returns an array.");
testMethods();
} else {
ok(false, "getAvailableComponents does not return an array.");
}
}, function() {
ok(false, "Fail to execute getAvailableComponents.");
});
},
function() {
// Test getStats.
ok(true, "Get system stats when start and end are adapted to sampleRate.");
// Prepare start and end.
var offset = (new Date()).getTimezoneOffset() * 60 * 1000;
var end = Math.floor((Date.now() - offset) / sampleRate) * sampleRate + offset;
var start = end - sampleRate * 10;
// Launch request.
var promise = networkStatsMgr.getStats(null, start, end);
promise.then(function(value) {
// Check the object type.
if (value instanceof ResourceStats) {
ok(true, "Get a ResourceStats object.");
} else {
ok(false, "Fail to get a ResourceStats object.");
return;
}
// Check attributes of ResourceStats.
ok(value.type == "network", "type should be network.");
ok(value.component == null, "component should be null.");
ok(value.serviceType == null, "serviceType should be null.");
ok(value.manifestURL == null, "manifestURL should be null.");
// Check if the time range of ResourceStats is equal to the request.
ok(value.start == start, "start timestamp should be equal.");
ok(value.end == end, "end timestamp should be equal.");
// Check stats stored inside ResourceStats.
if ('getData' in value) {
checkData(value.getData(), start, end);
} else {
ok(false, "getData is not a method of ResourceStats.");
return;
}
}, function() {
ok(false, "Get network stats failed.");
});
},
function() {
// Test getStats when start and end are not adapted to sampleRate.
ok(true,
"Get system stats when start and end are not adapted to sampleRate.");
// Prepare start and end.
var end = Date.now();
var start = end - sampleRate * 10;
// Normalize start and end.
var offset = (new Date()).getTimezoneOffset() * 60 * 1000;
var normEnd = Math.floor((end - offset) / sampleRate)
* sampleRate + offset;
var normStart = Math.floor((start - offset) / sampleRate)
* sampleRate + offset;
// Launch request.
var promise = networkStatsMgr.getStats(null, start, end);
promise.then(function(value) {
// Check the object type.
if (value instanceof ResourceStats) {
ok(true, "Get a ResourceStats object.");
} else {
ok(false, "Fail to get a ResourceStats object.");
return;
}
// Check attributes of ResourceStats.
ok(value.type == "network", "type should be network.");
ok(value.component == null, "component should be null.");
ok(value.serviceType == null, "serviceType should be null.");
ok(value.manifestURL == null, "manifestURL should be null.");
// Check if time range of ResourceStats are normalized.
ok(value.start == normStart, "start timestamp should be normalized.");
ok(value.end == normEnd, "end timestamp should be normalized.");
// Check stats stored inside ResourceStats.
if ('getData' in value) {
checkData(value.getData(), normStart, normEnd);
} else {
ok(false, "getData is not a method of ResourceStats.");
return;
}
}, function() {
ok(false, "Get network stats failed.");
});
},
function () {
// Check if getStats throw exception when start is greater than end.
var end = Date.now();
var start = end + 1000;
var promise = networkStatsMgr.getStats(null, start, end);
promise.then(function() {
ok(false,
"getStats dose not throw exception when start is great than end.");
}, function() {
ok(true, "getStats throw exception when start is great than end.");
testMethods();
});
},
function() {
// Check if getStats throw exception when start is less than 0.
var end = Date.now();
var start = -1;
var promise = networkStatsMgr.getStats(null, start, end);
promise.then(function() {
ok(false,
"getStats dose not throw exception when start is less than 0.");
}, function() {
ok(true, "getStats throw exception when start is less than 0.");
testMethods();
});
},
function() {
// Check if getStats throw exception when manifestURL is invalid.
var options = {manifestURL: invalidManifestURL};
var promise = networkStatsMgr.getStats(options);
promise.then(function(value) {
ok(false,
"getStats does not throw exception when manifestURL is invalid.");
}, function() {
ok(true, "getStats throw exception when manifestURL is invalid.");
testMethods();
});
}
];
// Test WebIDL methods related stats operation.
function testMethods() {
if (!testCases.length) {
ok(true, "Done.");
SpecialPowers.removePermission("resourcestats-manage", document);
SimpleTest.finish();
return;
}
var testCase = testCases.shift();
testCase();
}
function startTest() {
// Create an instance of ResourceStatsManager for network stats.
networkStatsMgr = new window.ResourceStatsManager("network");
ok(networkStatsMgr, "Create networkStatsMgr.");
// Test WebIDL attributes.
testAttributes();
// Test WebIDL methods related to stats operation.
testMethods();
}
SimpleTest.waitForExplicitFinish();
// Enable permission and preference.
SpecialPowers.addPermission("resourcestats-manage", true, document);
SpecialPowers.pushPrefEnv({ 'set': [
["dom.resource_stats.enabled", true],
["dom.ignore_webidl_scope_checks", true]
]}, startTest);
</script>
</pre>
</body>
</html>

View File

@ -1,38 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test to ensure ResourceStatsManager is not accessible without permission</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
SimpleTest.waitForExplicitFinish();
// Test to ensure ResourceStatsManager is not accessible without permission.
SpecialPowers.removePermission("resourcestats-manage", document);
SpecialPowers.pushPrefEnv({ 'set': [
["dom.resource_stats.enabled", true],
["dom.ignore_webidl_scope_checks", true]
]}, function() {
ok(!(SpecialPowers.hasPermission("resourcestats-manage", document)),
"Do not have permission 'resourcestats-manage'.");
ok(SpecialPowers.getBoolPref("dom.resource_stats.enabled"),
"Preference 'dom.resource_stats.enabled' is true.");
// Check ResourceStatsManager exist.
ok(!('ResourceStatsManager' in window),
"Cannot access window.ResourceStatsManager when have no permission");
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -1,41 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test to ensure ResourceStatsManager does not create an instance for non-supported type</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
const type = "non-supported";
SimpleTest.waitForExplicitFinish();
// Test to ensure ResourceStatsManager does not create an instance for
// non-supported type.
SpecialPowers.addPermission("resourcestats-manage", true, document);
SpecialPowers.pushPrefEnv({ 'set': [
["dom.resource_stats.enabled", true],
["dom.ignore_webidl_scope_checks", true]
]}, function() {
try {
var mgr = ResourceStatsManager(type);
ok(false,
"Creating an instance for non-supported type should throw an exeception.");
} catch (ex) {
ok(ex,
"Got an exception when creating an instance for non-supported type.");
}
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

View File

@ -1,355 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for ResourceStats methods realted to power resource control</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
const invalidManifestURL = "app://invalid.gaiamobile.org/manifest.webapp";
const cpuComponent = "cpu:0";
const gpsComponent = "gps:0";
var powerStatsMgr = null; // ResourceStatsManager for power statistics.
function errorCb(reason) {
ok(false, reason);
}
// Check the content returned by getAlarms.
function checkAlarmsArray(alarms) {
// Check if data is an array.
if (!Array.isArray(alarms)) {
throw "getAlarms does not return an array.";
} else {
ok(true, "getAlarms returns an array.")
}
// Iterate the array and check the type of each element.
var obj = null;
var message = null; // Message for exception
for (var i = 0; i < alarms.length; i++) {
obj = alarms[i];
// Check if obj is an instance os ResourceStatsAlarm.
if (!(obj instanceof ResourceStatsAlarm)) {
message = "The array contains a non-ResourceStatsAlarm object.";
break;
}
// Check if obj.type is power.
if (obj.type != "power") {
message = "The type of a ResourceStatsAlarm object is not power.";
break;
}
}
if (message) {
throw message;
}
ok(true, "The return is an array of ResourceStatsAlarm objects.");
}
// Test Cases for testing WebIDL methods related to resource control.
var testCases = [
function() {
// Test removeAllAlarms.
var promise = powerStatsMgr.removeAllAlarms();
promise.then(function() {
ok(true, "removeAllAlarms deleted all power alarms.");
testMethods();
}, function() {
ok(false, "removeAllAlarms failed to delete power alarms.");
});
},
function() {
// Test addAlarm.
var threshold = Math.floor(Math.random() * 1000);
var promise = powerStatsMgr.addAlarm(threshold,
{ 'component': cpuComponent },
{ 'startTime': Date.now() });
promise.then(function(value) {
// Check the value (alarmId).
if (value < 0) {
ok(false, "addAlarm failed to create an alarm.");
} else {
ok(true, "addAlarm created an alarm.");
testMethods();
}
}, function() {
ok(false, "addAlarm failed to create an alarm.");
});
},
function() {
// Test addAlarm with negative threshold.
var threshold = -1;
var promise = powerStatsMgr.addAlarm(threshold,
{ 'component': cpuComponent },
{ 'startTime': Date.now() });
promise.then(function() {
// Check the value.
ok(false,
"addAlarm did not throw an exception when negative threshold is set.");
}, function() {
ok(true, "addAlarm threw an exception when negative threshold is set.");
testMethods();
});
},
function() {
// Test addAlarm with no threshold.
var promise = powerStatsMgr.addAlarm();
promise.then(function() {
// Check the value.
ok(false, "addAlarm did not throw an exception when no threshold.");
}, function() {
ok(true, "addAlarm threw an exception when no threshold.");
testMethods();
});
},
function() {
// Test addAlarm with negative startTime.
var threshold = Math.floor(Math.random() * 1000);
var promise = powerStatsMgr.addAlarm(threshold,
{ 'component': cpuComponent },
{ 'startTime': -1 });
promise.then(function() {
// Check the value.
ok(false,
"addAlarm did not throw an exception when negative startTime is set.");
}, function() {
ok(true, "addAlarm threw an exception when negative startTime is set.");
testMethods();
});
},
function() {
// Test addAlarm when manifestURL is invalid.
var threshold = Math.floor(Math.random() * 1000);
var promise = powerStatsMgr.addAlarm(threshold,
{ 'component': cpuComponent,
'manifestURL': invalidManifestURL },
{ 'startTime': Date.now() });
promise.then(function() {
// Check the value.
ok(false, "addAlarm did not throw an exception when manifestURL is invalid.");
}, function() {
ok(true, "addAlarm threw an exception when manifestURL is invalid.");
testMethods();
});
},
function() {
// Test getAlarms.
var alarmId;
var alarms;
var threshold = Math.floor(Math.random() * 1000);
// Execution steps:
// 1. Add a new alarm.
var promise = powerStatsMgr.addAlarm(threshold,
{ 'component': cpuComponent },
{ 'startTime': Date.now() });
// 2. Test getAlarms if new alarm is added.
var runGetAlarms = function(value) {
alarmId = value;
return powerStatsMgr.getAlarms({ 'component': cpuComponent });
};
// 3. Check the content returned by getAlarms.
var checkGetAlarmsReturn = function(value) {
alarms = value;
checkAlarmsArray(value);
};
// 4. Check the alarm added in step 1 is inside the return of getAlarms.
var checkAlarm = function (value) {
// Find the alarm.
var index = alarms.map(function(e) { return e.alarmId; })
.indexOf(alarmId);
if (index < 0) {
throw "getAlarms does not get the alarm added in previous step.";
}
var alarm = alarms[index];
// Evaluate the alarm.
ok(alarm.threshold == threshold, "threshold is equal.");
ok(alarm.component == cpuComponent, "component is equal.");
ok(alarm.serviceType == null, "serviceType should be null.");
ok(alarm.manifestURL == null, "manifestURL should be null.");
};
// Create promise chaining.
promise.then(runGetAlarms)
.then(checkGetAlarmsReturn)
.then(checkAlarm)
.then(testMethods, errorCb); // Execute next test case.
},
function() {
// Test getAlarms with invalid manifestURL.
var threshold = Math.floor(Math.random() * 1000);
var promise = powerStatsMgr.addAlarm(threshold,
{ 'component': cpuComponent,
'manifestURL': invalidManifestURL },
{ 'startTime': Date.now() });
promise.then(function() {
// Check the value.
ok(false, "getAlarms did not throw an exception when manifestURL is invalid.");
}, function() {
ok(true, "getAlarms threw an exception when manifestURL is invalid.");
testMethods();
});
},
function() {
// Test getAlarms with incorrect parameter.
var threshold = Math.floor(Math.random() * 1000);
// Execution steps:
// 1. Add a new alarm.
var promise = powerStatsMgr.addAlarm(threshold,
{ 'component': cpuComponent },
{ 'startTime': Date.now() });
// 2. Call getAlarms with incorrect parameter.
var runGetAlarms = function() {
return powerStatsMgr.getAlarms({ 'component': gpsComponent });
};
// 3. check the content returned by getAlarms.
var checkGetAlarmsReturn = function(value) {
// Check array length
if (value.length) {
throw "getAlarms gets an alarm when using incorrect parameter.";
} else {
ok(true,
"getAlarms returns an empty array when using incorrect parameter.");
}
};
// Create pomise chaining.
promise.then(runGetAlarms)
.then(checkGetAlarmsReturn)
.then(testMethods, errorCb); // Execute next test case.
},
function() {
// Test removeAlarm
var alarmId;
var threshold = Math.floor(Math.random() * 1000);
// Execution steps:
// 1. Add a new alarm.
var promise = powerStatsMgr.addAlarm(threshold,
{ 'component': cpuComponent },
{ 'startTime': Date.now() });
// 2. Try to remove the new alarm.
var runRemoveAlarm = function(value) {
alarmId = value;
return powerStatsMgr.removeAlarm(alarmId);
}
// Create promise chaining.
promise.then(runRemoveAlarm)
.then(function() {
ok(true, "removeAlarm deleted the alarm.");
testMethods();
}, errorCb);
},
function() {
// Test removeAlarm with negative alarmId
var alarmId = -1;
var promise = powerStatsMgr.removeAlarm(alarmId);
promise.then(function() {
ok(false,
"removeAlarm did not throw an exception when negative alarmId is set.");
}, function() {
ok(true, "removeAlarm threw an exception when negative alarmId is set.");
testMethods();
});
},
function() {
// Test removeAlarm with invalid alarmId
var alarmId;
var threshold = Math.floor(Math.random() * 1000);
// Execution steps:
// 1. Add a new alarm.
var promise = powerStatsMgr.addAlarm(threshold,
{ 'component': cpuComponent },
{ 'startTime': Date.now() });
// 2. Try to remove an invalid alarm.
var runRemoveAlarm = function(value) {
alarmId = value;
// Because alarmId is auto-increment, any alarmId larger than the
// latest alarmId should be invalid.
return powerStatsMgr.removeAlarm(alarmId + 10);
}
// Create promise chaining.
promise.then(runRemoveAlarm)
.then(function() {
// Input with incorrect alarmId should not be resolved.
throw "removeAlarm should fail with invalid alarmId.";
}, function(reason) {
if (reason == "alarm not existed") {
ok(true, "removeAlarm with invalid alarmId should fail.")
} else {
throw reason;
}
})
.then(testMethods, errorCb);
}
];
// Test WebIDL methods related stats operation.
function testMethods() {
if (!testCases.length) {
ok(true, "Done.");
SpecialPowers.removePermission("resourcestats-manage", document);
SimpleTest.finish();
return;
}
var testCase = testCases.shift();
testCase();
}
function startTest() {
// Create an instance of ResourceStatsManager for power.
powerStatsMgr = new ResourceStatsManager("power");
ok(powerStatsMgr, "Create powerStatsMgr.");
// Test WebIDL methods related to resource control.
testMethods();
}
SimpleTest.waitForExplicitFinish();
// Enable permission and preference.
SpecialPowers.addPermission("resourcestats-manage", true, document);
SpecialPowers.pushPrefEnv({ 'set': [
["dom.resource_stats.enabled", true],
["dom.ignore_webidl_scope_checks", true]
]}, startTest);
</script>
</pre>
</body>
</html>

View File

@ -1,345 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test for ResourceStats methods realted to power statistics</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript">
const invalidManifestURL = "app://invalid.gaiamobile.org/manifest.webapp";
var powerStatsMgr = null; // ResourceStatsManager for power statistics.
var sampleRate = 0;
// Test WebIDL attributes.
function testAttributes() {
// Test sampleRate.
ok('sampleRate' in powerStatsMgr,
"sampleRate should be a ResourceStatsManager attribute.");
sampleRate = powerStatsMgr.sampleRate;
ok(sampleRate > 0, "sampleRate is greater than 0.");
// Test maxStorageAge.
ok('maxStorageAge' in powerStatsMgr,
"maxStorageAge should be a ResourceStatsManager attribute.");
ok(powerStatsMgr.maxStorageAge > 0,
"maxStorageAge is greater than 0.");
// Test whether "power" in resourceTypes array.
ok('resourceTypes' in powerStatsMgr,
"resourceTypes should be a ResourceStatsManager attribute.");
ok(Array.isArray(powerStatsMgr.resourceTypes),
"powerStatsMgr.resourceTypes is an array.");
ok(powerStatsMgr.resourceTypes.indexOf("power") > -1,
"'power' is an element of powerStatsMgr.resourceTypes.");
}
// Check the content returned by ResourceStats.getData().
function checkData(data, start, end) {
// Check if data is an array.
if (!Array.isArray(data)) {
ok(false, "getData does not return an array.")
return;
} else {
ok(true, "getData returns an array.")
}
// Iterate the array and check the timestamp and type of each element.
var success = true;
var obj = null;
var timestamp = start;
var i = 0;
var length = data.length;
do {
obj = data[i++];
// Check object type.
if (!(obj instanceof PowerStatsData)) {
success = false;
ok(false, "The array contains a non-PowerStatsData object.");
break;
}
// Check if the timestamp is continuous.
if (obj.timestamp != timestamp) {
success = false;
ok(false, "The timestamp of PowerStatsData object is correct.");
break;
}
timestamp += sampleRate;
} while (i < length);
if (!success) {
return;
}
// Check the timestamp of the last element is equal to end.
if (obj.timestamp != end) {
ok(false,
"The timestamp of the last element of the array is equal to end.");
return;
}
// Execute next test case.
ok(true, "The return of getData is an array of PowerStatsData objects.");
testMethods();
}
// Test Cases for testing WebIDL methods.
var testCases = [
function() {
// Test clearAllStats.
var promise = powerStatsMgr.clearAllStats();
promise.then(function() {
ok(true, "clearAllStats clears the power store.");
testMethods();
}, function() {
ok(false, "clearAllStats fails to clear the power store.");
});
},
function() {
// Test clearStats.
var promise = powerStatsMgr.clearStats();
promise.then(function() {
ok(true, "clearStats clears the power store.");
testMethods();
}, function() {
ok(false, "clearStats fails to clear the power store.");
});
},
function() {
// Check if clearStats throw exception when start is great than end.
var end = Date.now();
var start = end + 1000;
var promise = powerStatsMgr.clearStats(null, start, end);
promise.then(function() {
ok(false,
"clearStats does not throw exception when start is great than end.");
}, function() {
ok(true, "clearStats throw exception when start is great than end.");
testMethods();
});
},
function() {
// Check if clearStats throw exception when start is less than 0.
var end = Date.now();
var start = -1;
var promise = powerStatsMgr.clearStats(null, start, end);
promise.then(function() {
ok(false,
"clearStats dose not throw exception when start is less than 0.");
}, function() {
ok(true, "clearStats throw exception when start is less than 0.");
testMethods();
});
},
function() {
// Check if clearStats throw exception when manifestURL is invalid.
var options = {manifestURL: invalidManifestURL};
var promise = powerStatsMgr.clearStats(options);
promise.then(function() {
ok(false,
"clearStats does not throw exception when manifestURL is invalid.");
}, function() {
ok(true, "clearStats throw exception when manifestURL is invalid.");
testMethods();
});
},
function() {
// Test getAvailableComponents.
var promise = powerStatsMgr.getAvailableComponents();
promise.then(function(value) {
if (Array.isArray(value)) {
ok(true, "getAvailableComponents returns an array.");
testMethods();
} else {
ok(false, "getAvailableComponents does not return an array.");
}
}, function() {
ok(false, "Fail to execute getAvailableComponents.");
});
},
function() {
// Test getStats.
ok(true, "Get system stats when start and end are adapted to sampleRate.");
// Prepare start and end.
var offset = (new Date()).getTimezoneOffset() * 60 * 1000;
var end = Math.floor((Date.now() - offset) / sampleRate) * sampleRate + offset;
var start = end - sampleRate * 10;
// Launch request.
var promise = powerStatsMgr.getStats(null, start, end);
promise.then(function(value) {
// Check the object type.
if (value instanceof ResourceStats) {
ok(true, "Get a ResourceStats object.");
} else {
ok(false, "Fail to get a ResourceStats object.");
return;
}
// Check attributes of ResourceStats.
ok(value.type == "power", "type should be power.");
ok(value.component == null, "component should be null.");
ok(value.serviceType == null, "serviceType should be null.");
ok(value.manifestURL == null, "manifestURL should be null.");
// Check if the time range of ResourceStats is equal to the request.
ok(value.start == start, "start timestamp should be equal.");
ok(value.end == end, "end timestamp should be equal.");
// Check stats stored inside ResourceStats.
if ('getData' in value) {
checkData(value.getData(), start, end);
} else {
ok(false, "getData is not a method of ResourceStats.");
return;
}
}, function() {
ok(false, "Get power stats failed.");
});
},
function() {
// Test getStats when start and end are not adapted to sampleRate.
ok(true,
"Get system stats when start and end are not adapted to sampleRate.");
// Prepare start and end.
var end = Date.now();
var start = end - sampleRate * 10;
// Normalize start and end.
var offset = (new Date()).getTimezoneOffset() * 60 * 1000;
var normEnd = Math.floor((end - offset) / sampleRate)
* sampleRate + offset;
var normStart = Math.floor((start - offset) / sampleRate)
* sampleRate + offset;
// Launch request.
var promise = powerStatsMgr.getStats(null, start, end);
promise.then(function(value) {
// Check the object type.
if (value instanceof ResourceStats) {
ok(true, "Get a ResourceStats object.");
} else {
ok(false, "Fail to get a ResourceStats object.");
return;
}
// Check attributes of ResourceStats.
ok(value.type == "power", "type should be power.");
ok(value.component == null, "component should be null.");
ok(value.serviceType == null, "serviceType should be null.");
ok(value.manifestURL == null, "manifestURL should be null.");
// Check if time range of ResourceStats are normalized.
ok(value.start == normStart, "start timestamp should be normalized.");
ok(value.end == normEnd, "end timestamp should be normalized.");
// Check stats stored inside ResourceStats.
if ('getData' in value) {
checkData(value.getData(), normStart, normEnd);
} else {
ok(false, "getData is not a method of ResourceStats.");
return;
}
}, function() {
ok(false, "Get power stats failed.");
});
},
function() {
// Check if getStats throw exception when start is greater than end.
var end = Date.now();
var start = end + 1000;
var promise = powerStatsMgr.getStats(null, start, end);
promise.then(function() {
ok(false,
"getStats dose not throw exception when start is great than end.");
}, function() {
ok(true, "getStats throw exception when start is great than end.");
testMethods();
});
},
function() {
// Check if getStats throw exception when start is less than 0.
var end = Date.now();
var start = -1;
var promise = powerStatsMgr.getStats(null, start, end);
promise.then(function() {
ok(false,
"getStats dose not throw exception when start is less than 0.");
}, function() {
ok(true, "getStats throw exception when start is less than 0.");
testMethods();
});
},
function() {
// Check if getStats throw exception when manifestURL is invalid.
var options = {manifestURL: invalidManifestURL};
var promise = powerStatsMgr.getStats(options);
promise.then(function(value) {
ok(false,
"getStats does not throw exception when manifestURL is invalid.");
}, function() {
ok(true, "getStats throw exception when manifestURL is invalid.");
testMethods();
});
}
];
// Test WebIDL methods related stats operation.
function testMethods() {
if (!testCases.length) {
ok(true, "Done.");
SpecialPowers.removePermission("resourcestats-manage", document);
SimpleTest.finish();
return;
}
var testCase = testCases.shift();
testCase();
}
function startTest() {
// Create an instance of ResourceStatsManager for power stats.
powerStatsMgr = new ResourceStatsManager("power");
ok(powerStatsMgr, "Create powerStatsMgr.");
// Test WebIDL attributes.
testAttributes();
// Test WebIDL methods related to stats operation.
testMethods();
}
SimpleTest.waitForExplicitFinish();
// Enable permission and preference.
SpecialPowers.addPermission("resourcestats-manage", true, document);
SpecialPowers.pushPrefEnv({ 'set': [
["dom.resource_stats.enabled", true],
["dom.ignore_webidl_scope_checks", true]
]}, startTest);
</script>
</pre>
</body>
</html>

View File

@ -1,985 +0,0 @@
/* Any: copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
Cu.import("resource://gre/modules/ResourceStatsDB.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
const db = new ResourceStatsDB();
// Components.
const wifiComponent = "wifi:0";
const mobileComponent = "mobile:1";
const cpuComponent = "cpu:0";
const gpsComponent = "gps:0";
// List of available components.
const networkComponents = [wifiComponent, mobileComponent];
const powerComponents = [cpuComponent, gpsComponent];
const offset = (new Date()).getTimezoneOffset() * 60 * 1000;
// Clear store.
function clearStore(store, callback) {
db._dbNewTxn(store, "readwrite", function(aTxn, aStore) {
aStore.openCursor().onsuccess = function (event) {
let cursor = event.target.result;
if (cursor){
cursor.delete();
cursor.continue();
}
};
}, callback);
}
// Clear all stores to avoid starting tests with unknown state.
add_test(function prepareDatabase() {
clearStore('power_stats_store', function() {
clearStore('network_stats_store', function() {
clearStore('alarm_store', function() {
run_next_test();
});
});
});
});
// Dump data saved in a store.
function dumpStore(store, callback) {
db._dbNewTxn(store, "readonly", function(aTxn, aStore) {
aStore.mozGetAll().onsuccess = function onsuccess(event) {
aTxn.result = event.target.result;
};
}, callback);
}
// Check sampleRate is unchangeable.
add_test(function test_sampleRate() {
var sampleRate = db.sampleRate;
do_check_true(sampleRate > 0);
db.sampleRate = 0;
sampleRate = db.sampleRate;
do_check_true(sampleRate > 0);
run_next_test();
});
// Test maxStorageAge is unchangeable.
add_test(function test_maxStorageAge() {
var maxStorageAge = db.maxStorageAge;
do_check_true(maxStorageAge > 0);
db.maxStorageAge = 0;
maxStorageAge = db.maxStorageAge;
do_check_true(maxStorageAge > 0);
run_next_test();
});
// Normalize timestamp to sampleRate precision.
function normalizeTime(aTimeStamp) {
var sampleRate = db.sampleRate;
return Math.floor((aTimeStamp - offset) / sampleRate) * sampleRate;
}
// Generte record as input for saveNetworkStats() as well as the expected
// result when calling getStats().
function generateNetworkRecord(aAppId, aServiceType, aComponents) {
var result = [];
var componentStats = {};
var receivedBytes;
var sentBytes;
var totalReceivedBytes = 0;
var totalSentBytes = 0;
aComponents.forEach(function(comp) {
// Step 1: generate random value for receivedBytes and sentBytes.
receivedBytes = Math.floor(Math.random() * 1000);
sentBytes = Math.floor(Math.random() * 1000);
totalReceivedBytes += receivedBytes;
totalSentBytes += sentBytes;
// Step 2: add stats to record.componentStats.
componentStats[comp] = {
receivedBytes: receivedBytes,
sentBytes: sentBytes
};
// Step 3: generate expected results.
result.push({
appId: aAppId,
serviceType: aServiceType,
component: comp,
receivedBytes: receivedBytes,
sentBytes: sentBytes
});
});
// Step 4: generate expected total stats.
result.push({
appId: aAppId,
serviceType: aServiceType,
component: "",
receivedBytes: totalReceivedBytes,
sentBytes: totalSentBytes
});
// Step 5: get record.
var record = { appId: aAppId,
serviceType: aServiceType,
componentStats: componentStats };
return { record: record, result: result };
}
// Generte record as input for savePowerStats() as well as the expected
// result when calling getStats().
function generatePowerRecord(aAppId, aServiceType, aComponents) {
var result = [];
var componentStats = {};
var consumedPower;
var totalConsumedPower = 0;
aComponents.forEach(function(comp) {
// Step 1: generate random value for consumedPower.
consumedPower = Math.floor(Math.random() * 1000);
totalConsumedPower += consumedPower;
// Step 2: add stats to record.componentStats.
componentStats[comp] = consumedPower;
// Step 3: generate expected results.
result.push({
appId: aAppId,
serviceType: aServiceType,
component: comp,
consumedPower: consumedPower
});
});
// Step 4: generate expected total stats.
result.push({
appId: aAppId,
serviceType: aServiceType,
component: "",
consumedPower: totalConsumedPower
});
// Step 5: get record.
var record = { appId: aAppId,
serviceType: aServiceType,
componentStats: componentStats };
return { record: record, result: result };
}
// Compare stats saved in network store with expected results.
function checkNetworkStatsStore(aExpectedResult, aDumpResult, aTimestamp) {
// Step 1: a quick check for the length of arrays first.
do_check_eq(aExpectedResult.length, aDumpResult.length);
// Step 2: create a map array for search by receivedBytes.
var mapArray = aExpectedResult.map(function(e) {return e.receivedBytes;});
// Step 3: compare each element to make sure both array are equal.
var index;
var target;
aDumpResult.forEach(function(stats) {
index = 0;
// Find the first equal receivedBytes since index.
while ((index = mapArray.indexOf(stats.receivedBytes, index)) > -1) {
// Compare all attributes.
target = aExpectedResult[index];
if (target.appId != stats.appId ||
target.serviceType != stats.serviceType ||
target.component != stats.component ||
target.sentBytes != stats.sentBytes ||
aTimestamp != stats.timestamp) {
index += 1;
continue;
} else {
// If found, remove that element from aExpectedResult and mapArray.
aExpectedResult.splice(index, 1);
mapArray.splice(index, 1);
break;
}
}
do_check_neq(index, -1);
});
run_next_test();
}
// Compare stats saved in power store with expected results.
function checkPowerStatsStore(aExpectedResult, aDumpResult, aTimestamp) {
// Step 1: a quick check for the length of arrays first.
do_check_eq(aExpectedResult.length, aDumpResult.length);
// Step 2: create a map array for search by consumedPower.
var mapArray = aExpectedResult.map(function(e) {return e.consumedPower;});
// Step 3: compare each element to make sure both array are equal.
var index;
var target;
aDumpResult.forEach(function(stats) {
index = 0;
// Find the first equal consumedPower since index.
while ((index = mapArray.indexOf(stats.consumedPower, index)) > -1) {
// Compare all attributes.
target = aExpectedResult[index];
if (target.appId != stats.appId ||
target.serviceType != stats.serviceType ||
target.component != stats.component ||
aTimestamp != stats.timestamp) {
index += 1;
continue;
} else {
// If found, remove that element from aExpectedResult and mapArray.
aExpectedResult.splice(index, 1);
mapArray.splice(index, 1);
break;
}
}
do_check_neq(index, -1);
});
run_next_test();
}
// Prepare network store for testing.
function prepareNetworkStatsStore(recordArray, timestamp, callback) {
// Step 1: clear store.
clearStore("network_stats_store", function() {
// Step 2: save record to store.
db.saveNetworkStats(recordArray, timestamp, callback);
});
}
// Prepare power store for testing.
function preparePowerStatsStore(recordArray, timestamp, callback) {
// Step 1: clear store.
clearStore("power_stats_store", function() {
// Step 2: save record to store.
db.savePowerStats(recordArray, timestamp, callback);
});
}
// Test saveNetworkStats.
add_test(function test_saveNetworkStats() {
var appId = 1;
var serviceType = "";
// Step 1: generate data saved to store.
var { record: record, result: expectedResult } =
generateNetworkRecord(appId, serviceType, networkComponents);
var recordArray = [record];
var timestamp = Date.now();
// Step 2: save recordArray to network store.
prepareNetworkStatsStore(recordArray, timestamp, function(error, callback) {
// Step 3: check if the function call succeed.
do_check_eq(error, null);
// Step 4: dump store for comparison.
dumpStore("network_stats_store", function(error, result) {
do_check_eq(error, null);
checkNetworkStatsStore(expectedResult, result, normalizeTime(timestamp));
});
});
});
// Test savePowerStats.
add_test(function test_savePowerStats() {
var appId = 1;
var serviceType = "";
// Step 1: generate data saved to store.
var { record: record, result: expectedResult } =
generatePowerRecord(appId, serviceType, powerComponents);
var recordArray = [record];
var timestamp = Date.now();
// Step 2: save recordArray to power store.
preparePowerStatsStore(recordArray, timestamp, function(error, callback) {
// Step 3: check if the function call succeed.
do_check_eq(error, null);
// Step 4: dump store for comparison.
dumpStore("power_stats_store", function(error, result) {
do_check_eq(error, null);
checkPowerStatsStore(expectedResult, result, normalizeTime(timestamp));
});
});
});
// Test getting network stats via getStats.
add_test(function test_getNetworkStats() {
var appId = 0;
var manifestURL = "";
var serviceType = "";
var component = "";
// Step 1: generate data saved to store.
var { record: record, result: result } =
generateNetworkRecord(appId, serviceType, networkComponents);
var recordArray = [record];
var expectedStats = result[result.length - 1]; // Check total stats only.
var timestamp = Date.now();
var end = normalizeTime(timestamp) + offset;
var start = end;
// Step 2: save record and prepare network store.
prepareNetworkStatsStore(recordArray, timestamp, function(error, callback) {
// Step 3: get network stats.
db.getStats("network", manifestURL, serviceType, component, start, end,
function(error, result) {
do_check_eq(error, null);
// Step 4: verify result.
do_check_eq(result.type, "network");
do_check_eq(result.manifestURL, manifestURL);
do_check_eq(result.serviceType, serviceType);
do_check_eq(result.component, component);
do_check_eq(result.start, start);
do_check_eq(result.end, end);
do_check_eq(result.sampleRate, db.sampleRate);
do_check_true(Array.isArray(result.statsData));
do_check_eq(result.statsData.length, 1);
var stats = result.statsData[0];
do_check_eq(stats.receivedBytes, expectedStats.receivedBytes);
do_check_eq(stats.sentBytes, expectedStats.sentBytes);
run_next_test(); // If success, run next test.
});
});
});
// Test getting power stats via getStats.
add_test(function test_getPowerStats() {
var appId = 0;
var manifestURL = "";
var serviceType = "";
var component = "";
// Step 1: generate data saved to store.
var { record: record, result: result } =
generatePowerRecord(appId, serviceType, powerComponents);
var recordArray = [record];
var expectedStats = result[result.length - 1]; // Check total stats only.
var timestamp = Date.now();
var end = normalizeTime(timestamp) + offset;
var start = end;
// Step 2: save record and prepare power store.
preparePowerStatsStore(recordArray, timestamp, function(error, callback) {
// Step 3: get power stats.
db.getStats("power", manifestURL, serviceType, component, start, end,
function(error, result) {
do_check_eq(error, null);
// Step 4: verify result
do_check_eq(result.type, "power");
do_check_eq(result.manifestURL, manifestURL);
do_check_eq(result.serviceType, serviceType);
do_check_eq(result.component, component);
do_check_eq(result.start, start);
do_check_eq(result.end, end);
do_check_eq(result.sampleRate, db.sampleRate);
do_check_true(Array.isArray(result.statsData));
do_check_eq(result.statsData.length, 1);
var stats = result.statsData[0];
do_check_eq(stats.consumedPower, expectedStats.consumedPower);
run_next_test(); // If success, run next test.
});
});
});
// Test deleting network stats via clearStats.
add_test(function test_clearNetworkStats() {
var appId = 0;
var manifestURL = "";
var serviceType = "";
var component = "";
// Step 1: genrate data saved to network store.
var { record: record, result: result } =
generateNetworkRecord(appId, serviceType, networkComponents);
var recordArray = [record];
var timestamp = Date.now();
var end = normalizeTime(timestamp) + offset;
var start = end;
// Step 2: save record and prepare network store.
prepareNetworkStatsStore(recordArray, timestamp, function(error, callback) {
// Step 3: clear network stats.
db.clearStats("network", appId, serviceType, component, start, end,
function(error, result) {
do_check_eq(error, null);
// Step 4: check if the stats is deleted.
db.getStats("network", manifestURL, serviceType, component, start, end,
function(error, result) {
do_check_eq(result.statsData.length, 0);
run_next_test();
});
});
});
});
// Test deleting power stats via clearStats.
add_test(function test_clearPowerStats() {
var appId = 0;
var manifestURL = "";
var serviceType = "";
var component = "";
// Step 1: genrate data saved to power store.
var { record: record, result: result } =
generatePowerRecord(appId, serviceType, powerComponents);
var recordArray = [record];
var timestamp = Date.now();
var end = normalizeTime(timestamp) + offset;
var start = end;
// Step 2: save record and prepare power store.
preparePowerStatsStore(recordArray, timestamp, function(error, callback) {
// Step 3: clear power stats.
db.clearStats("power", appId, serviceType, component, start, end,
function(error, result) {
do_check_eq(error, null);
// Step 4: check if the stats is deleted.
db.getStats("power", manifestURL, serviceType, component, start, end,
function(error, result) {
do_check_eq(result.statsData.length, 0);
run_next_test();
});
});
});
});
// Test clearing all network stats.
add_test(function test_clearAllNetworkStats() {
db.clearAllStats("network", function(error, result) {
do_check_eq(error, null);
run_next_test();
});
});
// Test clearing all power stats.
add_test(function test_clearAllPowerStats() {
db.clearAllStats("power", function(error, result) {
do_check_eq(error, null);
run_next_test();
});
});
// Test getting network components.
add_test(function test_getNetworkComponents() {
var appId = 0;
var serviceType = "";
// Step 1: generate data saved to store.
var { record: record, result: expectedResult } =
generateNetworkRecord(appId, serviceType, networkComponents);
var recordArray = [record];
var timestamp = Date.now();
// Step 2: save recordArray to network store.
prepareNetworkStatsStore(recordArray, timestamp, function(error, callback) {
// Step 3: call getComponents.
db.getComponents("network", function(error, result) {
do_check_eq(error, null);
do_check_true(Array.isArray(result));
do_check_eq(result.length, networkComponents.length);
// Check each element in result array is an element of networkComponents.
result.forEach(function(component) {
do_check_true(networkComponents.indexOf(component) > -1);
});
run_next_test(); // If success, run next test.
});
});
});
// Test getting power components.
add_test(function test_getPowerComponents() {
var appId = 0;
var serviceType = "";
// Step 1: generate data saved to store.
var { record: record, result: expectedResult } =
generatePowerRecord(appId, serviceType, powerComponents);
var recordArray = [record];
var timestamp = Date.now();
// Step 2: save recordArray to power store.
preparePowerStatsStore(recordArray, timestamp, function(error, callback) {
// Step 3: call getComponents.
db.getComponents("power", function(error, result) {
do_check_eq(error, null);
do_check_true(Array.isArray(result));
do_check_eq(result.length, powerComponents.length);
// Check each element in result array is an element of powerComponents.
result.forEach(function(component) {
do_check_true(powerComponents.indexOf(component) > -1);
});
run_next_test(); // If success, run next test.
});
});
});
// Generate alarm object for addAlarm().
function generateAlarmObject(aType, aManifestURL, aServiceType, aComponent) {
let alarm = {
type: aType,
component: aComponent,
serviceType: aServiceType,
manifestURL: aManifestURL,
threshold: Math.floor(Math.random() * 1000),
startTime: Math.floor(Math.random() * 1000),
data: null
};
return alarm;
}
// Test adding a network alarm.
add_test(function test_addNetowrkAlarm() {
var manifestURL = "";
var serviceType = "";
// Step 1: generate a network alarm.
var alarm =
generateAlarmObject("network", manifestURL, serviceType, wifiComponent);
// Step 2: clear store.
clearStore("alarm_store", function() {
// Step 3: save the alarm to store.
db.addAlarm(alarm, function(error, result) {
// Step 4: check if the function call succeed.
do_check_eq(error, null);
do_check_true(result > -1);
let alarmId = result;
// Step 5: dump store for comparison.
dumpStore("alarm_store", function(error, result) {
do_check_eq(error, null);
do_check_true(Array.isArray(result));
do_check_true(result.length == 1);
do_check_eq(result[0].type, alarm.type);
do_check_eq(result[0].manifestURL, alarm.manifestURL);
do_check_eq(result[0].serviceType, alarm.serviceType);
do_check_eq(result[0].component, alarm.component);
do_check_eq(result[0].threshold, alarm.threshold);
do_check_eq(result[0].startTime, alarm.startTime);
do_check_eq(result[0].data, alarm.data);
do_check_eq(result[0].alarmId, alarmId);
run_next_test(); // If success, run next test.
});
});
});
});
// Test adding a power alarm.
add_test(function test_addPowerAlarm() {
var manifestURL = "";
var serviceType = "";
// Step 1: generate a power alarm.
var alarm =
generateAlarmObject("power", manifestURL, serviceType, cpuComponent);
// Step 2: clear store.
clearStore("alarm_store", function() {
// Step 3: save the alarm to store.
db.addAlarm(alarm, function(error, result) {
// Step 4: check if the function call succeed.
do_check_eq(error, null);
do_check_true(result > -1);
let alarmId = result;
// Step 5: dump store for comparison.
dumpStore("alarm_store", function(error, result) {
do_check_eq(error, null);
do_check_true(Array.isArray(result));
do_check_true(result.length == 1);
do_check_eq(result[0].type, alarm.type);
do_check_eq(result[0].manifestURL, alarm.manifestURL);
do_check_eq(result[0].serviceType, alarm.serviceType);
do_check_eq(result[0].component, alarm.component);
do_check_eq(result[0].threshold, alarm.threshold);
do_check_eq(result[0].startTime, alarm.startTime);
do_check_eq(result[0].data, alarm.data);
do_check_eq(result[0].alarmId, alarmId);
run_next_test(); // If success, run next test.
});
});
});
});
// Add multiple alarms to store and record the obtained alarmId in each
// alarm object.
function addAlarmsToStore(alarms, index, callback) {
var alarm = alarms[index++];
if (index < alarms.length) {
db.addAlarm(alarm, function(error, result) {
alarm.alarmId = result;
addAlarmsToStore(alarms, index, callback);
});
} else {
db.addAlarm(alarm, function(error, result) {
alarm.alarmId = result;
callback(error, result);
});
}
}
// Prepare alarm store for testging.
function prepareAlarmStore(alarms, callback) {
// Step 1: clear srore.
clearStore("alarm_store", function() {
// Step 2: save alarms to store one by one.
addAlarmsToStore(alarms, 0, callback);
});
}
// Compare alrams returned by getAlarms().
function compareAlarms(aExpectedResult, aResult) {
// Step 1: a quick check for the length of arrays first.
do_check_eq(aExpectedResult.length, aResult.length);
// Step 2: create a map array for search by threshold.
var mapArray = aExpectedResult.map(function(e) {return e.threshold;});
// Step 3: compare each element to make sure both array are equal.
var index;
var target;
aResult.forEach(function(alarm) {
index = 0;
// Find the first equal receivedBytes since index.
while ((index = mapArray.indexOf(alarm.threshold, index)) > -1) {
// Compare all attributes.
target = aExpectedResult[index];
if (target.alarmId != alarm.alarmId ||
target.type != alarm.type ||
target.manifestURL != alarm.manifestURL ||
target.serviceType != alarm.serviceType ||
target.component != alarm.component ||
target.data != alarm.data) {
index += 1;
continue;
} else {
// If found, remove that element from aExpectedResult and mapArray.
aExpectedResult.splice(index, 1);
mapArray.splice(index, 1);
break;
}
}
do_check_neq(index, -1);
});
run_next_test();
}
// Test getting designate network alarms from store.
add_test(function test_getNetworkAlarms() {
var manifestURL = "";
var serviceType = "";
var alarms = [];
// Step 1: generate two network alarms using same parameters.
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
wifiComponent));
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
wifiComponent));
// Step 2: generate another network alarm using different parameters.
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
mobileComponent));
// Step 3: clear alarm store and save new alarms to store.
prepareAlarmStore(alarms, function(error, result) {
// Step 4: call getAlarms.
let options = {
manifestURL: manifestURL,
serviceType: serviceType,
component: wifiComponent
};
db.getAlarms("network", options, function(error, result) {
// Step 5: check if the function call succeed.
do_check_eq(error, null);
// Step 6: check results.
// The last element in alarms array is not our expected result,
// so pop that out first.
alarms.pop();
compareAlarms(alarms, result);
});
});
});
// Test getting designate power alarms from store.
add_test(function test_getPowerAlarms() {
var manifestURL = "";
var serviceType = "";
var alarms = [];
// Step 1: generate two power alarms using same parameters.
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
cpuComponent));
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
cpuComponent));
// Step 2: generate another power alarm using different parameters.
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
gpsComponent));
// Step 3: clear alarm store and save new alarms to store.
prepareAlarmStore(alarms, function(error, result) {
// Step 4: call getAlarms.
let options = {
manifestURL: manifestURL,
serviceType: serviceType,
component: cpuComponent
};
db.getAlarms("power", options, function(error, result) {
// Step 5: check if the function call succeed.
do_check_eq(error, null);
// Step 6: check results.
// The last element in alarms array is not our expected result,
// so pop that out first.
alarms.pop();
compareAlarms(alarms, result);
});
});
});
// Test getting all network alarms from store.
add_test(function test_getAllNetworkAlarms() {
var manifestURL = "";
var serviceType = "";
var alarms = [];
// Step 1: generate two network alarms.
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
wifiComponent));
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
mobileComponent));
// Step 2: generate another power alarm.
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
cpuComponent));
// Step 3: clear alarm store and save new alarms to store.
prepareAlarmStore(alarms, function(error, result) {
// Step 4: call getAlarms.
let options = null;
db.getAlarms("network", options, function(error, result) {
// Step 5: check if the function call succeed.
do_check_eq(error, null);
// Step 6: check results.
// The last element in alarms array is not our expected result,
// so pop that out first.
alarms.pop();
compareAlarms(alarms, result);
});
});
});
// Test getting all power alarms from store.
add_test(function test_getAllPowerAlarms() {
var manifestURL = "";
var serviceType = "";
var alarms = [];
// Step 1: generate two power alarms.
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
cpuComponent));
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
gpsComponent));
// Step 2: generate another network alarm.
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
wifiComponent));
// Step 3: clear alarm store and save new alarms to store.
prepareAlarmStore(alarms, function(error, result) {
// Step 4: call getAlarms.
let options = null;
db.getAlarms("power", options, function(error, result) {
// Step 5: check if the function call succeed.
do_check_eq(error, null);
// Step 6: check results.
// The last element in alarms array is not our expected result,
// so pop that out first.
alarms.pop();
compareAlarms(alarms, result);
});
});
});
// Test removing designate network alarm from store.
add_test(function test_removeNetworkAlarm() {
var manifestURL = "";
var serviceType = "";
var alarms = [];
// Step 1: generate one network alarm.
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
wifiComponent));
// Step 2: clear alarm store and save new alarms to store.
prepareAlarmStore(alarms, function(error, result) {
var alarmId = result;
// Step 3: remove the alarm.
db.removeAlarm("network", alarmId, function(error, result) {
// Step 4: check if the function call succeed.
do_check_eq(result, true);
// Step 5: dump store to check if the alarm is removed.
dumpStore("alarm_store", function(error, result) {
do_check_eq(error, null);
do_check_true(Array.isArray(result));
do_check_true(result.length === 0);
run_next_test(); // If success, run next test.
});
});
});
});
// Test removing designate power alarm from store.
add_test(function test_removePowerAlarm() {
var manifestURL = "";
var serviceType = "";
var alarms = [];
// Step 1: generate one power alarm.
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
cpuComponent));
// Step 2: clear alarm store and save new alarms to store.
prepareAlarmStore(alarms, function(error, result) {
var alarmId = result;
// Step 3: remove the alarm.
db.removeAlarm("power", alarmId, function(error, result) {
// Step 4: check if the function call succeed.
do_check_eq(result, true);
// Step 5: dump store to check if the alarm is removed.
dumpStore("alarm_store", function(error, result) {
do_check_eq(error, null);
do_check_true(Array.isArray(result));
do_check_true(result.length === 0);
run_next_test(); // If success, run next test.
});
});
});
});
// Test removing designate network alarm from store.
add_test(function test_removeAllNetworkAlarms() {
var manifestURL = "";
var serviceType = "";
var alarms = [];
// Step 1: generate two network alarms.
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
wifiComponent));
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
mobileComponent));
// Step 2: generate another power alarm.
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
cpuComponent));
// Step 3: clear alarm store and save new alarms to store.
prepareAlarmStore(alarms, function(error, result) {
// Step 4: remove all network alarms.
db.removeAllAlarms("network", function(error, result) {
// Step 5: check if the function call succeed.
do_check_eq(error, null);
// Step 6: dump store for comparison.
// Because the power alarm should not be removed, so it would be the
// only result returned by dumpStore.
var alarm = alarms.pop(); // The expected result.
dumpStore("alarm_store", function(error, result) {
do_check_eq(error, null);
do_check_true(Array.isArray(result));
do_check_true(result.length == 1);
do_check_eq(result[0].type, alarm.type);
do_check_eq(result[0].manifestURL, alarm.manifestURL);
do_check_eq(result[0].serviceType, alarm.serviceType);
do_check_eq(result[0].component, alarm.component);
do_check_eq(result[0].threshold, alarm.threshold);
do_check_eq(result[0].startTime, alarm.startTime);
do_check_eq(result[0].data, alarm.data);
do_check_eq(result[0].alarmId, alarm.alarmId);
run_next_test(); // If success, run next test.
});
});
});
});
// Test removing designate power alarm from store.
add_test(function test_removeAllPowerAlarms() {
var manifestURL = "";
var serviceType = "";
var alarms = [];
// Step 1: generate two power alarms.
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
cpuComponent));
alarms.push(generateAlarmObject("power", manifestURL, serviceType,
gpsComponent));
// Step 2: generate another network alarm.
alarms.push(generateAlarmObject("network", manifestURL, serviceType,
wifiComponent));
// Step 3: clear alarm store and save new alarms to store.
prepareAlarmStore(alarms, function(error, result) {
// Step 4: remove all power alarms.
db.removeAllAlarms("power", function(error, result) {
// Step 5: check if the function call succeed.
do_check_eq(error, null);
// Step 6: dump store for comparison.
// Because the network alarm should not be removed, so it would be the
// only result returned by dumpStore.
var alarm = alarms.pop(); // The expected result.
dumpStore("alarm_store", function(error, result) {
do_check_eq(error, null);
do_check_true(Array.isArray(result));
do_check_true(result.length == 1);
do_check_eq(result[0].type, alarm.type);
do_check_eq(result[0].manifestURL, alarm.manifestURL);
do_check_eq(result[0].serviceType, alarm.serviceType);
do_check_eq(result[0].component, alarm.component);
do_check_eq(result[0].threshold, alarm.threshold);
do_check_eq(result[0].startTime, alarm.startTime);
do_check_eq(result[0].data, alarm.data);
do_check_eq(result[0].alarmId, alarm.alarmId);
run_next_test(); // If success, run next test.
});
});
});
});
function run_test() {
do_get_profile();
run_next_test();
}

View File

@ -1,5 +0,0 @@
[DEFAULT]
head =
tail =
[test_resourcestats_db.js]

View File

@ -1,65 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
[ChromeOnly,
Pref="dom.resource_stats.enabled",
JSImplementation="@mozilla.org/networkStatsData;1"]
interface NetworkStatsData
{
readonly attribute unsigned long long receivedBytes;
readonly attribute unsigned long long sentBytes;
readonly attribute DOMTimeStamp timestamp; // timestamp of the record
};
[ChromeOnly,
Pref="dom.resource_stats.enabled",
JSImplementation="@mozilla.org/powerStatsData;1"]
interface PowerStatsData
{
readonly attribute unsigned long long consumedPower; // unit: mW
readonly attribute DOMTimeStamp timestamp; // timestamp of the record
};
[ChromeOnly,
Pref="dom.resource_stats.enabled",
JSImplementation="@mozilla.org/resourceStats;1"]
interface ResourceStats
{
/**
* Type of statistics/
*/
readonly attribute ResourceType type;
/**
* The |component| specifies statistics belongs to. This will be null if
* the ResourceStatsOptions.component argument passed to getStats() is null.
*/
readonly attribute DOMString? component;
/**
* |serviceType| specifies the system service. This will be null if the
* ResourceStatsOptions.serviceType argument passed to getStats() is null.
*/
readonly attribute SystemService? serviceType;
/**
* |manifestURL| specifies the manifestURL of an application. This will be
* null if the ResourceStatsOptions.manifestURL argument passed to getStats()
* is null.
*/
readonly attribute DOMString? manifestURL;
/**
* Statistics, one element per day
*/
sequence<(NetworkStatsData or PowerStatsData)> getData();
/**
* Date range
*/
readonly attribute DOMTimeStamp start; // start timestamp
readonly attribute DOMTimeStamp end; // end timestamp
};

View File

@ -1,226 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*/
/**
* Supported resource statistics
*/
enum ResourceType {
"network",
"power"
};
/**
* List of system services supporting resource statistics
*/
enum SystemService {
"ota",
"tethering"
};
dictionary ResourceStatsOptions
{
/**
* |component| specifies which component's resource usage will be returned.
* If null or undefined, sum of all components' usage is returned.
*
* |component| is expressed in "<component>:<id>", where <component> is the
* name of the component and <id> is used to identify different entities.
*
* The <id> field is mainly used in specifying the identity of different SIMs
* when quering mobile network usage, e.g. "mobile:<iccid>".
*
* Quering statistics of other components should specify the |component| to
* "<component>:0", such as "cpu:0" or "wifi:0".
*/
DOMString? component = null;
/**
* |manifestURL| specifies the manifestURL of an application.
* |systemService| specifies the system service.
*
* If both |systemService| and |manifestURL| are null or undefined, then a
* system-wide resource statistics is returned.
*
* If |manifestURL| is specified, then the resource statistics of the
* specified application is returned.
*
* If |systemService| is specified, then the resource statistics of the
* specified system service is returned.
*
* If |systemService| and |manifestURL| are both specified, then the return
* statistics indicates the resources that the system service consumed for
* the application.
*/
SystemService? serviceType = null;
DOMString? manifestURL = null;
};
dictionary ResourceStatsAlarmOptions
{
/**
* |startTime| indicates the start time of counting the resource usage.
*
* |data| is used to reflect in the alarm object when the alarm is triggered.
* |data| should be copied using the structured clone algorithm.
*/
[EnforceRange] DOMTimeStamp startTime; // time in milliseconds since Epoch
any data;
};
[ChromeOnly,
Pref="dom.resource_stats.enabled",
JSImplementation="@mozilla.org/resourceStatsAlarm;1"]
interface ResourceStatsAlarm
{
/**
* ID of the alarm
*/
readonly attribute unsigned long alarmId;
/**
* Type of resource this alarm monitor
*/
readonly attribute ResourceType type;
/**
* The target component this alarm monitor.
*/
readonly attribute DOMString? component;
/**
* |manifestURL| specifies the manifestURL of an application.
* |systemService| specifies the system service.
*
* Both attributes are null means that this alarm monitors a system-wide
* resource usage.
*/
readonly attribute SystemService? serviceType;
readonly attribute DOMString? manifestURL;
/**
* |threshold| specifies the limit of resource usage.
*/
readonly attribute unsigned long long threshold;
/**
* |data| is used to reflect in the alarm object when the alarm is triggered.
*/
readonly attribute any data;
};
[ChromeOnly,
Pref="dom.resource_stats.enabled",
Constructor(ResourceType type),
JSImplementation="@mozilla.org/resourceStatsManager;1"]
interface ResourceStatsManager
{
/**
* Query resource statistics.
*
* |statsOptions| specifies the detail of statistics of interest.
*
* |start| and |end| specifies the time range of interest, both included.
* If |start| is null or undefined, retrieve the stats since measurements.
* If |end| is null or undefined. retrieve the stats until the current time.
*
* If success, the fulfillment value is a ResourceStats object.
*/
Promise<ResourceStats> getStats(optional ResourceStatsOptions statsOptions,
[EnforceRange] optional DOMTimeStamp? start = null,
[EnforceRange] optional DOMTimeStamp? end = null);
/**
* Clear resource statistics stored in database.
*
* |statsOptions| specifies the detail of statistics to delete.
*
* |start| and |end| specifies the time range of interest, both included.
* If |start| is null or undefined, delete the stats since measurements.
* If |end| is null or undefined. delete the stats until the current time.
*/
// XXXbz What is this promise resolved with?
Promise<any> clearStats(optional ResourceStatsOptions statsOptions,
[EnforceRange] optional DOMTimeStamp? start = null,
[EnforceRange] optional DOMTimeStamp? end = null);
/**
* Clear all resource statistics stored in database.
*/
// XXXbz What is this promise resolved with?
Promise<any> clearAllStats();
/**
* Install an alarm to monitor resource usage.
*
* The |threshold| specifies the limit of resource usage. When resource
* usage reaches the threshold, a "resourceStats-alarm" system message
* is sent to the application.
*
* |statsOptions| specifies the detail of statistics of interest.
*
* |alarmOptions| is a ResourceStatsAlarmOptions object.
*
* If success, the fulfillment value is an alarm ID.
*/
Promise<unsigned long> addAlarm([EnforceRange] unsigned long long threshold,
optional ResourceStatsOptions statsOptions,
optional ResourceStatsAlarmOptions alarmOptions);
/**
* Obtain alarms.
*
* If |statsOptions| is provided, then only the alarms monitoring that
* resource are returned. Otherwise, all alarms set for this resource type
* is returned.
*
* If success, the fulfillment value is an array of ResourceStatsAlarm.
*/
Promise<sequence<ResourceStatsAlarm>> getAlarms(optional ResourceStatsOptions statsOptions);
/**
* Remove the specified alarm.
*
* |alarmId| specifies the alarm to be removed.
*/
// XXXbz What is this promise resolved with?
Promise<any> removeAlarm([EnforceRange] unsigned long alarmId);
/**
* Remove all alarms.
*/
// XXXbz What is this promise resolved with?
Promise<any> removeAllAlarms();
/**
* Enumerate components that have stored statistics in database.
*
* If success, the fulfillment value is an array of DOMString.
*/
Promise<sequence<DOMString>> getAvailableComponents();
/**
* Return supporting resource statistics, i.e. ["Network", "Power"]
*
* This should be specified as static attribute after Bug 863952 is resolved.
*/
[Cached, Pure]
readonly attribute sequence<DOMString> resourceTypes;
/**
* Time in milliseconds between statistics stored in database.
*
* This should be specified as static attribute after Bug 863952 is resolved.
*/
readonly attribute unsigned long sampleRate;
/**
* Time in milliseconds recorded by the API until present time. All
* statistics older than maxStorageAge from now are deleted.
*
* This should be specified as static attribute after Bug 863952 is resolved.
*/
readonly attribute unsigned long long maxStorageAge;
};

View File

@ -401,8 +401,6 @@ WEBIDL_FILES = [
'Range.webidl',
'Rect.webidl',
'Request.webidl',
'ResourceStats.webidl',
'ResourceStatsManager.webidl',
'Response.webidl',
'RGBColor.webidl',
'RTCStatsReport.webidl',