]> git.proxmox.com Git - mirror_novnc.git/commitdiff
Create FABridge tester. Move wstest into tests subdir.
authorJoel Martin <github@martintribe.org>
Mon, 17 May 2010 00:21:21 +0000 (19:21 -0500)
committerJoel Martin <github@martintribe.org>
Mon, 17 May 2010 00:21:21 +0000 (19:21 -0500)
include/fab-test/FABTest.as [new file with mode: 0644]
include/fab-test/FABTestMain.as [new file with mode: 0644]
include/fab-test/FABTestMain.swf [new file with mode: 0644]
include/fab-test/FABTestMessageEvent.as [new file with mode: 0644]
include/fab-test/bridge/FABridge.as [new symlink]
include/fab-test/fab-test.js [new file with mode: 0755]
tests/fab.html [new file with mode: 0644]
tests/ws.html [new file with mode: 0644]
tests/ws.py [new file with mode: 0755]
wstest.html [deleted file]
wstest.py [deleted file]

diff --git a/include/fab-test/FABTest.as b/include/fab-test/FABTest.as
new file mode 100644 (file)
index 0000000..fe3ed61
--- /dev/null
@@ -0,0 +1,37 @@
+package {
+
+import flash.events.*;
+import flash.external.*;
+import flash.utils.*;
+
+[Event(name="message", type="FABTestMessageEvent")]
+public class FABTest extends EventDispatcher {
+  
+    private var main:FABTestMain;
+    private var intervalID:int;
+    private var seqCnt:int;
+
+    public function FABTest(main:FABTestMain) {
+        this.main = main;
+        ExternalInterface.call("console.log", "[FABTest] FABTest()");
+    }
+    
+    public function start(eventDelay:int):void {
+        ExternalInterface.call("console.log", "[FABTest] start()");
+        seqCnt = 0;
+        intervalID = setInterval(sendEvent, eventDelay);
+    }
+    
+    public function stop():void {
+        ExternalInterface.call("console.log", "[FABTest] stop()");
+        clearInterval(intervalID);
+    }
+  
+    private function sendEvent():void {
+        //ExternalInterface.call("console.log", "[FABTest] sendEvent " + seqCnt);
+        dispatchEvent(new FABTestMessageEvent("message", encodeURIComponent(seqCnt.toString())));
+        seqCnt = seqCnt + 1;
+    }
+}
+
+}
diff --git a/include/fab-test/FABTestMain.as b/include/fab-test/FABTestMain.as
new file mode 100644 (file)
index 0000000..e16ded9
--- /dev/null
@@ -0,0 +1,28 @@
+package {
+
+import flash.display.*;
+import flash.events.*;
+import bridge.FABridge;
+
+public class FABTestMain extends Sprite {
+
+    public function FABTestMain() {
+    
+        // This is to avoid "You are trying to call recursively into the Flash Player ..."
+        // error which (I heard) happens when you pass bunch of messages.
+        // This workaround was written here:
+        // http://www.themorphicgroup.com/blog/2009/02/14/fabridge-error-you-are-trying-to-call-recursively-into-the-flash-player-which-is-not-allowed/
+        FABridge.EventsToCallLater["flash.events::Event"] = "true";
+        FABridge.EventsToCallLater["FABTestMessageEvent"] = "true";
+        
+        var fab:FABridge = new FABridge();
+        fab.rootObject = this;
+        //log("Flash initialized");
+    }
+  
+    public function create():FABTest {
+        return new FABTest(this);
+    }
+}
+
+}
diff --git a/include/fab-test/FABTestMain.swf b/include/fab-test/FABTestMain.swf
new file mode 100644 (file)
index 0000000..fcdb9c8
Binary files /dev/null and b/include/fab-test/FABTestMain.swf differ
diff --git a/include/fab-test/FABTestMessageEvent.as b/include/fab-test/FABTestMessageEvent.as
new file mode 100644 (file)
index 0000000..fbf1465
--- /dev/null
@@ -0,0 +1,14 @@
+package {\r
+\r
+import flash.events.*;\r
+\r
+public class FABTestMessageEvent extends Event {\r
+    public var data:String;\r
+    \r
+    public function FABTestMessageEvent(type:String, data:String) {\r
+        super(type);\r
+        this.data = data;\r
+    }\r
+}\r
+\r
+}\r
diff --git a/include/fab-test/bridge/FABridge.as b/include/fab-test/bridge/FABridge.as
new file mode 120000 (symlink)
index 0000000..7d525f8
--- /dev/null
@@ -0,0 +1 @@
+../../web-socket-js/flash-src/bridge/FABridge.as
\ No newline at end of file
diff --git a/include/fab-test/fab-test.js b/include/fab-test/fab-test.js
new file mode 100755 (executable)
index 0000000..499366e
--- /dev/null
@@ -0,0 +1,136 @@
+// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
+// Lincense: New BSD Lincense
+
+(function() {
+  
+  var console = window.console;
+  if (!console) console = {log: function(){ }, error: function(){ }};
+
+  function hasFlash() {
+    if ('navigator' in window && 'plugins' in navigator && navigator.plugins['Shockwave Flash']) {
+      return !!navigator.plugins['Shockwave Flash'].description;
+    }
+    if ('ActiveXObject' in window) {
+      try {
+        return !!new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
+      } catch (e) {}
+    }
+    return false;
+  }
+  
+  if (!hasFlash()) {
+    console.error("Flash Player is not installed.");
+    return;
+  }
+
+  FABTest = function() {
+    var self = this;
+    FABTest.__addTask(function() {
+      self.__flash =
+        FABTest.__flash.create();
+
+      self.__flash.addEventListener("message", function(fe) {
+        var data = decodeURIComponent(fe.getData());
+        try {
+          if (self.onmessage) {
+            var e;
+            if (window.MessageEvent) {
+              e = document.createEvent("MessageEvent");
+              e.initMessageEvent("message", false, false, data, null, null, window);
+            } else { // IE
+              e = {data: data};
+            }
+            self.onmessage(e);
+          }
+        } catch (e) {
+          console.error(e.toString());
+        }
+      });
+
+      //console.log("[FABTest] Flash object is ready");
+    });
+  }
+
+  FABTest.prototype.start = function(eventDelay) {
+    if (!this.__flash) {
+      throw "INVALID_STATE_ERR: FABTest connection has not been established";
+    }
+    var result = this.__flash.start(eventDelay);
+    if (result < 0) { // success
+      return true;
+    } else {
+      return false;
+    }
+  };
+
+  FABTest.prototype.stop = function() {
+    if (!this.__flash) return;
+    this.__flash.stop();
+  };
+
+
+
+  FABTest.__tasks = [];
+
+  FABTest.__initialize = function() {
+    if (!FABTest.__swfLocation) {
+      console.error("[FABTest] set FABTest.__swfLocation to location of FABTestMain.swf");
+      return;
+    }
+    var container = document.createElement("div");
+    container.id = "fabTestContainer";
+    // Puts the Flash out of the window. Note that we cannot use display: none or visibility: hidden
+    // here because it prevents Flash from loading at least in IE.
+    container.style.position = "absolute";
+    container.style.left = "-100px";
+    container.style.top = "-100px";
+    var holder = document.createElement("div");
+    holder.id = "fabTestFlash";
+    container.appendChild(holder);
+    document.body.appendChild(container);
+    swfobject.embedSWF(
+      FABTest.__swfLocation, "fabTestFlash", "8", "8", "9.0.0",
+      null, {bridgeName: "fabTest"}, null, null,
+      function(e) {
+        if (!e.success) console.error("[FABTest] swfobject.embedSWF failed");
+      }
+    );
+    FABridge.addInitializationCallback("fabTest", function() {
+      try {
+        console.log("[FABTest] FABridge initializad");
+        FABTest.__flash = FABridge.fabTest.root();
+        for (var i = 0; i < FABTest.__tasks.length; ++i) {
+          FABTest.__tasks[i]();
+        }
+        FABTest.__tasks = [];
+      } catch (e) {
+        console.error("[FABTest] " + e.toString());
+      }
+    });
+  };
+
+  FABTest.__addTask = function(task) {
+    if (FABTest.__flash) {
+      task();
+    } else {
+      FABTest.__tasks.push(task);
+    }
+  }
+
+  // called from Flash
+  function fabTestLog(message) {
+    console.log(decodeURIComponent(message));
+  }
+
+  // called from Flash
+  function fabTestError(message) {
+    console.error(decodeURIComponent(message));
+  }
+
+  if (window.addEventListener) {
+    window.addEventListener("load", FABTest.__initialize, false);
+  } else {
+    window.attachEvent("onload", FABTest.__initialize);
+  }
+  
+})();
diff --git a/tests/fab.html b/tests/fab.html
new file mode 100644 (file)
index 0000000..6079ecc
--- /dev/null
@@ -0,0 +1,114 @@
+<html>
+
+    <head><title>FABridge Event Test</title></head>
+
+    <body>
+
+        Event Delay (ms): <input id='eventDelay' style='width:50' value="100">&nbsp;
+        <input id='startButton' type='button' value='Start' style='width:100px'
+            onclick="start();">&nbsp;
+
+        <br><br>
+        <table border=1>
+            <tr>
+                <th align="right">Good Events Received:</th>
+                <td align="right"><div id='received'>0</div></td>
+            </tr><tr>
+                <th align="right">Errors (Bad Events Received:)</th>
+                <td align="right"><div id='errors'>0</div></td>
+            </tr>
+        </table>
+
+        <br>
+        Errors:<br>
+        <textarea id="error" style="font-size: 9;" cols=80 rows=25></textarea>
+    </body>
+
+
+    <!-- Uncomment to activate firebug lite -->
+    <!--
+    <script type='text/javascript' 
+        src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
+    -->
+
+    <script src="../include/mootools.js"></script>
+    <script src="../include/util.js"></script>
+
+    <script>
+
+        function error(str) {
+            console.error(str);
+            cell = $('error');
+            cell.innerHTML += errors + ": " + str + "\n";
+            cell.scrollTop = cell.scrollHeight;
+        }
+
+        var eventDelay = 0;
+        var fab = null;
+        var recv_seq = 0, received = 0, errors = 0;
+
+        function check_event(data) {
+            //console.log(">> check_event");
+            var got_seq = parseInt(data, 10);
+            if (got_seq !== recv_seq) {
+                error("got event " + got_seq + ", expecting " + recv_seq);
+                errors = errors + 1;
+            } else {
+                received = received + 1;
+            }
+            recv_seq = got_seq + 1;
+            //console.log("<< check_event");
+        }
+
+        function update_stats() {
+            $('received').innerHTML = received;
+            $('errors').innerHTML = errors;
+        }
+
+        function start() {
+            console.log(">> start");
+            eventDelay = parseInt($('eventDelay').value, 10);
+            recv_seq = 0;
+
+            fab.onmessage = function(e) {
+                //console.log(">> FABTest.onmessage");
+                check_event(e.data);
+                //console.log("<< FABTest.onmessage");
+            };
+            fab.start(eventDelay);
+            update_ref = update_stats.periodical(1);
+
+            $('startButton').value = "Stop";
+            $('startButton').onclick = stop;
+            console.log("<< start");
+        }
+
+        function stop() {
+            console.log(">> stop");
+            fab.stop();
+            $clear(update_ref);
+            update_stats(); // Final numbers
+            recv_seq = 0;
+
+            $('startButton').value = "Start";
+            $('startButton').onclick = start;
+            console.log("<< stop");
+        }
+
+
+        /* If no builtin websockets then load web_socket.js */
+        console.log("Loading FABridge event test object");
+        var extra = "<script src='../include/web-socket-js/swfobject.js'><\/script>";
+        extra += "<script src='../include/web-socket-js/FABridge.js'><\/script>";
+        extra += "<script src='../include/fab-test/fab-test.js'><\/script>";
+        document.write(extra);
+
+        window.onload = function() {
+            console.log("onload");
+            FABTest.__swfLocation = "../include/fab-test/FABTestMain.swf";
+            console.log("creating FABridge event test object");
+            fab = new FABTest(eventDelay);
+        }
+    </script>
+
+</html>
diff --git a/tests/ws.html b/tests/ws.html
new file mode 100644 (file)
index 0000000..a2f223d
--- /dev/null
@@ -0,0 +1,246 @@
+<html>
+
+    <head><title>WebSockets Test</title></head>
+
+    <body>
+
+        Host: <input id='host' style='width:100'>&nbsp;
+        Port: <input id='port' style='width:50'>&nbsp;
+        Encrypt: <input id='encrypt' type='checkbox'>&nbsp;
+        Send Delay (ms): <input id='sendDelay' style='width:50' value="100">&nbsp;
+        <input id='connectButton' type='button' value='Start' style='width:100px'
+            onclick="connect();">&nbsp;
+
+        <br><br>
+        <table border=1>
+            <tr>
+                <th align="right">Packets sent:</th>
+                <td align="right"><div id='sent'>0</div></td>
+            </tr><tr>
+                <th align="right">Good Packets Received:</th>
+                <td align="right"><div id='received'>0</div></td>
+            </tr><tr>
+                <th align="right">Errors (Bad Packets Received:)</th>
+                <td align="right"><div id='errors'>0</div></td>
+            </tr>
+        </table>
+
+        <br>
+        Errors:<br>
+        <textarea id="error" style="font-size: 9;" cols=80 rows=25></textarea>
+    </body>
+
+
+    <!-- Uncomment to activate firebug lite -->
+    <!--
+    <script type='text/javascript' 
+        src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
+    -->
+
+    <script src="../include/mootools.js"></script>
+    <script src="../include/base64.js"></script>
+    <script src="../include/util.js"></script>
+
+    <script>
+
+        function error(str) {
+            console.error(str);
+            cell = $('error');
+            cell.innerHTML += errors + ": " + str + "\n";
+            cell.scrollTop = cell.scrollHeight;
+        }
+
+        var host = null, port = null, sendDelay = 0;
+        var ws = null, update_ref = null, send_ref = null;
+        var sent = 0, received = 0, errors = 0;
+        var max_send = 2000;
+        var recv_seq = 0, send_seq = 0;
+
+        Array.prototype.pushStr = function (str) {
+            var n = str.length;
+            for (var i=0; i < n; i++) {
+                this.push(str.charCodeAt(i));
+            }
+        }
+
+
+
+        function add (x,y) {
+            return parseInt(x,10)+parseInt(y,10);
+        }
+
+        function check_respond(data) {
+            //console.log(">> check_respond");
+            var decoded, first, last, str, length, chksum, nums, arr;
+            decoded = Base64.decode(data);
+            first = String.fromCharCode(decoded.shift());
+            last = String.fromCharCode(decoded.pop());
+
+            if (first != "^") {
+                errors++;
+                error("Packet missing start char '^'");
+                return;
+            }
+            if (last != "$") {
+                errors++;
+                error("Packet missing end char '$'");
+                return;
+            }
+            arr = decoded.map(function(num) {
+                    return String.fromCharCode(num); 
+                } ).join('').split(':');
+            seq    = arr[0];
+            length = arr[1];
+            chksum = arr[2];
+            nums   = arr[3];
+
+            //console.log("   length:" + length + " chksum:" + chksum + " nums:" + nums);
+            if (seq != recv_seq) {
+                errors++;
+                error("Expected seq " + recv_seq + " but got " + seq);
+                recv_seq = parseInt(seq,10) + 1;   // Back on track
+                return;
+            }
+            recv_seq++;
+            if (nums.length != length) {
+                errors++;
+                error("Expected length " + length + " but got " + nums.length);
+                return;
+            }
+            //real_chksum = nums.reduce(add);
+            real_chksum = 0;
+            for (var i=0; i < nums.length; i++) {
+                real_chksum += parseInt(nums.charAt(i), 10);
+            }
+            if (real_chksum != chksum) {
+                errors++
+                error("Expected chksum " + chksum + " but real chksum is " + real_chksum);
+                return;
+            }
+            received++;
+            //console.log("   Packet checks out: length:" + length + " chksum:" + chksum);
+            //console.log("<< check_respond");
+        }
+
+        function send() {
+            if (ws.bufferedAmount > 0) {
+                console.log("Delaying send");
+                return;
+            }
+            var length = Math.floor(Math.random()*(max_send-9)) + 10; // 10 - max_send
+            var numlist = [], arr = [];
+            for (var i=0; i < length; i++) {
+                numlist.push( Math.floor(Math.random()*10) );
+            }
+            //chksum = numlist.reduce(add);
+            chksum = 0;
+            for (var i=0; i < numlist.length; i++) {
+                chksum += parseInt(numlist[i], 10);
+            }
+            var nums = numlist.join('');
+            arr.pushStr("^" + send_seq + ":" + length + ":" + chksum + ":" + nums + "$")
+            send_seq ++;
+            ws.send(Base64.encode(arr));
+            sent++;
+        }
+
+        function update_stats() {
+            $('sent').innerHTML = sent;
+            $('received').innerHTML = received;
+            $('errors').innerHTML = errors;
+        }
+
+        function init_ws() {
+            console.log(">> init_ws");
+            var scheme = "ws://";
+            if ($('encrypt').checked) {
+                scheme = "wss://";
+            }
+            var uri = scheme + host + ":" + port + "/?b64encode";
+            //if (RFB.use_seq) {
+            //    uri += "&seq_num";
+            //}
+            console.log("connecting to " + uri);
+            ws = new WebSocket(uri);
+
+            ws.onmessage = function(e) {
+                //console.log(">> WebSockets.onmessage");
+                check_respond(e.data);
+                //console.log("<< WebSockets.onmessage");
+            };
+            ws.onopen = function(e) {
+                console.log(">> WebSockets.onopen");
+                send_ref = send.periodical(sendDelay);
+                console.log("<< WebSockets.onopen");
+            };
+            ws.onclose = function(e) {
+                console.log(">> WebSockets.onclose");
+                $clear(send_ref);
+                console.log("<< WebSockets.onclose");
+            };
+            ws.onerror = function(e) {
+                console.log(">> WebSockets.onerror");
+                console.log("   " + e);
+                console.log("<< WebSockets.onerror");
+            };
+
+            console.log("<< init_ws");
+        }
+
+        function connect() {
+            console.log(">> connect");
+            host = $('host').value;
+            port = $('port').value;
+            sendDelay = parseInt($('sendDelay').value, 10);
+            if ((!host) || (!port)) {
+                console.log("must set host and port");
+                return;
+            }
+
+            if (ws) {
+                ws.close();
+            }
+            init_ws();
+            update_ref = update_stats.periodical(1);
+
+            $('connectButton').value = "Stop";
+            $('connectButton').onclick = disconnect;
+            console.log("<< connect");
+        }
+
+        function disconnect() {
+            console.log(">> disconnect");
+            if (ws) {
+                ws.close();
+            }
+
+            $clear(update_ref);
+            update_stats(); // Final numbers
+            recv_seq = 0;
+            send_seq = 0;
+
+            $('connectButton').value = "Start";
+            $('connectButton').onclick = connect;
+            console.log("<< disconnect");
+        }
+
+
+        /* If no builtin websockets then load web_socket.js */
+        if (! window.WebSocket) {
+            console.log("Loading web-socket-js flash bridge");
+            var extra = "<script src='include/web-socket-js/swfobject.js'><\/script>";
+            extra += "<script src='include/web-socket-js/FABridge.js'><\/script>";
+            extra += "<script src='include/web-socket-js/web_socket.js'><\/script>";
+            document.write(extra);
+        }
+
+        window.onload = function() {
+            console.log("onload");
+            WebSocket.__swfLocation = "include/web-socket-js/WebSocketMain.swf";
+            var url = document.location.href;
+            $('host').value = (url.match(/host=([^&#]*)/) || ['',''])[1];
+            $('port').value = (url.match(/port=([^&#]*)/) || ['',''])[1];
+        }
+    </script>
+
+</html>
diff --git a/tests/ws.py b/tests/ws.py
new file mode 100755 (executable)
index 0000000..1247253
--- /dev/null
@@ -0,0 +1,162 @@
+#!/usr/bin/python
+
+'''
+WebSocket server-side load test program. Sends and receives traffic
+that has a random payload (length and content) that is checksummed and
+given a sequence number. Any errors are reported and counted.
+'''
+
+import sys, os, socket, ssl, time, traceback
+import random, time
+from base64 import b64encode, b64decode
+from select import select
+
+sys.path.insert(0,os.path.dirname(__file__) + "/../")
+from websocket import *
+
+buffer_size = 65536
+recv_cnt = send_cnt = 0
+
+
+def check(buf):
+    global recv_cnt
+
+    try:
+        data_list = decode(buf)
+    except:
+        print "\n<BOF>" + repr(buf) + "<EOF>"
+        return "Failed to decode"
+
+    err = ""
+    for data in data_list:
+        if data.count('$') > 1:
+            raise Exception("Multiple parts within single packet")
+        if len(data) == 0:
+            traffic("_")
+            continue
+
+        if data[0] != "^":
+            err += "buf did not start with '^'\n"
+            continue
+
+        try:
+            cnt, length, chksum, nums = data[1:-1].split(':')
+            cnt    = int(cnt)
+            length = int(length)
+            chksum = int(chksum)
+        except:
+            print "\n<BOF>" + repr(data) + "<EOF>"
+            err += "Invalid data format\n"
+            continue
+
+        if recv_cnt != cnt:
+            err += "Expected count %d but got %d\n" % (recv_cnt, cnt)
+            recv_cnt = cnt + 1
+            continue
+
+        recv_cnt += 1
+
+        if len(nums) != length:
+            err += "Expected length %d but got %d\n" % (length, len(nums))
+            continue
+
+        inv = nums.translate(None, "0123456789")
+        if inv:
+            err += "Invalid characters found: %s\n" % inv
+            continue
+
+        real_chksum = 0
+        for num in nums:
+            real_chksum += int(num)
+
+        if real_chksum != chksum:
+            err += "Expected checksum %d but real chksum is %d\n" % (chksum, real_chksum)
+    return err
+
+
+def generate():
+    global send_cnt, rand_array
+    length = random.randint(10, 100000)
+    numlist = rand_array[100000-length:]
+    # Error in length
+    #numlist.append(5)
+    chksum = sum(numlist)
+    # Error in checksum
+    #numlist[0] = 5
+    nums = "".join( [str(n) for n in numlist] )
+    data = "^%d:%d:%d:%s$" % (send_cnt, length, chksum, nums)
+    send_cnt += 1
+
+    return encode(data)
+
+def responder(client, delay=10):
+    global errors
+    cqueue = []
+    cpartial = ""
+    socks = [client]
+    last_send = time.time() * 1000
+
+    while True:
+        ins, outs, excepts = select(socks, socks, socks, 1)
+        if excepts: raise Exception("Socket exception")
+
+        if client in ins:
+            buf = client.recv(buffer_size)
+            if len(buf) == 0: raise Exception("Client closed")
+            #print "Client recv: %s (%d)" % (repr(buf[1:-1]), len(buf))
+            if buf[-1] == '\xff':
+                if cpartial:
+                    err = check(cpartial + buf)
+                    cpartial = ""
+                else:
+                    err = check(buf)
+                if err:
+                    traffic("}")
+                    errors = errors + 1
+                    print err
+                else:
+                    traffic(">")
+            else:
+                traffic(".>")
+                cpartial = cpartial + buf
+
+        now = time.time() * 1000
+        if client in outs and now > (last_send + delay):
+            last_send = now
+            #print "Client send: %s" % repr(cqueue[0])
+            client.send(generate())
+            traffic("<")
+
+def test_handler(client):
+    global errors, delay, send_cnt, recv_cnt
+
+    send_cnt = 0
+    recv_cnt = 0
+
+    try:
+        responder(client, delay)
+    except:
+        print "accumulated errors:", errors
+        errors = 0
+        raise
+
+
+if __name__ == '__main__':
+    errors = 0
+    try:
+        if len(sys.argv) < 2: raise
+        listen_port = int(sys.argv[1])
+        if len(sys.argv) == 3:
+            delay = int(sys.argv[2])
+        else:
+            delay = 10
+    except:
+        print "Usage: <listen_port> [delay_ms]"
+        sys.exit(1)
+
+    print "Prepopulating random array"
+    rand_array = []
+    for i in range(0, 100000):
+        rand_array.append(random.randint(0, 9))
+
+    start_server(listen_port, test_handler)
diff --git a/wstest.html b/wstest.html
deleted file mode 100644 (file)
index c0ca623..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-<html>
-
-    <head><title>WebSockets Test</title></head>
-
-    <body>
-
-        Host: <input id='host' style='width:100'>&nbsp;
-        Port: <input id='port' style='width:50'>&nbsp;
-        Encrypt: <input id='encrypt' type='checkbox'>&nbsp;
-        Send Delay (ms): <input id='sendDelay' style='width:50' value="100">&nbsp;
-        <input id='connectButton' type='button' value='Start' style='width:100px'
-            onclick="connect();">&nbsp;
-
-        <br><br>
-        <table border=1>
-            <tr>
-                <th align="right">Packets sent:</th>
-                <td align="right"><div id='sent'>0</div></td>
-            </tr><tr>
-                <th align="right">Good Packets Received:</th>
-                <td align="right"><div id='received'>0</div></td>
-            </tr><tr>
-                <th align="right">Errors (Bad Packets Received:)</th>
-                <td align="right"><div id='errors'>0</div></td>
-            </tr>
-        </table>
-
-        <br>
-        Errors:<br>
-        <textarea id="error" style="font-size: 9;" cols=80 rows=25></textarea>
-    </body>
-
-
-    <!-- Uncomment to activate firebug lite -->
-    <!--
-    <script type='text/javascript' 
-        src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script>
-    -->
-
-    <script src="include/mootools.js"></script>
-    <script src="include/base64.js"></script>
-    <script src="include/util.js"></script>
-
-    <script>
-
-        function error(str) {
-            console.error(str);
-            cell = $('error');
-            cell.innerHTML += errors + ": " + str + "\n";
-            cell.scrollTop = cell.scrollHeight;
-        }
-
-        var host = null, port = null, sendDelay = 0;
-        var ws = null, update_ref = null, send_ref = null;
-        var sent = 0, received = 0, errors = 0;
-        var max_send = 2000;
-        var recv_seq = 0, send_seq = 0;
-
-        Array.prototype.pushStr = function (str) {
-            var n = str.length;
-            for (var i=0; i < n; i++) {
-                this.push(str.charCodeAt(i));
-            }
-        }
-
-
-
-        function add (x,y) {
-            return parseInt(x,10)+parseInt(y,10);
-        }
-
-        function check_respond(data) {
-            //console.log(">> check_respond");
-            var decoded, first, last, str, length, chksum, nums, arr;
-            decoded = Base64.decode(data);
-            first = String.fromCharCode(decoded.shift());
-            last = String.fromCharCode(decoded.pop());
-
-            if (first != "^") {
-                errors++;
-                error("Packet missing start char '^'");
-                return;
-            }
-            if (last != "$") {
-                errors++;
-                error("Packet missing end char '$'");
-                return;
-            }
-            arr = decoded.map(function(num) {
-                    return String.fromCharCode(num); 
-                } ).join('').split(':');
-            seq    = arr[0];
-            length = arr[1];
-            chksum = arr[2];
-            nums   = arr[3];
-
-            //console.log("   length:" + length + " chksum:" + chksum + " nums:" + nums);
-            if (seq != recv_seq) {
-                errors++;
-                error("Expected seq " + recv_seq + " but got " + seq);
-                recv_seq = parseInt(seq,10) + 1;   // Back on track
-                return;
-            }
-            recv_seq++;
-            if (nums.length != length) {
-                errors++;
-                error("Expected length " + length + " but got " + nums.length);
-                return;
-            }
-            //real_chksum = nums.reduce(add);
-            real_chksum = 0;
-            for (var i=0; i < nums.length; i++) {
-                real_chksum += parseInt(nums.charAt(i), 10);
-            }
-            if (real_chksum != chksum) {
-                errors++
-                error("Expected chksum " + chksum + " but real chksum is " + real_chksum);
-                return;
-            }
-            received++;
-            //console.log("   Packet checks out: length:" + length + " chksum:" + chksum);
-            //console.log("<< check_respond");
-        }
-
-        function send() {
-            if (ws.bufferedAmount > 0) {
-                console.log("Delaying send");
-                return;
-            }
-            var length = Math.floor(Math.random()*(max_send-9)) + 10; // 10 - max_send
-            var numlist = [], arr = [];
-            for (var i=0; i < length; i++) {
-                numlist.push( Math.floor(Math.random()*10) );
-            }
-            //chksum = numlist.reduce(add);
-            chksum = 0;
-            for (var i=0; i < numlist.length; i++) {
-                chksum += parseInt(numlist[i], 10);
-            }
-            var nums = numlist.join('');
-            arr.pushStr("^" + send_seq + ":" + length + ":" + chksum + ":" + nums + "$")
-            send_seq ++;
-            ws.send(Base64.encode(arr));
-            sent++;
-        }
-
-        function update_stats() {
-            $('sent').innerHTML = sent;
-            $('received').innerHTML = received;
-            $('errors').innerHTML = errors;
-        }
-
-        function init_ws() {
-            console.log(">> init_ws");
-            var scheme = "ws://";
-            if ($('encrypt').checked) {
-                scheme = "wss://";
-            }
-            var uri = scheme + host + ":" + port + "/?b64encode";
-            //if (RFB.use_seq) {
-            //    uri += "&seq_num";
-            //}
-            console.log("connecting to " + uri);
-            ws = new WebSocket(uri);
-
-            ws.onmessage = function(e) {
-                //console.log(">> WebSockets.onmessage");
-                check_respond(e.data);
-                //console.log("<< WebSockets.onmessage");
-            };
-            ws.onopen = function(e) {
-                console.log(">> WebSockets.onopen");
-                send_ref = send.periodical(sendDelay);
-                console.log("<< WebSockets.onopen");
-            };
-            ws.onclose = function(e) {
-                console.log(">> WebSockets.onclose");
-                $clear(send_ref);
-                console.log("<< WebSockets.onclose");
-            };
-            ws.onerror = function(e) {
-                console.log(">> WebSockets.onerror");
-                console.log("   " + e);
-                console.log("<< WebSockets.onerror");
-            };
-
-            console.log("<< init_ws");
-        }
-
-        function connect() {
-            console.log(">> connect");
-            host = $('host').value;
-            port = $('port').value;
-            sendDelay = parseInt($('sendDelay').value, 10);
-            if ((!host) || (!port)) {
-                console.log("must set host and port");
-                return;
-            }
-
-            if (ws) {
-                ws.close();
-            }
-            init_ws();
-            update_ref = update_stats.periodical(1);
-
-            $('connectButton').value = "Stop";
-            $('connectButton').onclick = disconnect;
-            console.log("<< connect");
-        }
-
-        function disconnect() {
-            console.log(">> disconnect");
-            if (ws) {
-                ws.close();
-            }
-
-            $clear(update_ref);
-            update_stats(); // Final numbers
-            recv_seq = 0;
-            send_seq = 0;
-
-            $('connectButton').value = "Start";
-            $('connectButton').onclick = connect;
-            console.log("<< disconnect");
-        }
-
-
-        /* If no builtin websockets then load web_socket.js */
-        if (! window.WebSocket) {
-            console.log("Loading web-socket-js flash bridge");
-            var extra = "<script src='include/web-socket-js/swfobject.js'><\/script>";
-            extra += "<script src='include/web-socket-js/FABridge.js'><\/script>";
-            extra += "<script src='include/web-socket-js/web_socket.js'><\/script>";
-            document.write(extra);
-        }
-
-        window.onload = function() {
-            console.log("onload");
-            WebSocket.__swfLocation = "include/web-socket-js/WebSocketMain.swf";
-            var url = document.location.href;
-            $('host').value = (url.match(/host=([^&#]*)/) || ['',''])[1];
-            $('port').value = (url.match(/port=([^&#]*)/) || ['',''])[1];
-        }
-    </script>
-
-</html>
diff --git a/wstest.py b/wstest.py
deleted file mode 100755 (executable)
index 40d7813..0000000
--- a/wstest.py
+++ /dev/null
@@ -1,160 +0,0 @@
-#!/usr/bin/python
-
-'''
-WebSocket server-side load test program. Sends and receives traffic
-that has a random payload (length and content) that is checksummed and
-given a sequence number. Any errors are reported and counted.
-'''
-
-import sys, socket, ssl, time, traceback
-import random, time
-from base64 import b64encode, b64decode
-from select import select
-from websocket import *
-
-buffer_size = 65536
-recv_cnt = send_cnt = 0
-
-
-def check(buf):
-    global recv_cnt
-
-    try:
-        data_list = decode(buf)
-    except:
-        print "\n<BOF>" + repr(buf) + "<EOF>"
-        return "Failed to decode"
-
-    err = ""
-    for data in data_list:
-        if data.count('$') > 1:
-            raise Exception("Multiple parts within single packet")
-        if len(data) == 0:
-            traffic("_")
-            continue
-
-        if data[0] != "^":
-            err += "buf did not start with '^'\n"
-            continue
-
-        try:
-            cnt, length, chksum, nums = data[1:-1].split(':')
-            cnt    = int(cnt)
-            length = int(length)
-            chksum = int(chksum)
-        except:
-            print "\n<BOF>" + repr(data) + "<EOF>"
-            err += "Invalid data format\n"
-            continue
-
-        if recv_cnt != cnt:
-            err += "Expected count %d but got %d\n" % (recv_cnt, cnt)
-            recv_cnt = cnt + 1
-            continue
-
-        recv_cnt += 1
-
-        if len(nums) != length:
-            err += "Expected length %d but got %d\n" % (length, len(nums))
-            continue
-
-        inv = nums.translate(None, "0123456789")
-        if inv:
-            err += "Invalid characters found: %s\n" % inv
-            continue
-
-        real_chksum = 0
-        for num in nums:
-            real_chksum += int(num)
-
-        if real_chksum != chksum:
-            err += "Expected checksum %d but real chksum is %d\n" % (chksum, real_chksum)
-    return err
-
-
-def generate():
-    global send_cnt, rand_array
-    length = random.randint(10, 100000)
-    numlist = rand_array[100000-length:]
-    # Error in length
-    #numlist.append(5)
-    chksum = sum(numlist)
-    # Error in checksum
-    #numlist[0] = 5
-    nums = "".join( [str(n) for n in numlist] )
-    data = "^%d:%d:%d:%s$" % (send_cnt, length, chksum, nums)
-    send_cnt += 1
-
-    return encode(data)
-
-def responder(client, delay=10):
-    global errors
-    cqueue = []
-    cpartial = ""
-    socks = [client]
-    last_send = time.time() * 1000
-
-    while True:
-        ins, outs, excepts = select(socks, socks, socks, 1)
-        if excepts: raise Exception("Socket exception")
-
-        if client in ins:
-            buf = client.recv(buffer_size)
-            if len(buf) == 0: raise Exception("Client closed")
-            #print "Client recv: %s (%d)" % (repr(buf[1:-1]), len(buf))
-            if buf[-1] == '\xff':
-                if cpartial:
-                    err = check(cpartial + buf)
-                    cpartial = ""
-                else:
-                    err = check(buf)
-                if err:
-                    traffic("}")
-                    errors = errors + 1
-                    print err
-                else:
-                    traffic(">")
-            else:
-                traffic(".>")
-                cpartial = cpartial + buf
-
-        now = time.time() * 1000
-        if client in outs and now > (last_send + delay):
-            last_send = now
-            #print "Client send: %s" % repr(cqueue[0])
-            client.send(generate())
-            traffic("<")
-
-def test_handler(client):
-    global errors, delay, send_cnt, recv_cnt
-
-    send_cnt = 0
-    recv_cnt = 0
-
-    try:
-        responder(client, delay)
-    except:
-        print "accumulated errors:", errors
-        errors = 0
-        raise
-
-
-if __name__ == '__main__':
-    errors = 0
-    try:
-        if len(sys.argv) < 2: raise
-        listen_port = int(sys.argv[1])
-        if len(sys.argv) == 3:
-            delay = int(sys.argv[2])
-        else:
-            delay = 10
-    except:
-        print "Usage: <listen_port> [delay_ms]"
-        sys.exit(1)
-
-    print "Prepopulating random array"
-    rand_array = []
-    for i in range(0, 100000):
-        rand_array.append(random.randint(0, 9))
-
-    start_server(listen_port, test_handler)