From 889b3fee98d77163dc8ee8d5ff805129eb9dc341 Mon Sep 17 00:00:00 2001
From: Serene Han <keroserene+git@gmail.com>
Date: Fri, 5 Feb 2016 09:20:01 -0800
Subject: [PATCH] better ProxyPair jasmine specs, ensure travis using more
 recent npm

---
 .gitignore                                   |  2 +-
 .travis.yml                                  | 20 ++--
 proxy/Cakefile                               | 17 ++--
 proxy/spec/proxypair.spec.coffee             | 95 +++++++++++++++++++
 proxy/{spec.coffee => spec/util.spec.coffee} | 96 +++++++++++++++++---
 proxy/websocket.coffee                       |  2 -
 6 files changed, 200 insertions(+), 32 deletions(-)
 create mode 100644 proxy/spec/proxypair.spec.coffee
 rename proxy/{spec.coffee => spec/util.spec.coffee} (69%)

diff --git a/.gitignore b/.gitignore
index b1db25c6..f9356aec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,5 +10,5 @@ snowflake.log
 proxy/test
 proxy/build
 proxy/node_modules
-proxy/spec
+proxy/spec/support
 ignore/
diff --git a/.travis.yml b/.travis.yml
index 4a7aedda..7f4e2655 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,20 @@
 language: go
 
 go:
-    - 1.5
+  - 1.5
+
+env:
+  - TRAVIS_NODE_VERSION="4.1"
+
+install:
+  - rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $TRAVIS_NODE_VERSION
 
 before_script:
-    npm install -g coffee-script coffeelint jasmine
+  npm install -g coffee-script coffeelint jasmine
 
 script:
-    - make check
-    - go test -v -race ./broker
-    - cd proxy
-    - cake lint
-    - cake test
+  - make check
+  - go test -v -race ./broker
+  - cd proxy
+  - cake lint
+  - cake test
diff --git a/proxy/Cakefile b/proxy/Cakefile
index c5691106..a41b55bf 100644
--- a/proxy/Cakefile
+++ b/proxy/Cakefile
@@ -1,5 +1,5 @@
 fs = require 'fs'
-{spawn, exec} = require 'child_process'
+{exec, spawn, execSync} = require 'child_process'
 
 # All coffeescript files required.
 FILES = [
@@ -12,7 +12,8 @@ FILES = [
   'snowflake.coffee'
 ]
 FILES_SPEC = [
-  'spec.coffee'
+  'spec/util.spec.coffee'
+  'spec/proxypair.spec.coffee'
 ]
 FILES_ALL = FILES.concat FILES_SPEC
 OUTFILE = 'build/snowflake.coffee'
@@ -20,19 +21,21 @@ STATIC = 'static'
 
 concatCoffeeFiles = -> exec 'cat ' + FILES.join(' ') + ' | cat > ' + OUTFILE
 
-copyStaticFiles = -> exec 'cp ' + STATIC + '/* build/'
+copyStaticFiles = -> exec '' + STATIC + '/* build/'
 
 compileCoffee = ->
   exec 'coffee -o build -b -c build/snowflake.coffee', (err, stdout, stderr) ->
     throw err if err
 
 task 'test', 'snowflake unit tests', ->
+  exec 'mkdir -p build'
   exec 'jasmine init >&-'
+  # Simply concat all the files because we're not using node exports.
   jasmineFiles = FILES.concat FILES_SPEC
-  outFile = 'spec/snowflake.bundle.coffee'
+  outFile = 'build/bundle.spec.coffee'
   exec 'cat ' + jasmineFiles.join(' ') +  ' | cat > ' + outFile
-  exec 'coffee -o spec -cb ' + outFile
-  spawn 'jasmine', ['spec/snowflake.bundle.js'], {
+  execSync 'coffee -cb ' + outFile
+  spawn 'jasmine', ['build/bundle.spec.js'], {
     stdio: 'inherit'
   }
 
@@ -51,5 +54,3 @@ task 'lint', 'ensure idiomatic coffeescript', ->
 
 task 'clean', 'remove all built files', ->
   exec 'rm -r build'
-  exec 'rm -r spec'
-  exec 'rm -r test/snowflake.bundle.coffee'
diff --git a/proxy/spec/proxypair.spec.coffee b/proxy/spec/proxypair.spec.coffee
new file mode 100644
index 00000000..261d38d2
--- /dev/null
+++ b/proxy/spec/proxypair.spec.coffee
@@ -0,0 +1,95 @@
+###
+jasmine tests for Snowflake
+###
+
+# Stubs to fake browser functionality.
+class PeerConnection
+class WebSocket
+  OPEN: 1
+  CLOSED: 0
+ui =
+  log: ->
+  setActive: ->
+log = ->
+
+describe 'ProxyPair', ->
+  fakeRelay = Parse.address '0.0.0.0:12345'
+  rateLimit = new DummyRateLimit()
+  destination = []
+  fakeClient = send: (d) -> destination.push d
+  # Fake snowflake to interact with
+  snowflake = {
+    broker:
+      sendAnswer: ->
+  }
+  pp = new ProxyPair(fakeClient, fakeRelay, rateLimit)
+
+  it 'begins webrtc connection', ->
+    pp.begin()
+    expect(pp.pc).not.toBeNull()
+
+  it 'accepts WebRTC offer from some client', ->
+    it 'rejects invalid offers', ->
+      expect(pp.receiveWebRTCOffer {}).toBe false
+      expect pp.receiveWebRTCOffer {
+        type: 'answer'
+      }.toBeFalse()
+    it 'accepts valid offers', ->
+      goodOffer = {
+        type: 'offer'
+        sdp: 'foo'
+      }
+      expect(pp.receiveWebRTCOffer goodOffer).toBe true
+
+  it 'responds with a WebRTC answer correctly', ->
+    spyOn snowflake.broker, 'sendAnswer'
+    pp.pc.onicecandidate {
+      candidate: null
+    }
+    expect(snowflake.broker.sendAnswer).toHaveBeenCalled()
+
+  it 'handles a new data channel correctly', ->
+    expect(pp.client).toBeNull()
+    pp.pc.ondatachannel {
+      channel: {}
+    }
+    expect(pp.client).not.toBeNull()
+    expect(pp.client.onopen).not.toBeNull()
+    expect(pp.client.onclose).not.toBeNull()
+    expect(pp.client.onerror).not.toBeNull()
+    expect(pp.client.onmessage).not.toBeNull()
+
+  it 'connects to the relay once datachannel opens', ->
+    spyOn pp, 'connectRelay'
+    pp.client.onopen()
+    expect(pp.connectRelay).toHaveBeenCalled()
+
+  it 'connects to a relay', ->
+    pp.connectRelay()
+    expect(pp.relay.onopen).not.toBeNull()
+    expect(pp.relay.onclose).not.toBeNull()
+    expect(pp.relay.onerror).not.toBeNull()
+    expect(pp.relay.onmessage).not.toBeNull()
+
+  it 'flushes data between client and relay', ->
+
+    it 'proxies data from client to relay', ->
+      spyOn pp.relay, 'send'
+      pp.c2rSchedule.push { data: 'foo' }
+      pp.flush()
+      expect(pp.client.send).not.toHaveBeenCalled()
+      expect(pp.relay.send).toHaveBeenCalledWith 'foo'
+
+    it 'proxies data from relay to client', ->
+      spyOn pp.client, 'send'
+      pp.r2cSchedule.push { data: 'bar' }
+      pp.flush()
+      expect(pp.client.send).toHaveBeenCalledWith 'bar'
+      expect(pp.relay.send).not.toHaveBeenCalled()
+
+    it 'sends nothing with nothing to flush', ->
+      pp.flush()
+      expect(pp.client.send).not.toHaveBeenCalled()
+      expect(pp.relay.send).not.toHaveBeenCalled()
+
+# TODO: rate limit tests
diff --git a/proxy/spec.coffee b/proxy/spec/util.spec.coffee
similarity index 69%
rename from proxy/spec.coffee
rename to proxy/spec/util.spec.coffee
index 3d8ae61a..a4281e92 100644
--- a/proxy/spec.coffee
+++ b/proxy/spec/util.spec.coffee
@@ -3,10 +3,14 @@ jasmine tests for Snowflake
 ###
 
 # Stubs to fake browser functionality.
+class PeerConnection
 class WebSocket
   OPEN: 1
   CLOSED: 0
-ui = {}
+ui =
+  log: ->
+  setActive: ->
+log = ->
 
 describe 'BuildUrl', ->
   it 'should parse just protocol and host', ->
@@ -139,14 +143,14 @@ describe 'Params', ->
     getBool = (query) ->
       Params.getBool (Query.parse query), 'param', false
     it 'parses correctly', ->
-      expect(getBool 'param=true').toEqual true
-      expect(getBool 'param').toEqual true
-      expect(getBool 'param=').toEqual true
-      expect(getBool 'param=1').toEqual true
-      expect(getBool 'param=0').toEqual false
-      expect(getBool 'param=false').toEqual false
+      expect(getBool 'param=true').toBe true
+      expect(getBool 'param').toBe true
+      expect(getBool 'param=').toBe true
+      expect(getBool 'param=1').toBe true
+      expect(getBool 'param=0').toBe false
+      expect(getBool 'param=false').toBe false
       expect(getBool 'param=unexpected').toBeNull()
-      expect(getBool 'pram=true').toEqual false
+      expect(getBool 'pram=true').toBe false
 
   describe 'address', ->
     DEFAULT = { host: '1.1.1.1', port: 2222 }
@@ -166,15 +170,79 @@ describe 'ProxyPair', ->
   rateLimit = new DummyRateLimit()
   destination = []
   fakeClient = send: (d) -> destination.push d
+  # Fake snowflake to interact with
+  snowflake = {
+    broker:
+      sendAnswer: ->
+  }
   pp = new ProxyPair(fakeClient, fakeRelay, rateLimit)
-  it 'handles relay correctly', ->
+
+  it 'begins webrtc connection', ->
+    pp.begin()
+    expect(pp.pc).not.toBeNull()
+
+  it 'accepts WebRTC offer from some client', ->
+    it 'rejects invalid offers', ->
+      expect(pp.receiveWebRTCOffer {}).toBe false
+      expect pp.receiveWebRTCOffer {
+        type: 'answer'
+      }.toBeFalse()
+    it 'accepts valid offers', ->
+      goodOffer = {
+        type: 'offer'
+        sdp: 'foo'
+      }
+      expect(pp.receiveWebRTCOffer goodOffer).toBe true
+
+  it 'responds with a WebRTC answer correctly', ->
+    spyOn snowflake.broker, 'sendAnswer'
+    pp.pc.onicecandidate {
+      candidate: null
+    }
+    expect(snowflake.broker.sendAnswer).toHaveBeenCalled()
+
+  it 'handles a new data channel correctly', ->
+    expect(pp.client).toBeNull()
+    pp.pc.ondatachannel {
+      channel: {}
+    }
+    expect(pp.client).not.toBeNull()
+    expect(pp.client.onopen).not.toBeNull()
+    expect(pp.client.onclose).not.toBeNull()
+    expect(pp.client.onerror).not.toBeNull()
+    expect(pp.client.onmessage).not.toBeNull()
+
+  it 'connects to the relay once datachannel opens', ->
+    spyOn pp, 'connectRelay'
+    pp.client.onopen()
+    expect(pp.connectRelay).toHaveBeenCalled()
+
+  it 'connects to a relay', ->
     pp.connectRelay()
     expect(pp.relay.onopen).not.toBeNull()
     expect(pp.relay.onclose).not.toBeNull()
     expect(pp.relay.onerror).not.toBeNull()
     expect(pp.relay.onmessage).not.toBeNull()
-  # TODO: Test for flush
-  # pp.c2rSchedule.push { data: 'omg' }
-  # pp.flush()
-  # if destination == ['omg'] then pass 'flush'
-  # else fail 'flush', ['omg'], destination
+
+  it 'flushes data between client and relay', ->
+
+    it 'proxies data from client to relay', ->
+      spyOn pp.relay, 'send'
+      pp.c2rSchedule.push { data: 'foo' }
+      pp.flush()
+      expect(pp.client.send).not.toHaveBeenCalled()
+      expect(pp.relay.send).toHaveBeenCalledWith 'foo'
+
+    it 'proxies data from relay to client', ->
+      spyOn pp.client, 'send'
+      pp.r2cSchedule.push { data: 'bar' }
+      pp.flush()
+      expect(pp.client.send).toHaveBeenCalledWith 'bar'
+      expect(pp.relay.send).not.toHaveBeenCalled()
+
+    it 'sends nothing with nothing to flush', ->
+      pp.flush()
+      expect(pp.client.send).not.toHaveBeenCalled()
+      expect(pp.relay.send).not.toHaveBeenCalled()
+
+  # TODO: rate limit tests
diff --git a/proxy/websocket.coffee b/proxy/websocket.coffee
index 03fa0e83..e4a95506 100644
--- a/proxy/websocket.coffee
+++ b/proxy/websocket.coffee
@@ -56,5 +56,3 @@ makeWebsocket = (addr) ->
   ###
   ws.binaryType = 'arraybuffer'
   ws
-
-# module.exports.buildUrl = buildUrl
-- 
GitLab