diff options
Diffstat (limited to 'devtools/shared/webconsole/test/unit')
11 files changed, 760 insertions, 0 deletions
diff --git a/devtools/shared/webconsole/test/unit/.eslintrc.js b/devtools/shared/webconsole/test/unit/.eslintrc.js new file mode 100644 index 000000000..59adf410a --- /dev/null +++ b/devtools/shared/webconsole/test/unit/.eslintrc.js @@ -0,0 +1,6 @@ +"use strict"; + +module.exports = { + // Extend from the common devtools xpcshell eslintrc config. + "extends": "../../../../.eslintrc.xpcshell.js" +}; diff --git a/devtools/shared/webconsole/test/unit/test_js_property_provider.js b/devtools/shared/webconsole/test/unit/test_js_property_provider.js new file mode 100644 index 000000000..c360cf96d --- /dev/null +++ b/devtools/shared/webconsole/test/unit/test_js_property_provider.js @@ -0,0 +1,170 @@ +/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */ +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/publicdomain/zero/1.0/ + +"use strict"; +const { require } = Components.utils.import("resource://devtools/shared/Loader.jsm", {}); +const { FallibleJSPropertyProvider: JSPropertyProvider } = + require("devtools/shared/webconsole/js-property-provider"); + +Components.utils.import("resource://gre/modules/jsdebugger.jsm"); +addDebuggerToGlobal(this); + +function run_test() { + const testArray = `var testArray = [ + {propA: "A"}, + { + propB: "B", + propC: [ + "D" + ] + }, + [ + {propE: "E"} + ] + ]`; + + const testObject = 'var testObject = {"propA": [{"propB": "B"}]}'; + const testHyphenated = 'var testHyphenated = {"prop-A": "res-A"}'; + const testLet = "let foobar = {a: ''}; const blargh = {a: 1};"; + + let sandbox = Components.utils.Sandbox("http://example.com"); + let dbg = new Debugger; + let dbgObject = dbg.addDebuggee(sandbox); + let dbgEnv = dbgObject.asEnvironment(); + Components.utils.evalInSandbox(testArray, sandbox); + Components.utils.evalInSandbox(testObject, sandbox); + Components.utils.evalInSandbox(testHyphenated, sandbox); + Components.utils.evalInSandbox(testLet, sandbox); + + do_print("Running tests with dbgObject"); + runChecks(dbgObject, null); + + do_print("Running tests with dbgEnv"); + runChecks(null, dbgEnv); + +} + +function runChecks(dbgObject, dbgEnv) { + do_print("Test that suggestions are given for 'this'"); + let results = JSPropertyProvider(dbgObject, dbgEnv, "t"); + test_has_result(results, "this"); + + if (dbgObject != null) { + do_print("Test that suggestions are given for 'this.'"); + results = JSPropertyProvider(dbgObject, dbgEnv, "this."); + test_has_result(results, "testObject"); + + do_print("Test that no suggestions are given for 'this.this'"); + results = JSPropertyProvider(dbgObject, dbgEnv, "this.this"); + test_has_no_results(results); + } + + do_print("Testing lexical scope issues (Bug 1207868)"); + results = JSPropertyProvider(dbgObject, dbgEnv, "foobar"); + test_has_result(results, "foobar"); + + results = JSPropertyProvider(dbgObject, dbgEnv, "foobar."); + test_has_result(results, "a"); + + results = JSPropertyProvider(dbgObject, dbgEnv, "blargh"); + test_has_result(results, "blargh"); + + results = JSPropertyProvider(dbgObject, dbgEnv, "blargh."); + test_has_result(results, "a"); + + do_print("Test that suggestions are given for 'foo[n]' where n is an integer."); + results = JSPropertyProvider(dbgObject, dbgEnv, "testArray[0]."); + test_has_result(results, "propA"); + + do_print("Test that suggestions are given for multidimensional arrays."); + results = JSPropertyProvider(dbgObject, dbgEnv, "testArray[2][0]."); + test_has_result(results, "propE"); + + do_print("Test that suggestions are given for nested arrays."); + results = JSPropertyProvider(dbgObject, dbgEnv, "testArray[1].propC[0]."); + test_has_result(results, "indexOf"); + + do_print("Test that suggestions are given for literal arrays."); + results = JSPropertyProvider(dbgObject, dbgEnv, "[1,2,3]."); + test_has_result(results, "indexOf"); + + do_print("Test that suggestions are given for literal arrays with newlines."); + results = JSPropertyProvider(dbgObject, dbgEnv, "[1,2,3,\n4\n]."); + test_has_result(results, "indexOf"); + + do_print("Test that suggestions are given for literal strings."); + results = JSPropertyProvider(dbgObject, dbgEnv, "'foo'."); + test_has_result(results, "charAt"); + results = JSPropertyProvider(dbgObject, dbgEnv, '"foo".'); + test_has_result(results, "charAt"); + results = JSPropertyProvider(dbgObject, dbgEnv, "`foo`."); + test_has_result(results, "charAt"); + results = JSPropertyProvider(dbgObject, dbgEnv, "'[1,2,3]'."); + test_has_result(results, "charAt"); + + do_print("Test that suggestions are not given for syntax errors."); + results = JSPropertyProvider(dbgObject, dbgEnv, "'foo\""); + do_check_null(results); + results = JSPropertyProvider(dbgObject, dbgEnv, "[1,',2]"); + do_check_null(results); + results = JSPropertyProvider(dbgObject, dbgEnv, "'[1,2]."); + do_check_null(results); + results = JSPropertyProvider(dbgObject, dbgEnv, "'foo'.."); + do_check_null(results); + + do_print("Test that suggestions are not given without a dot."); + results = JSPropertyProvider(dbgObject, dbgEnv, "'foo'"); + test_has_no_results(results); + results = JSPropertyProvider(dbgObject, dbgEnv, "[1,2,3]"); + test_has_no_results(results); + results = JSPropertyProvider(dbgObject, dbgEnv, "[1,2,3].\n'foo'"); + test_has_no_results(results); + + do_print("Test that suggestions are not given for numeric literals."); + results = JSPropertyProvider(dbgObject, dbgEnv, "1."); + do_check_null(results); + + do_print("Test that suggestions are not given for index that's out of bounds."); + results = JSPropertyProvider(dbgObject, dbgEnv, "testArray[10]."); + do_check_null(results); + + do_print("Test that no suggestions are given if an index is not numerical somewhere in the chain."); + results = JSPropertyProvider(dbgObject, dbgEnv, "testArray[0]['propC'][0]."); + do_check_null(results); + + results = JSPropertyProvider(dbgObject, dbgEnv, "testObject['propA'][0]."); + do_check_null(results); + + results = JSPropertyProvider(dbgObject, dbgEnv, "testArray[0]['propC']."); + do_check_null(results); + + results = JSPropertyProvider(dbgObject, dbgEnv, "testArray[][1]."); + do_check_null(results); + + do_print("Test that suggestions are not given if there is an hyphen in the chain."); + results = JSPropertyProvider(dbgObject, dbgEnv, "testHyphenated['prop-A']."); + do_check_null(results); +} + +/** + * A helper that ensures an empty array of results were found. + * @param Object aResults + * The results returned by JSPropertyProvider. + */ +function test_has_no_results(aResults) { + do_check_neq(aResults, null); + do_check_eq(aResults.matches.length, 0); +} +/** + * A helper that ensures (required) results were found. + * @param Object aResults + * The results returned by JSPropertyProvider. + * @param String aRequiredSuggestion + * A suggestion that must be found from the results. + */ +function test_has_result(aResults, aRequiredSuggestion) { + do_check_neq(aResults, null); + do_check_true(aResults.matches.length > 0); + do_check_true(aResults.matches.indexOf(aRequiredSuggestion) !== -1); +} diff --git a/devtools/shared/webconsole/test/unit/test_network_helper.js b/devtools/shared/webconsole/test/unit/test_network_helper.js new file mode 100644 index 000000000..3a43ff432 --- /dev/null +++ b/devtools/shared/webconsole/test/unit/test_network_helper.js @@ -0,0 +1,47 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; +var Cu = Components.utils; +const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); + +Object.defineProperty(this, "NetworkHelper", { + get: function () { + return require("devtools/shared/webconsole/network-helper"); + }, + configurable: true, + writeable: false, + enumerable: true +}); + +function run_test() { + test_isTextMimeType(); +} + +function test_isTextMimeType() { + do_check_eq(NetworkHelper.isTextMimeType("text/plain"), true); + do_check_eq(NetworkHelper.isTextMimeType("application/javascript"), true); + do_check_eq(NetworkHelper.isTextMimeType("application/json"), true); + do_check_eq(NetworkHelper.isTextMimeType("text/css"), true); + do_check_eq(NetworkHelper.isTextMimeType("text/html"), true); + do_check_eq(NetworkHelper.isTextMimeType("image/svg+xml"), true); + do_check_eq(NetworkHelper.isTextMimeType("application/xml"), true); + + // Test custom JSON subtype + do_check_eq(NetworkHelper.isTextMimeType("application/vnd.tent.posts-feed.v0+json"), true); + do_check_eq(NetworkHelper.isTextMimeType("application/vnd.tent.posts-feed.v0-json"), true); + // Test custom XML subtype + do_check_eq(NetworkHelper.isTextMimeType("application/vnd.tent.posts-feed.v0+xml"), true); + do_check_eq(NetworkHelper.isTextMimeType("application/vnd.tent.posts-feed.v0-xml"), false); + // Test case-insensitive + do_check_eq(NetworkHelper.isTextMimeType("application/vnd.BIG-CORP+json"), true); + // Test non-text type + do_check_eq(NetworkHelper.isTextMimeType("image/png"), false); + // Test invalid types + do_check_eq(NetworkHelper.isTextMimeType("application/foo-+json"), false); + do_check_eq(NetworkHelper.isTextMimeType("application/-foo+json"), false); + do_check_eq(NetworkHelper.isTextMimeType("application/foo--bar+json"), false); + + // Test we do not cause internal errors with unoptimized regex. Bug 961097 + do_check_eq(NetworkHelper.isTextMimeType("application/vnd.google.safebrowsing-chunk"), false); +} diff --git a/devtools/shared/webconsole/test/unit/test_security-info-certificate.js b/devtools/shared/webconsole/test/unit/test_security-info-certificate.js new file mode 100644 index 000000000..be223d87e --- /dev/null +++ b/devtools/shared/webconsole/test/unit/test_security-info-certificate.js @@ -0,0 +1,68 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +// Tests that NetworkHelper.parseCertificateInfo parses certificate information +// correctly. + +const { require } = Components.utils.import("resource://devtools/shared/Loader.jsm", {}); + +Object.defineProperty(this, "NetworkHelper", { + get: function () { + return require("devtools/shared/webconsole/network-helper"); + }, + configurable: true, + writeable: false, + enumerable: true +}); + +var Ci = Components.interfaces; +const DUMMY_CERT = { + commonName: "cn", + organization: "o", + organizationalUnit: "ou", + issuerCommonName: "issuerCN", + issuerOrganization: "issuerO", + issuerOrganizationUnit: "issuerOU", + sha256Fingerprint: "qwertyuiopoiuytrewq", + sha1Fingerprint: "qwertyuiop", + validity: { + notBeforeLocalDay: "yesterday", + notAfterLocalDay: "tomorrow", + } +}; + +function run_test() { + do_print("Testing NetworkHelper.parseCertificateInfo."); + + let result = NetworkHelper.parseCertificateInfo(DUMMY_CERT); + + // Subject + equal(result.subject.commonName, DUMMY_CERT.commonName, + "Common name is correct."); + equal(result.subject.organization, DUMMY_CERT.organization, + "Organization is correct."); + equal(result.subject.organizationUnit, DUMMY_CERT.organizationUnit, + "Organizational unit is correct."); + + // Issuer + equal(result.issuer.commonName, DUMMY_CERT.issuerCommonName, + "Common name of the issuer is correct."); + equal(result.issuer.organization, DUMMY_CERT.issuerOrganization, + "Organization of the issuer is correct."); + equal(result.issuer.organizationUnit, DUMMY_CERT.issuerOrganizationUnit, + "Organizational unit of the issuer is correct."); + + // Validity + equal(result.validity.start, DUMMY_CERT.validity.notBeforeLocalDay, + "Start of the validity period is correct."); + equal(result.validity.end, DUMMY_CERT.validity.notAfterLocalDay, + "End of the validity period is correct."); + + // Fingerprints + equal(result.fingerprint.sha1, DUMMY_CERT.sha1Fingerprint, + "Certificate SHA1 fingerprint is correct."); + equal(result.fingerprint.sha256, DUMMY_CERT.sha256Fingerprint, + "Certificate SHA256 fingerprint is correct."); +} diff --git a/devtools/shared/webconsole/test/unit/test_security-info-parser.js b/devtools/shared/webconsole/test/unit/test_security-info-parser.js new file mode 100644 index 000000000..a5682e209 --- /dev/null +++ b/devtools/shared/webconsole/test/unit/test_security-info-parser.js @@ -0,0 +1,64 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +// Test that NetworkHelper.parseSecurityInfo returns correctly formatted object. + +const { require } = Components.utils.import("resource://devtools/shared/Loader.jsm", {}); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +Object.defineProperty(this, "NetworkHelper", { + get: function () { + return require("devtools/shared/webconsole/network-helper"); + }, + configurable: true, + writeable: false, + enumerable: true +}); + +var Ci = Components.interfaces; +const wpl = Ci.nsIWebProgressListener; +const MockCertificate = { + commonName: "cn", + organization: "o", + organizationalUnit: "ou", + issuerCommonName: "issuerCN", + issuerOrganization: "issuerO", + issuerOrganizationUnit: "issuerOU", + sha256Fingerprint: "qwertyuiopoiuytrewq", + sha1Fingerprint: "qwertyuiop", + validity: { + notBeforeLocalDay: "yesterday", + notAfterLocalDay: "tomorrow", + } +}; + +const MockSecurityInfo = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsITransportSecurityInfo, + Ci.nsISSLStatusProvider]), + securityState: wpl.STATE_IS_SECURE, + errorCode: 0, + SSLStatus: { + cipherSuite: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + protocolVersion: 3, // TLS_VERSION_1_2 + serverCert: MockCertificate, + } +}; + +function run_test() { + let result = NetworkHelper.parseSecurityInfo(MockSecurityInfo, {}); + + equal(result.state, "secure", "State is correct."); + + equal(result.cipherSuite, MockSecurityInfo.cipherSuite, + "Cipher suite is correct."); + + equal(result.protocolVersion, "TLSv1.2", "Protocol version is correct."); + + deepEqual(result.cert, NetworkHelper.parseCertificateInfo(MockCertificate), + "Certificate information is correct."); + + equal(result.hpkp, false, "HPKP is false when URI is not available."); + equal(result.hsts, false, "HSTS is false when URI is not available."); +} diff --git a/devtools/shared/webconsole/test/unit/test_security-info-protocol-version.js b/devtools/shared/webconsole/test/unit/test_security-info-protocol-version.js new file mode 100644 index 000000000..b84002131 --- /dev/null +++ b/devtools/shared/webconsole/test/unit/test_security-info-protocol-version.js @@ -0,0 +1,54 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +// Tests that NetworkHelper.formatSecurityProtocol returns correct +// protocol version strings. + +const { require } = Components.utils.import("resource://devtools/shared/Loader.jsm", {}); + +Object.defineProperty(this, "NetworkHelper", { + get: function () { + return require("devtools/shared/webconsole/network-helper"); + }, + configurable: true, + writeable: false, + enumerable: true +}); + +var Ci = Components.interfaces; +const TEST_CASES = [ + { + description: "TLS_VERSION_1", + input: 1, + expected: "TLSv1" + }, { + description: "TLS_VERSION_1.1", + input: 2, + expected: "TLSv1.1" + }, { + description: "TLS_VERSION_1.2", + input: 3, + expected: "TLSv1.2" + }, { + description: "TLS_VERSION_1.3", + input: 4, + expected: "TLSv1.3" + }, { + description: "invalid version", + input: -1, + expected: "Unknown" + }, +]; + +function run_test() { + do_print("Testing NetworkHelper.formatSecurityProtocol."); + + for (let {description, input, expected} of TEST_CASES) { + do_print("Testing " + description); + + equal(NetworkHelper.formatSecurityProtocol(input), expected, + "Got the expected protocol string."); + } +} diff --git a/devtools/shared/webconsole/test/unit/test_security-info-state.js b/devtools/shared/webconsole/test/unit/test_security-info-state.js new file mode 100644 index 000000000..efa493a95 --- /dev/null +++ b/devtools/shared/webconsole/test/unit/test_security-info-state.js @@ -0,0 +1,100 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +// Tests that security info parser gives correct general security state for +// different cases. + +const { require } = Components.utils.import("resource://devtools/shared/Loader.jsm", {}); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); + +Object.defineProperty(this, "NetworkHelper", { + get: function () { + return require("devtools/shared/webconsole/network-helper"); + }, + configurable: true, + writeable: false, + enumerable: true +}); + +var Ci = Components.interfaces; +const wpl = Ci.nsIWebProgressListener; +const MockSecurityInfo = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsITransportSecurityInfo, + Ci.nsISSLStatusProvider]), + securityState: wpl.STATE_IS_BROKEN, + errorCode: 0, + SSLStatus: { + protocolVersion: 3, // nsISSLStatus.TLS_VERSION_1_2 + cipherSuite: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + } +}; + +function run_test() { + test_nullSecurityInfo(); + test_insecureSecurityInfoWithNSSError(); + test_insecureSecurityInfoWithoutNSSError(); + test_brokenSecurityInfo(); + test_secureSecurityInfo(); +} + +/** + * Test that undefined security information is returns "insecure". + */ +function test_nullSecurityInfo() { + let result = NetworkHelper.parseSecurityInfo(null, {}); + equal(result.state, "insecure", + "state == 'insecure' when securityInfo was undefined"); +} + +/** + * Test that STATE_IS_INSECURE with NSSError returns "broken" + */ +function test_insecureSecurityInfoWithNSSError() { + MockSecurityInfo.securityState = wpl.STATE_IS_INSECURE; + + // Taken from security/manager/ssl/tests/unit/head_psm.js. + MockSecurityInfo.errorCode = -8180; + + let result = NetworkHelper.parseSecurityInfo(MockSecurityInfo, {}); + equal(result.state, "broken", + "state == 'broken' if securityState contains STATE_IS_INSECURE flag AND " + + "errorCode is NSS error."); + + MockSecurityInfo.errorCode = 0; +} + +/** + * Test that STATE_IS_INSECURE without NSSError returns "insecure" + */ +function test_insecureSecurityInfoWithoutNSSError() { + MockSecurityInfo.securityState = wpl.STATE_IS_INSECURE; + + let result = NetworkHelper.parseSecurityInfo(MockSecurityInfo, {}); + equal(result.state, "insecure", + "state == 'insecure' if securityState contains STATE_IS_INSECURE flag BUT " + + "errorCode is not NSS error."); +} + +/** + * Test that STATE_IS_SECURE returns "secure" + */ +function test_secureSecurityInfo() { + MockSecurityInfo.securityState = wpl.STATE_IS_SECURE; + + let result = NetworkHelper.parseSecurityInfo(MockSecurityInfo, {}); + equal(result.state, "secure", + "state == 'secure' if securityState contains STATE_IS_SECURE flag"); +} + +/** + * Test that STATE_IS_BROKEN returns "weak" + */ +function test_brokenSecurityInfo() { + MockSecurityInfo.securityState = wpl.STATE_IS_BROKEN; + + let result = NetworkHelper.parseSecurityInfo(MockSecurityInfo, {}); + equal(result.state, "weak", + "state == 'weak' if securityState contains STATE_IS_BROKEN flag"); +} diff --git a/devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js b/devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js new file mode 100644 index 000000000..b76fa141a --- /dev/null +++ b/devtools/shared/webconsole/test/unit/test_security-info-static-hpkp.js @@ -0,0 +1,47 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +// Test that NetworkHelper.parseSecurityInfo correctly detects static hpkp pins + +const { require } = Components.utils.import("resource://devtools/shared/Loader.jsm", {}); +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +const Services = require("Services"); + +Object.defineProperty(this, "NetworkHelper", { + get: function () { + return require("devtools/shared/webconsole/network-helper"); + }, + configurable: true, + writeable: false, + enumerable: true +}); + +var Ci = Components.interfaces; +const wpl = Ci.nsIWebProgressListener; + +const MockSecurityInfo = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsITransportSecurityInfo, + Ci.nsISSLStatusProvider]), + securityState: wpl.STATE_IS_SECURE, + errorCode: 0, + SSLStatus: { + cipherSuite: "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", + protocolVersion: 3, // TLS_VERSION_1_2 + serverCert: { + validity: {} + }, + } +}; + +const MockHttpInfo = { + hostname: "include-subdomains.pinning.example.com", + private: false, +}; + +function run_test() { + Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 1); + let result = NetworkHelper.parseSecurityInfo(MockSecurityInfo, MockHttpInfo); + equal(result.hpkp, true, "Static HPKP detected."); +} diff --git a/devtools/shared/webconsole/test/unit/test_security-info-weakness-reasons.js b/devtools/shared/webconsole/test/unit/test_security-info-weakness-reasons.js new file mode 100644 index 000000000..f91d8049e --- /dev/null +++ b/devtools/shared/webconsole/test/unit/test_security-info-weakness-reasons.js @@ -0,0 +1,47 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +// Tests that NetworkHelper.getReasonsForWeakness returns correct reasons for +// weak requests. + +const { require } = Components.utils.import("resource://devtools/shared/Loader.jsm", {}); + +Object.defineProperty(this, "NetworkHelper", { + get: function () { + return require("devtools/shared/webconsole/network-helper"); + }, + configurable: true, + writeable: false, + enumerable: true +}); + +var Ci = Components.interfaces; +const wpl = Ci.nsIWebProgressListener; +const TEST_CASES = [ + { + description: "weak cipher", + input: wpl.STATE_IS_BROKEN | wpl.STATE_USES_WEAK_CRYPTO, + expected: ["cipher"] + }, { + description: "only STATE_IS_BROKEN flag", + input: wpl.STATE_IS_BROKEN, + expected: [] + }, { + description: "only STATE_IS_SECURE flag", + input: wpl.STATE_IS_SECURE, + expected: [] + }, +]; + +function run_test() { + do_print("Testing NetworkHelper.getReasonsForWeakness."); + + for (let {description, input, expected} of TEST_CASES) { + do_print("Testing " + description); + + deepEqual(NetworkHelper.getReasonsForWeakness(input), expected, + "Got the expected reasons for weakness."); + } +} diff --git a/devtools/shared/webconsole/test/unit/test_throttle.js b/devtools/shared/webconsole/test/unit/test_throttle.js new file mode 100644 index 000000000..fa8b26b61 --- /dev/null +++ b/devtools/shared/webconsole/test/unit/test_throttle.js @@ -0,0 +1,140 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const Cu = Components.utils; +const Cc = Components.classes; +const Ci = Components.interfaces; +const { require } = Cu.import("resource://devtools/shared/Loader.jsm", {}); +const promise = require("promise"); +const { NetworkThrottleManager } = + require("devtools/shared/webconsole/throttle"); +const nsIScriptableInputStream = Ci.nsIScriptableInputStream; + +function TestStreamListener() { + this.state = "initial"; +} +TestStreamListener.prototype = { + onStartRequest: function() { + this.setState("start"); + }, + + onStopRequest: function() { + this.setState("stop"); + }, + + onDataAvailable: function(request, context, inputStream, offset, count) { + const sin = Components.classes["@mozilla.org/scriptableinputstream;1"] + .createInstance(nsIScriptableInputStream); + sin.init(inputStream); + this.data = sin.read(count); + this.setState("data"); + }, + + setState: function(state) { + this.state = state; + if (this._deferred) { + this._deferred.resolve(state); + this._deferred = null; + } + }, + + onStateChanged: function() { + if (!this._deferred) { + this._deferred = promise.defer(); + } + return this._deferred.promise; + } +}; + +function TestChannel() { + this.state = "initial"; + this.testListener = new TestStreamListener(); + this._throttleQueue = null; +} +TestChannel.prototype = { + QueryInterface: function() { + return this; + }, + + get throttleQueue() { + return this._throttleQueue; + }, + + set throttleQueue(q) { + this._throttleQueue = q; + this.state = "throttled"; + }, + + setNewListener: function(listener) { + this.listener = listener; + this.state = "listener"; + return this.testListener; + }, +}; + +add_task(function*() { + let throttler = new NetworkThrottleManager({ + roundTripTimeMean: 1, + roundTripTimeMax: 1, + downloadBPSMean: 500, + downloadBPSMax: 500, + uploadBPSMean: 500, + uploadBPSMax: 500, + }); + + let uploadChannel = new TestChannel(); + throttler.manageUpload(uploadChannel); + equal(uploadChannel.state, "throttled", + "NetworkThrottleManager set throttleQueue"); + + let downloadChannel = new TestChannel(); + let testListener = downloadChannel.testListener; + + let listener = throttler.manage(downloadChannel); + equal(downloadChannel.state, "listener", + "NetworkThrottleManager called setNewListener"); + + equal(testListener.state, "initial", "test listener in initial state"); + + // This method must be passed through immediately. + listener.onStartRequest(null, null); + equal(testListener.state, "start", "test listener started"); + + const TEST_INPUT = "hi bob"; + + let testStream = Cc["@mozilla.org/storagestream;1"] + .createInstance(Ci.nsIStorageStream); + testStream.init(512, 512); + let out = testStream.getOutputStream(0); + out.write(TEST_INPUT, TEST_INPUT.length); + out.close(); + let testInputStream = testStream.newInputStream(0); + + let activityDistributor = + Cc["@mozilla.org/network/http-activity-distributor;1"] + .getService(Ci.nsIHttpActivityDistributor); + let activitySeen = false; + listener.addActivityCallback(() => activitySeen = true, null, null, null, + activityDistributor + .ACTIVITY_SUBTYPE_RESPONSE_COMPLETE, + null, TEST_INPUT.length, null); + + // onDataAvailable is required to immediately read the data. + listener.onDataAvailable(null, null, testInputStream, 0, 6); + equal(testInputStream.available(), 0, "no more data should be available"); + equal(testListener.state, "start", + "test listener should not have received data"); + equal(activitySeen, false, "activity not distributed yet"); + + let newState = yield testListener.onStateChanged(); + equal(newState, "data", "test listener received data"); + equal(testListener.data, TEST_INPUT, "test listener received all the data"); + equal(activitySeen, true, "activity has been distributed"); + + let onChange = testListener.onStateChanged(); + listener.onStopRequest(null, null, null); + newState = yield onChange; + equal(newState, "stop", "onStateChanged reported"); +}); diff --git a/devtools/shared/webconsole/test/unit/xpcshell.ini b/devtools/shared/webconsole/test/unit/xpcshell.ini new file mode 100644 index 000000000..083950834 --- /dev/null +++ b/devtools/shared/webconsole/test/unit/xpcshell.ini @@ -0,0 +1,17 @@ +[DEFAULT] +tags = devtools +head = +tail = +firefox-appdir = browser +skip-if = toolkit == 'android' +support-files = + +[test_js_property_provider.js] +[test_network_helper.js] +[test_security-info-certificate.js] +[test_security-info-parser.js] +[test_security-info-protocol-version.js] +[test_security-info-state.js] +[test_security-info-static-hpkp.js] +[test_security-info-weakness-reasons.js] +[test_throttle.js] |