summaryrefslogtreecommitdiffstats
path: root/netwerk/test/unit/test_net_addr.js
diff options
context:
space:
mode:
Diffstat (limited to 'netwerk/test/unit/test_net_addr.js')
-rw-r--r--netwerk/test/unit/test_net_addr.js216
1 files changed, 216 insertions, 0 deletions
diff --git a/netwerk/test/unit/test_net_addr.js b/netwerk/test/unit/test_net_addr.js
new file mode 100644
index 0000000000..331fa9bc74
--- /dev/null
+++ b/netwerk/test/unit/test_net_addr.js
@@ -0,0 +1,216 @@
+"use strict";
+
+var CC = Components.Constructor;
+
+const ServerSocket = CC(
+ "@mozilla.org/network/server-socket;1",
+ "nsIServerSocket",
+ "init"
+);
+
+/**
+ * TestServer: A single instance of this is created as |serv|. When created,
+ * it starts listening on the loopback address on port |serv.port|. Tests will
+ * connect to it after setting |serv.acceptCallback|, which is invoked after it
+ * accepts a connection.
+ *
+ * Within |serv.acceptCallback|, various properties of |serv| can be used to
+ * run checks. After the callback, the connection is closed, but the server
+ * remains listening until |serv.stop|
+ *
+ * Note: TestServer can only handle a single connection at a time. Tests
+ * should use run_next_test at the end of |serv.acceptCallback| to start the
+ * following test which creates a connection.
+ */
+function TestServer() {
+ this.reset();
+
+ // start server.
+ // any port (-1), loopback only (true), default backlog (-1)
+ this.listener = ServerSocket(-1, true, -1);
+ this.port = this.listener.port;
+ info("server: listening on " + this.port);
+ this.listener.asyncListen(this);
+}
+
+TestServer.prototype = {
+ onSocketAccepted(socket, trans) {
+ info("server: got client connection");
+
+ // one connection at a time.
+ if (this.input !== null) {
+ try {
+ socket.close();
+ } catch (ignore) {}
+ do_throw("Test written to handle one connection at a time.");
+ }
+
+ try {
+ this.input = trans.openInputStream(0, 0, 0);
+ this.output = trans.openOutputStream(0, 0, 0);
+ this.selfAddr = trans.getScriptableSelfAddr();
+ this.peerAddr = trans.getScriptablePeerAddr();
+
+ this.acceptCallback();
+ } catch (e) {
+ /* In a native callback such as onSocketAccepted, exceptions might not
+ * get output correctly or logged to test output. Send them through
+ * do_throw, which fails the test immediately. */
+ do_report_unexpected_exception(e, "in TestServer.onSocketAccepted");
+ }
+
+ this.reset();
+ },
+
+ onStopListening(socket) {},
+
+ /**
+ * Called to close a connection and clean up properties.
+ */
+ reset() {
+ if (this.input) {
+ try {
+ this.input.close();
+ } catch (ignore) {}
+ }
+ if (this.output) {
+ try {
+ this.output.close();
+ } catch (ignore) {}
+ }
+
+ this.input = null;
+ this.output = null;
+ this.acceptCallback = null;
+ this.selfAddr = null;
+ this.peerAddr = null;
+ },
+
+ /**
+ * Cleanup for TestServer and this test case.
+ */
+ stop() {
+ this.reset();
+ try {
+ this.listener.close();
+ } catch (ignore) {}
+ },
+};
+
+/**
+ * Helper function.
+ * Compares two nsINetAddr objects and ensures they are logically equivalent.
+ */
+function checkAddrEqual(lhs, rhs) {
+ Assert.equal(lhs.family, rhs.family);
+
+ if (lhs.family === Ci.nsINetAddr.FAMILY_INET) {
+ Assert.equal(lhs.address, rhs.address);
+ Assert.equal(lhs.port, rhs.port);
+ }
+
+ /* TODO: fully support ipv6 and local */
+}
+
+/**
+ * An instance of SocketTransportService, used to create connections.
+ */
+var sts;
+
+/**
+ * Single instance of TestServer
+ */
+var serv;
+
+/**
+ * A place for individual tests to place Objects of importance for access
+ * throughout asynchronous testing. Particularly important for any output or
+ * input streams opened, as cleanup of those objects (by the garbage collector)
+ * causes the stream to close and may have other side effects.
+ */
+var testDataStore = null;
+
+/**
+ * IPv4 test.
+ */
+function testIpv4() {
+ testDataStore = {
+ transport: null,
+ ouput: null,
+ };
+
+ serv.acceptCallback = function () {
+ // disable the timeoutCallback
+ serv.timeoutCallback = function () {};
+
+ var selfAddr = testDataStore.transport.getScriptableSelfAddr();
+ var peerAddr = testDataStore.transport.getScriptablePeerAddr();
+
+ // check peerAddr against expected values
+ Assert.equal(peerAddr.family, Ci.nsINetAddr.FAMILY_INET);
+ Assert.equal(peerAddr.port, testDataStore.transport.port);
+ Assert.equal(peerAddr.port, serv.port);
+ Assert.equal(peerAddr.address, "127.0.0.1");
+
+ // check selfAddr against expected values
+ Assert.equal(selfAddr.family, Ci.nsINetAddr.FAMILY_INET);
+ Assert.equal(selfAddr.address, "127.0.0.1");
+
+ // check that selfAddr = server.peerAddr and vice versa.
+ checkAddrEqual(selfAddr, serv.peerAddr);
+ checkAddrEqual(peerAddr, serv.selfAddr);
+
+ testDataStore = null;
+ executeSoon(run_next_test);
+ };
+
+ // Useful timeout for debugging test hangs
+ /*serv.timeoutCallback = function(tname) {
+ if (tname === 'testIpv4')
+ do_throw('testIpv4 never completed a connection to TestServ');
+ };
+ do_timeout(connectTimeout, function(){ serv.timeoutCallback('testIpv4'); });*/
+
+ testDataStore.transport = sts.createTransport(
+ [],
+ "127.0.0.1",
+ serv.port,
+ null,
+ null
+ );
+ /*
+ * Need to hold |output| so that the output stream doesn't close itself and
+ * the associated connection.
+ */
+ testDataStore.output = testDataStore.transport.openOutputStream(
+ Ci.nsITransport.OPEN_BLOCKING,
+ 0,
+ 0
+ );
+
+ /* NEXT:
+ * openOutputStream -> onSocketAccepted -> acceptedCallback -> run_next_test
+ * OR (if the above timeout is uncommented)
+ * <connectTimeout lapses> -> timeoutCallback -> do_throw
+ */
+}
+
+/**
+ * Running the tests.
+ */
+function run_test() {
+ sts = Cc["@mozilla.org/network/socket-transport-service;1"].getService(
+ Ci.nsISocketTransportService
+ );
+ serv = new TestServer();
+
+ registerCleanupFunction(function () {
+ serv.stop();
+ });
+
+ add_test(testIpv4);
+ /* TODO: testIpv6 */
+ /* TODO: testLocal */
+
+ run_next_test();
+}