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