mirror of
https://gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake.git
synced 2025-10-13 20:11:19 -04:00
better ProxyPair jasmine specs, ensure travis using more recent npm
This commit is contained in:
parent
e38bed8be3
commit
889b3fee98
6 changed files with 200 additions and 32 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -10,5 +10,5 @@ snowflake.log
|
||||||
proxy/test
|
proxy/test
|
||||||
proxy/build
|
proxy/build
|
||||||
proxy/node_modules
|
proxy/node_modules
|
||||||
proxy/spec
|
proxy/spec/support
|
||||||
ignore/
|
ignore/
|
||||||
|
|
|
@ -3,6 +3,12 @@ language: go
|
||||||
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:
|
before_script:
|
||||||
npm install -g coffee-script coffeelint jasmine
|
npm install -g coffee-script coffeelint jasmine
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
fs = require 'fs'
|
fs = require 'fs'
|
||||||
{spawn, exec} = require 'child_process'
|
{exec, spawn, execSync} = require 'child_process'
|
||||||
|
|
||||||
# All coffeescript files required.
|
# All coffeescript files required.
|
||||||
FILES = [
|
FILES = [
|
||||||
|
@ -12,7 +12,8 @@ FILES = [
|
||||||
'snowflake.coffee'
|
'snowflake.coffee'
|
||||||
]
|
]
|
||||||
FILES_SPEC = [
|
FILES_SPEC = [
|
||||||
'spec.coffee'
|
'spec/util.spec.coffee'
|
||||||
|
'spec/proxypair.spec.coffee'
|
||||||
]
|
]
|
||||||
FILES_ALL = FILES.concat FILES_SPEC
|
FILES_ALL = FILES.concat FILES_SPEC
|
||||||
OUTFILE = 'build/snowflake.coffee'
|
OUTFILE = 'build/snowflake.coffee'
|
||||||
|
@ -20,19 +21,21 @@ STATIC = 'static'
|
||||||
|
|
||||||
concatCoffeeFiles = -> exec 'cat ' + FILES.join(' ') + ' | cat > ' + OUTFILE
|
concatCoffeeFiles = -> exec 'cat ' + FILES.join(' ') + ' | cat > ' + OUTFILE
|
||||||
|
|
||||||
copyStaticFiles = -> exec 'cp ' + STATIC + '/* build/'
|
copyStaticFiles = -> exec '' + STATIC + '/* build/'
|
||||||
|
|
||||||
compileCoffee = ->
|
compileCoffee = ->
|
||||||
exec 'coffee -o build -b -c build/snowflake.coffee', (err, stdout, stderr) ->
|
exec 'coffee -o build -b -c build/snowflake.coffee', (err, stdout, stderr) ->
|
||||||
throw err if err
|
throw err if err
|
||||||
|
|
||||||
task 'test', 'snowflake unit tests', ->
|
task 'test', 'snowflake unit tests', ->
|
||||||
|
exec 'mkdir -p build'
|
||||||
exec 'jasmine init >&-'
|
exec 'jasmine init >&-'
|
||||||
|
# Simply concat all the files because we're not using node exports.
|
||||||
jasmineFiles = FILES.concat FILES_SPEC
|
jasmineFiles = FILES.concat FILES_SPEC
|
||||||
outFile = 'spec/snowflake.bundle.coffee'
|
outFile = 'build/bundle.spec.coffee'
|
||||||
exec 'cat ' + jasmineFiles.join(' ') + ' | cat > ' + outFile
|
exec 'cat ' + jasmineFiles.join(' ') + ' | cat > ' + outFile
|
||||||
exec 'coffee -o spec -cb ' + outFile
|
execSync 'coffee -cb ' + outFile
|
||||||
spawn 'jasmine', ['spec/snowflake.bundle.js'], {
|
spawn 'jasmine', ['build/bundle.spec.js'], {
|
||||||
stdio: 'inherit'
|
stdio: 'inherit'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,5 +54,3 @@ task 'lint', 'ensure idiomatic coffeescript', ->
|
||||||
|
|
||||||
task 'clean', 'remove all built files', ->
|
task 'clean', 'remove all built files', ->
|
||||||
exec 'rm -r build'
|
exec 'rm -r build'
|
||||||
exec 'rm -r spec'
|
|
||||||
exec 'rm -r test/snowflake.bundle.coffee'
|
|
||||||
|
|
95
proxy/spec/proxypair.spec.coffee
Normal file
95
proxy/spec/proxypair.spec.coffee
Normal file
|
@ -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
|
|
@ -3,10 +3,14 @@ jasmine tests for Snowflake
|
||||||
###
|
###
|
||||||
|
|
||||||
# Stubs to fake browser functionality.
|
# Stubs to fake browser functionality.
|
||||||
|
class PeerConnection
|
||||||
class WebSocket
|
class WebSocket
|
||||||
OPEN: 1
|
OPEN: 1
|
||||||
CLOSED: 0
|
CLOSED: 0
|
||||||
ui = {}
|
ui =
|
||||||
|
log: ->
|
||||||
|
setActive: ->
|
||||||
|
log = ->
|
||||||
|
|
||||||
describe 'BuildUrl', ->
|
describe 'BuildUrl', ->
|
||||||
it 'should parse just protocol and host', ->
|
it 'should parse just protocol and host', ->
|
||||||
|
@ -139,14 +143,14 @@ describe 'Params', ->
|
||||||
getBool = (query) ->
|
getBool = (query) ->
|
||||||
Params.getBool (Query.parse query), 'param', false
|
Params.getBool (Query.parse query), 'param', false
|
||||||
it 'parses correctly', ->
|
it 'parses correctly', ->
|
||||||
expect(getBool 'param=true').toEqual true
|
expect(getBool 'param=true').toBe true
|
||||||
expect(getBool 'param').toEqual true
|
expect(getBool 'param').toBe true
|
||||||
expect(getBool 'param=').toEqual true
|
expect(getBool 'param=').toBe true
|
||||||
expect(getBool 'param=1').toEqual true
|
expect(getBool 'param=1').toBe true
|
||||||
expect(getBool 'param=0').toEqual false
|
expect(getBool 'param=0').toBe false
|
||||||
expect(getBool 'param=false').toEqual false
|
expect(getBool 'param=false').toBe false
|
||||||
expect(getBool 'param=unexpected').toBeNull()
|
expect(getBool 'param=unexpected').toBeNull()
|
||||||
expect(getBool 'pram=true').toEqual false
|
expect(getBool 'pram=true').toBe false
|
||||||
|
|
||||||
describe 'address', ->
|
describe 'address', ->
|
||||||
DEFAULT = { host: '1.1.1.1', port: 2222 }
|
DEFAULT = { host: '1.1.1.1', port: 2222 }
|
||||||
|
@ -166,15 +170,79 @@ describe 'ProxyPair', ->
|
||||||
rateLimit = new DummyRateLimit()
|
rateLimit = new DummyRateLimit()
|
||||||
destination = []
|
destination = []
|
||||||
fakeClient = send: (d) -> destination.push d
|
fakeClient = send: (d) -> destination.push d
|
||||||
|
# Fake snowflake to interact with
|
||||||
|
snowflake = {
|
||||||
|
broker:
|
||||||
|
sendAnswer: ->
|
||||||
|
}
|
||||||
pp = new ProxyPair(fakeClient, fakeRelay, rateLimit)
|
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()
|
pp.connectRelay()
|
||||||
expect(pp.relay.onopen).not.toBeNull()
|
expect(pp.relay.onopen).not.toBeNull()
|
||||||
expect(pp.relay.onclose).not.toBeNull()
|
expect(pp.relay.onclose).not.toBeNull()
|
||||||
expect(pp.relay.onerror).not.toBeNull()
|
expect(pp.relay.onerror).not.toBeNull()
|
||||||
expect(pp.relay.onmessage).not.toBeNull()
|
expect(pp.relay.onmessage).not.toBeNull()
|
||||||
# TODO: Test for flush
|
|
||||||
# pp.c2rSchedule.push { data: 'omg' }
|
it 'flushes data between client and relay', ->
|
||||||
# pp.flush()
|
|
||||||
# if destination == ['omg'] then pass 'flush'
|
it 'proxies data from client to relay', ->
|
||||||
# else fail 'flush', ['omg'], destination
|
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
|
|
@ -56,5 +56,3 @@ makeWebsocket = (addr) ->
|
||||||
###
|
###
|
||||||
ws.binaryType = 'arraybuffer'
|
ws.binaryType = 'arraybuffer'
|
||||||
ws
|
ws
|
||||||
|
|
||||||
# module.exports.buildUrl = buildUrl
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue