Bug 1263799 - Support IPC for TV service between B2G and content processes. Part 3 - Enhance TV mochitests. r=schien
MozReview-Commit-ID: IsCVCxtSzEn
--- a/dom/tv/TVSimulatorService.js
+++ b/dom/tv/TVSimulatorService.js
@@ -39,55 +39,48 @@ function TVSimulatorService() {
// "sourceType1": [ /* source listeners */ ],
// "sourceType2": [ /* source listeners */ ],
// ...
// },
// ...
// }
this._sourceListeners = {};
this._internalTuners = null;
- this._scanCompleteTimer = null;
- this._scanningWrapTunerData = null;
- this._init();
+ try {
+ this.initData();
+ } catch (e) {
+ debug("Error: " + e + ", Cannot init the data.");
+ }
}
TVSimulatorService.prototype = {
classID: Components.ID("{94b065ad-d45a-436a-b394-6dabc3cf110f}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsITVSimulatorService,
- Ci.nsITVService,
- Ci.nsITimerCallback]),
-
- _init: function TVSimInit() {
- if (this._internalTuners) {
- return;
- }
+ Ci.nsITVService]),
- // I try to load the testing mock data if related preference are already set.
- // Otherwise, use to the simulation data from prefences.
- // See /dom/tv/test/mochitest/head.js for more details.
- let settingStr = "";
- try {
- settingStr = Services.prefs.getCharPref("dom.testing.tv_mock_data");
- } catch(e) {
+ initData: function(aMockedData) {
+ // Use the passed-in mocked data. If it doesn't exist, then try to load the
+ // simulation data.
+ let settingStr = aMockedData;
+ if (!settingStr) {
try {
settingStr = this._getDummyData();
} catch(e) {
debug("TV Simulator service failed to load simulation data: " + e);
- return;
+ throw Cr.NS_ERROR_FAILURE;
}
}
let settingsObj;
try {
/*
*
* Setting JSON file format:
*
- * Note: This setting JSON is not allow empty array.
- * If set the empty array, _init() will fail.
+ * Note: Empty arrays are not allowed in the format.
* e.g.
* - "tuners": []
* - "channels":[]
* Format:
* {
* "tuners": [{
* "id": "The ID of the tuner",
* "supportedType": ["The array of source type to be used."],
@@ -116,23 +109,23 @@ TVSimulatorService.prototype = {
* },]
* },]
* },]
* }
*/
settingsObj = JSON.parse(settingStr);
} catch(e) {
debug("File load error: " + e);
- return;
+ throw Cr.NS_ERROR_FAILURE;
}
// validation
if (!this._validateSettings(settingsObj)) {
debug("Failed to validate settings.");
- return;
+ throw Cr.NS_ERROR_INVALID_ARG;
}
// Key is as follow
// {'tunerId':tunerId, 'sourceType':sourceType}
this._internalTuners = new Map();
// TVTunerData
for (let tunerData of settingsObj.tuners) {
@@ -294,80 +287,32 @@ TVSimulatorService.prototype = {
},
startScanningChannels: function(aTunerId, aSourceType, aCallback) {
if (!aCallback) {
debug("aCallback is null\n");
throw Cr.NS_ERROR_INVALID_ARG;
}
- if (this._scanningWrapTunerData) {
- aCallback.notifyError(Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
- return;
- }
-
let wrapTunerData = this._getWrapTunerData(aTunerId, aSourceType);
if (!wrapTunerData || !wrapTunerData.channels) {
aCallback.notifyError(Ci.nsITVServiceCallback.TV_ERROR_FAILURE);
return;
}
- this._scanningWrapTunerData = wrapTunerData;
-
aCallback.notifySuccess(null);
-
- for (let [key, wrapChannelData] of wrapTunerData.channels) {
- for (let listener of this._getSourceListeners(aTunerId, aSourceType)) {
- listener.notifyChannelScanned(aTunerId, aSourceType, wrapChannelData.channel);
- }
- }
-
- this._scanCompleteTimer = Cc["@mozilla.org/timer;1"]
- .createInstance(Ci.nsITimer);
- this._scanCompleteTimer.initWithCallback(this, 10,
- Ci.nsITimer.TYPE_ONE_SHOT);
- },
-
- notify: function(aTimer) {
- if (!this._scanningWrapTunerData) {
- return;
- }
-
- this._scanCompleteTimer = null;
-
- let tunerId = this._scanningWrapTunerData.tuner.id;
- let sourceType = this._scanningWrapTunerData.sourceType;
- let notifyResult = Cr.NS_OK;
- for (let listener of this._getSourceListeners(tunerId, sourceType)) {
- notifyResult = listener.notifyChannelScanComplete(tunerId, sourceType);
- }
- this._scanningWrapTunerData = null;
- return notifyResult;
},
stopScanningChannels: function(aTunerId, aSourceType, aCallback) {
+
if (!aCallback) {
debug("aCallback is null\n");
throw Cr.NS_ERROR_INVALID_ARG;
}
- if (!this._scanningWrapTunerData ||
- aTunerId != this._scanningWrapTunerData.tuner.id ||
- aSourceType != this._scanningWrapTunerData.sourceType) {
- aCallback.notifyError(Cr.NS_ERROR_DOM_INVALID_STATE_ERR);
- return;
- }
-
- this._scanningWrapTunerData = null;
-
- if (this._scanCompleteTimer) {
- this._scanCompleteTimer.cancel();
- this._scanCompleteTimer = null;
- }
-
for (let listener of this._getSourceListeners(aTunerId, aSourceType)) {
listener.notifyChannelScanStopped(aTunerId, aSourceType);
}
aCallback.notifySuccess(null);
},
clearScannedChannelsCache: function(aTunerId, aSourceType, aCallback) {
@@ -459,16 +404,61 @@ TVSimulatorService.prototype = {
}
let videoFile = new File(this._getFilePath(wrapChannelData.videoFilePath));
let videoBlobURL = aWin.URL.createObjectURL(videoFile);
return videoBlobURL;
},
+ simulateChannelScanned: function(aTunerId, aSourceType) {
+ let wrapTunerData = this._getWrapTunerData(aTunerId, aSourceType);
+ if (!wrapTunerData || !wrapTunerData.channels) {
+ throw Cr.NS_ERROR_INVALID_ARG;
+ }
+
+ let listeners = this._getSourceListeners(aTunerId, aSourceType);
+ for (let [key, wrapChannelData] of wrapTunerData.channels) {
+ for (let listener of listeners) {
+ listener.notifyChannelScanned(aTunerId, aSourceType, wrapChannelData.channel);
+ }
+ }
+ },
+
+ simulateChannelScanComplete: function(aTunerId, aSourceType) {
+ for (let listener of this._getSourceListeners(aTunerId, aSourceType)) {
+ listener.notifyChannelScanComplete(aTunerId, aSourceType);
+ }
+ },
+
+ simulateChannelScanError: function(aTunerId, aSourceType) {
+ for (let listener of this._getSourceListeners(aTunerId, aSourceType)) {
+ listener.notifyChannelScanStopped(aTunerId, aSourceType);
+ }
+ },
+
+ simulateEITBroadcasted: function(aTunerId, aSourceType, aChannelNumber) {
+ let wrapTunerData = this._getWrapTunerData(aTunerId, aSourceType);
+ if (!wrapTunerData || !wrapTunerData.channels) {
+ throw Cr.NS_ERROR_INVALID_ARG;
+ }
+
+ let wrapChannelData = wrapTunerData.channels.get(aChannelNumber);
+ if (!wrapChannelData || !wrapChannelData.programs) {
+ throw Cr.NS_ERROR_INVALID_ARG;
+ }
+
+ for (let listener of this._getSourceListeners(aTunerId, aSourceType)) {
+ listener.notifyEITBroadcasted(aTunerId, aSourceType,
+ wrapChannelData.channel,
+ wrapChannelData.programs,
+ wrapChannelData.programs.length);
+ }
+ },
+
_getDummyData : function() {
// Load the setting file from local JSON file.
// Synchrhronous File Reading.
let file = Cc["@mozilla.org/file/local;1"]
.createInstance(Ci.nsILocalFile);
let fstream = Cc["@mozilla.org/network/file-input-stream;1"]
.createInstance(Ci.nsIFileInputStream);
--- a/dom/tv/nsITVSimulatorService.idl
+++ b/dom/tv/nsITVSimulatorService.idl
@@ -11,22 +11,67 @@ interface mozIDOMWindow;
#define TV_SIMULATOR_SERVICE_CONTRACTID\
"@mozilla.org/tv/simulatorservice;1"
%}
[scriptable, uuid(3f670994-5915-415a-b906-7ead54bb3be1)]
interface nsITVSimulatorService : nsITVService
{
/*
+ * Init the simulation data.
+ *
+ * @param mockedData The preloaded mocked data in stringified JSON format.
+ */
+ void initData([optional] in DOMString mockedData);
+
+ /*
* Get the URL of simulated video blob.
*
* @param tunerId The ID of the tuner.
* @param sourceType The source type to be used.
* @param channelNumber The LCN (Logical Channel Number) of the channel.
* @param window The window object of content.
* @return blobUrl The URL of created blob from local video file.
*/
void getSimulatorVideoBlobURL(in DOMString tunerId,
in DOMString sourceType,
in DOMString channelNumber,
in mozIDOMWindow window,
[retval] out DOMString blobUrl);
+
+ /*
+ * Simulate some channels are scanned.
+ *
+ * @param tunerId The ID of the tuner.
+ * @param sourceType The source type to be used.
+ */
+ void simulateChannelScanned(in DOMString tunerId,
+ in DOMString sourceType);
+
+ /*
+ * Simulate channel scanning complete.
+ *
+ * @param tunerId The ID of the tuner.
+ * @param sourceType The source type to be used.
+ */
+ void simulateChannelScanComplete(in DOMString tunerId,
+ in DOMString sourceType);
+
+ /*
+ * Simulate error occurs during channel scanning.
+ *
+ * @param tunerId The ID of the tuner.
+ * @param sourceType The source type to be used.
+ */
+ void simulateChannelScanError(in DOMString tunerId,
+ in DOMString sourceType);
+
+ /*
+ * Simulate EIT broadcasted.
+ *
+ * @param tunerId The ID of the tuner.
+ * @param sourceType The source type to be used.
+ * @param channelNumber The LCN (Logical Channel Number) of the channel.
+ */
+ void simulateEITBroadcasted(in DOMString tunerId,
+ in DOMString sourceType,
+ in DOMString channelNumber);
};
--- a/dom/tv/test/mochitest/head.js
+++ b/dom/tv/test/mochitest/head.js
@@ -1,40 +1,45 @@
"use strict";
-function setupPrefsAndPermissions(callback) {
+function setupPrefsAndPermissions(aCallback) {
setupPrefs(function() {
SpecialPowers.pushPermissions([
{"type":"tv", "allow":1, "context":document}
- ], callback);
+ ], aCallback);
+ });
+}
+
+function setupPrefs(aCallback) {
+ SpecialPowers.pushPrefEnv({"set": [
+ ["dom.tv.enabled", true],
+ ["dom.ignore_webidl_scope_checks", true],
+ ]}, function() {
+ aCallback();
});
}
-function setupPrefs(callback) {
+function removePrefsAndPermissions(aCallback) {
+ SpecialPowers.popPrefEnv(function() {
+ SpecialPowers.popPermissions(aCallback);
+ });
+}
+
+function prepareTest(aCallback) {
+ removePrefsAndPermissions(function() {
+ setupPrefsAndPermissions(function() {
+ initMockedData(aCallback);
+ });
+ });
+}
+
+function initMockedData(aCallback) {
let xhr = new XMLHttpRequest;
- let data;
-
xhr.open("GET", "./mock_data.json", false);
xhr.send(null);
if (xhr.status == 200) {
- data = xhr.responseText;
- }
+ var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('tv_chrome_script.js'));
- SpecialPowers.pushPrefEnv({"set": [
- ["dom.tv.enabled", true],
- ["dom.ignore_webidl_scope_checks", true],
- ["dom.testing.tv_mock_data", data]
- ]}, function() {
- callback();
- });
-}
+ gScript.addMessageListener('init-mocked-data-complete', aCallback);
-function removePrefsAndPermissions(callback) {
- SpecialPowers.popPrefEnv(function() {
- SpecialPowers.popPermissions(callback);
- });
+ gScript.sendAsyncMessage('init-mocked-data', xhr.responseText);
+ }
}
-
-function prepareTest(callback) {
- removePrefsAndPermissions(function() {
- setupPrefsAndPermissions(callback);
- });
-}
--- a/dom/tv/test/mochitest/mochitest.ini
+++ b/dom/tv/test/mochitest/mochitest.ini
@@ -1,20 +1,27 @@
[DEFAULT]
+skip-if = toolkit == "gonk"
support-files =
head.js
mock_data.json
+ tv_chrome_script.js
[test_tv_non_permitted_app.html]
[test_tv_permitted_app.html]
[test_tv_get_tuners.html]
[test_tv_get_sources.html]
[test_tv_get_channels.html]
[test_tv_get_channels_during_scanning.html]
[test_tv_get_programs.html]
[test_tv_get_current_program.html]
[test_tv_set_current_source.html]
[test_tv_set_invalid_current_source.html]
[test_tv_set_current_channel.html]
[test_tv_set_current_channel_during_scanning.html]
[test_tv_set_invalid_current_channel.html]
[test_tv_scan_channels_stopped.html]
+skip-if = e10s || buildapp == 'b2g'
[test_tv_scan_channels_completed.html]
+skip-if = e10s || buildapp == 'b2g'
+[test_tv_scan_channels_error.html]
+skip-if = e10s || buildapp == 'b2g'
+[test_tv_eit_broadcasted.html]
new file mode 100644
--- /dev/null
+++ b/dom/tv/test/mochitest/test_tv_eit_broadcasted.html
@@ -0,0 +1,77 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test TVEITBroadcastedEvent for TV API</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" src="./head.js"></script>
+<script type="application/javascript">
+
+function runTest() {
+ ok('tv' in navigator, "navigator.tv should exist.");
+ var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('tv_chrome_script.js'));
+
+ navigator.tv.getTuners().then(
+ function(aTuners) {
+ ok(aTuners.length > 0, "Got at least 1 tuner.");
+
+ aTuners[0].getSources().then(
+ function(aSources) {
+ ok(aSources.length > 0, "Got at least 1 source.");
+ var source = aSources[0];
+
+ source.oneitbroadcasted = function(aEvent) {
+ info("Received EIT broadcasted event.");
+
+ var programs = aEvent.programs;
+ for (var i = 0; i < programs.length; i++) {
+ ok(programs[i], "Program " + i + " should be set.")
+ }
+
+ gScript.destroy();
+ SimpleTest.finish();
+ };
+
+ source.getChannels().then(
+ function(aChannels) {
+ ok(aChannels.length > 0, "Got at least 1 channel.");
+
+ gScript.sendAsyncMessage('trigger-eit-broadcasted',
+ { tunerId: aTuners[0].id,
+ sourceType: source.type,
+ channelNumber: aChannels[0].number });
+ },
+ function(aError) {
+ ok(false, "Error occurred when getting channels: " + aError);
+ gScript.destroy();
+ SimpleTest.finish();
+ }
+ );
+ },
+ function(aError) {
+ ok(false, "Error occurred when getting sources: " + aError);
+ gScript.destroy();
+ SimpleTest.finish();
+ }
+ );
+ },
+ function(aError) {
+ ok(false, "Error occurred when getting tuners: " + aError);
+ gScript.destroy();
+ SimpleTest.finish();
+ }
+ );
+}
+
+SimpleTest.waitForExplicitFinish();
+prepareTest(runTest);
+
+</script>
+</pre>
+</body>
+</html>
--- a/dom/tv/test/mochitest/test_tv_scan_channels_completed.html
+++ b/dom/tv/test/mochitest/test_tv_scan_channels_completed.html
@@ -11,63 +11,68 @@
<pre id="test">
<script type="application/javascript" src="./head.js"></script>
<script type="application/javascript">
function runTest() {
ok('tv' in navigator, "navigator.tv should exist.");
var isScannedEventFired = false;
-
+ var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('tv_chrome_script.js'));
+
navigator.tv.getTuners().then(
function(aTuners) {
ok(aTuners.length > 0, "Got at least 1 tuner.");
aTuners[0].getSources().then(
function(aSources) {
ok(aSources.length > 0, "Got at least 1 source.");
var source = aSources[0];
- source.oneitbroadcasted = function(aEvent) {
- info("Received EIT broadcasted event.");
-
- var programs = aEvent.programs;
- for (var i = 0; i < programs.length; i++) {
- ok(programs[i], "Program " + i + " should be set.")
- }
- };
-
source.onscanningstatechanged = function(aEvent) {
if (aEvent.state === 'scanned') {
- isScannedEventFired = true;
+ if (!isScannedEventFired) {
+ isScannedEventFired = true;
+ gScript.sendAsyncMessage('trigger-channel-scan-complete',
+ { tunerId: aTuners[0].id,
+ sourceType: source.type });
+ }
info("Received channel scanned event.");
ok(aEvent.channel, "Scanned channel should be set.");
} else if (aEvent.state === 'completed') {
ok(isScannedEventFired, "Received channel scanning completed event after channel scanned event.");
+ gScript.destroy();
SimpleTest.finish();
}
};
// TODO Bug 1088818 - Modify the behavior of channel scanning.
source.startScanning({}).then(
- function() {},
+ function() {
+ gScript.sendAsyncMessage('trigger-channel-scanned',
+ { tunerId: aTuners[0].id,
+ sourceType: source.type });
+ },
function(aError) {
ok(false, "Error occurred when starting scanning: " + aError);
+ gScript.destroy();
SimpleTest.finish();
}
);
},
function(aError) {
ok(false, "Error occurred when getting sources: " + aError);
+ gScript.destroy();
SimpleTest.finish();
}
);
},
function(aError) {
ok(false, "Error occurred when getting tuners: " + aError);
+ gScript.destroy();
SimpleTest.finish();
}
);
}
SimpleTest.expectAssertions(0, 2);
SimpleTest.waitForExplicitFinish();
prepareTest(runTest);
new file mode 100644
--- /dev/null
+++ b/dom/tv/test/mochitest/test_tv_scan_channels_error.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test channel scanning error for TV API</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" src="./head.js"></script>
+<script type="application/javascript">
+
+function runTest() {
+ ok('tv' in navigator, "navigator.tv should exist.");
+
+ var gScript = SpecialPowers.loadChromeScript(SimpleTest.getTestFileURL('tv_chrome_script.js'));
+
+ navigator.tv.getTuners().then(
+ function(aTuners) {
+ ok(aTuners.length > 0, "Got at least 1 tuner.");
+
+ aTuners[0].getSources().then(
+ function(aSources) {
+ ok(aSources.length > 0, "Got at least 1 source.");
+ var source = aSources[0];
+
+ source.onscanningstatechanged = function(aEvent) {
+ if (aEvent.state === 'stopped') {
+ ok(true, "Received channel scanning stopped event.");
+ gScript.destroy();
+ SimpleTest.finish();
+ }
+ };
+
+ // TODO Bug 1088818 - Modify the behavior of channel scanning.
+ source.startScanning().then(
+ function() {
+ gScript.sendAsyncMessage('trigger-channel-scan-error',
+ { tunerId: aTuners[0].id,
+ sourceType: source.type });
+ },
+ function(aError) {
+ ok(false, "Error occurred when starting scanning: " + aError);
+ gScript.destroy();
+ SimpleTest.finish();
+ }
+ );
+ },
+ function(aError) {
+ ok(false, "Error occurred when getting sources: " + aError);
+ gScript.destroy();
+ SimpleTest.finish();
+ }
+ );
+ },
+ function(aError) {
+ ok(false, "Error occurred when getting tuners: " + aError);
+ gScript.destroy();
+ SimpleTest.finish();
+ }
+ );
+}
+
+SimpleTest.waitForExplicitFinish();
+prepareTest(runTest);
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/tv/test/mochitest/tv_chrome_script.js
@@ -0,0 +1,44 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+'use strict';
+
+const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
+
+Cu.import('resource://gre/modules/XPCOMUtils.jsm');
+
+addMessageListener('init-mocked-data', function(aData) {
+ var service = Cc["@mozilla.org/tv/tvservice;1"].getService(Ci.nsITVService);
+ try {
+ service.QueryInterface(Ci.nsITVSimulatorService).initData(aData);
+ sendAsyncMessage('init-mocked-data-complete');
+ } catch (e) {}
+});
+
+addMessageListener('trigger-channel-scanned', function(aData) {
+ var service = Cc["@mozilla.org/tv/tvservice;1"].getService(Ci.nsITVService);
+ try {
+ service.QueryInterface(Ci.nsITVSimulatorService).simulateChannelScanned(aData.tunerId, aData.sourceType);
+ } catch (e) {}
+});
+
+addMessageListener('trigger-channel-scan-complete', function(aData) {
+ var service = Cc["@mozilla.org/tv/tvservice;1"].getService(Ci.nsITVService);
+ try {
+ service.QueryInterface(Ci.nsITVSimulatorService).simulateChannelScanComplete(aData.tunerId, aData.sourceType);
+ } catch (e) {}
+});
+
+addMessageListener('trigger-channel-scan-error', function(aData) {
+ var service = Cc["@mozilla.org/tv/tvservice;1"].getService(Ci.nsITVService);
+ try {
+ service.QueryInterface(Ci.nsITVSimulatorService).simulateChannelScanError(aData.tunerId, aData.sourceType);
+ } catch (e) {}
+});
+
+addMessageListener('trigger-eit-broadcasted', function(aData) {
+ var service = Cc["@mozilla.org/tv/tvservice;1"].getService(Ci.nsITVService);
+ try {
+ service.QueryInterface(Ci.nsITVSimulatorService).simulateEITBroadcasted(aData.tunerId, aData.sourceType, aData.channelNumber);
+ } catch (e) {}
+});