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.js199
1 files changed, 199 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 000000000..732ecd42f
--- /dev/null
+++ b/netwerk/test/unit/test_net_addr.js
@@ -0,0 +1,199 @@
+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;
+ do_print('server: listening on ' + this.port);
+ this.listener.asyncListen(this);
+}
+
+TestServer.prototype = {
+ onSocketAccepted: function(socket, trans) {
+ do_print('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: function(socket) {} ,
+
+ /**
+ * Called to close a connection and clean up properties.
+ */
+ reset: function() {
+ 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: function() {
+ this.reset();
+ try { this.listener.close(); } catch(ignore) {}
+ }
+};
+
+
+/**
+ * Helper function.
+ * Compares two nsINetAddr objects and ensures they are logically equivalent.
+ */
+function checkAddrEqual(lhs, rhs) {
+ do_check_eq(lhs.family, rhs.family);
+
+ if (lhs.family === Ci.nsINetAddr.FAMILY_INET) {
+ do_check_eq(lhs.address, rhs.address);
+ do_check_eq(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;
+
+/**
+ * Connections have 5 seconds to be made, or a timeout function fails this
+ * test. This prevents the test from hanging and bringing down the entire
+ * xpcshell test chain.
+ */
+var connectTimeout = 5*1000;
+
+/**
+ * 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
+ do_check_eq(peerAddr.family, Ci.nsINetAddr.FAMILY_INET);
+ do_check_eq(peerAddr.port, testDataStore.transport.port);
+ do_check_eq(peerAddr.port, serv.port);
+ do_check_eq(peerAddr.address, "127.0.0.1");
+
+ // check selfAddr against expected values
+ do_check_eq(selfAddr.family, Ci.nsINetAddr.FAMILY_INET);
+ do_check_eq(selfAddr.address, "127.0.0.1");
+
+ // check that selfAddr = server.peerAddr and vice versa.
+ checkAddrEqual(selfAddr, serv.peerAddr);
+ checkAddrEqual(peerAddr, serv.selfAddr);
+
+ testDataStore = null;
+ do_execute_soon(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(null, 0, '127.0.0.1', serv.port, 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();
+
+ do_register_cleanup(function(){ serv.stop(); });
+
+ add_test(testIpv4);
+ /* TODO: testIpv6 */
+ /* TODO: testLocal */
+
+ run_next_test();
+}