convert all coffeescript tests to jasmine

This commit is contained in:
Serene Han 2016-02-04 14:13:03 -08:00
parent 10d24accad
commit e38bed8be3
8 changed files with 205 additions and 338 deletions

1
.gitignore vendored
View file

@ -10,4 +10,5 @@ snowflake.log
proxy/test
proxy/build
proxy/node_modules
proxy/spec
ignore/

View file

@ -4,7 +4,7 @@ go:
- 1.5
before_script:
npm install -g coffee-script coffeelint
npm install -g coffee-script coffeelint jasmine
script:
- make check

View file

@ -11,10 +11,10 @@ FILES = [
'ui.coffee'
'snowflake.coffee'
]
FILES_TEST = [
'snowflake_test.coffee'
FILES_SPEC = [
'spec.coffee'
]
FILES_ALL = FILES.concat FILES_TEST
FILES_ALL = FILES.concat FILES_SPEC
OUTFILE = 'build/snowflake.coffee'
STATIC = 'static'
@ -23,16 +23,18 @@ concatCoffeeFiles = -> exec 'cat ' + FILES.join(' ') + ' | cat > ' + OUTFILE
copyStaticFiles = -> exec 'cp ' + STATIC + '/* build/'
compileCoffee = ->
exec 'coffee -o build -c build/snowflake.coffee', (err, stdout, stderr) ->
exec 'coffee -o build -b -c build/snowflake.coffee', (err, stdout, stderr) ->
throw err if err
task 'test', 'snowflake unit tests', ->
exec 'mkdir -p test'
testFile = 'test/snowflake.bundle.coffee'
exec 'cat ' + FILES.join(' ') + ' snowflake_test.coffee | cat > ' + testFile
exec 'coffee ' + testFile + ' -v', (err, stdout, stderr) ->
throw err if err
console.log stdout + stderr
exec 'jasmine init >&-'
jasmineFiles = FILES.concat FILES_SPEC
outFile = 'spec/snowflake.bundle.coffee'
exec 'cat ' + jasmineFiles.join(' ') + ' | cat > ' + outFile
exec 'coffee -o spec -cb ' + outFile
spawn 'jasmine', ['spec/snowflake.bundle.js'], {
stdio: 'inherit'
}
task 'build', 'build the snowflake proxy', ->
exec 'mkdir -p build'
@ -49,4 +51,5 @@ 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'

View file

@ -2,12 +2,16 @@ This is the browser proxy component of Snowflake.
### Testing:
Unit tests are available with:
Unit testing with Jasmine are available with:
```
cake test
```
Requires jasmine. (`npm install -g jasmine`)
To run locally, start a webserver and navigate to `snowflake.html`.
To run locally, either:
- Navigate to `proxy/build/embed.html`
- For a more fully featured "debug" version,
start a webserver and navigate to `snowflake.html`.
### Parameters
@ -16,7 +20,6 @@ snowflake uses the default relay `192.81.135.242:9901` and
uses automatic signaling with the default broker at
`https://snowflake-reg.appspot.com/`.
Here are optional parameters to include in the query string.
```
manual - enables copy-paste signalling mode.

View file

@ -15,10 +15,12 @@ COPY_PASTE_ENABLED = false
DEBUG = false
query = null
if window && window.location
if 'undefined' != typeof window && window.location
query = Query.parse(window.location.search.substr(1))
DEBUG = Params.getBool(query, 'debug', false)
COPY_PASTE_ENABLED = Params.getBool(query, 'manual', false)
else
window = {}
# HEADLESS is true if we are running not in a browser with a DOM.
HEADLESS = 'undefined' == typeof(document)

View file

@ -1,323 +0,0 @@
window = {}
ui = {}
VERBOSE = false
VERBOSE = true if process.argv.indexOf('-v') >= 0
numTests = 0
numFailed = 0
announce = (testName) ->
console.log '\n --- ' + testName + ' ---' if VERBOSE
pass = (test) ->
numTests++
console.log 'PASS ' + test if VERBOSE
fail = (test, expected, actual) ->
numTests++
numFailed++
console.log 'FAIL ' + test +
' expected: ' + JSON.stringify(expected) +
' actual: ' + JSON.stringify(actual)
# Stubs for browser functionality.
class WebSocket
OPEN: 1
CLOSED: 0
testBuildUrl = ->
TESTS = [{
args: ['http', 'example.com']
expected: 'http://example.com'
},{
args: ['http', 'example.com', 80]
expected: 'http://example.com'
},{
args: ['http', 'example.com', 81],
expected: 'http://example.com:81'
},{
args: ['https', 'example.com', 443]
expected: 'https://example.com'
},{
args: ['https', 'example.com', 444]
expected: 'https://example.com:444'
},{
args: ['http', 'example.com', 80, '/']
expected: 'http://example.com/'
},{
args: ['http', 'example.com', 80, '/test?k=%#v']
expected: 'http://example.com/test%3Fk%3D%25%23v'
},{
args: ['http', 'example.com', 80, '/test', []]
expected: 'http://example.com/test?'
},{
args: ['http', 'example.com', 80, '/test', [['k', '%#v']]]
expected: 'http://example.com/test?k=%25%23v'
},{
args: ['http', 'example.com', 80, '/test', [['a', 'b'], ['c', 'd']]]
expected: 'http://example.com/test?a=b&c=d'
},{
args: ['http', '1.2.3.4']
expected: 'http://1.2.3.4'
},{
args: ['http', '1:2::3:4']
expected: 'http://[1:2::3:4]'
},{
args: ['http', 'bog][us']
expected: 'http://bog%5D%5Bus'
},{
args: ['http', 'bog:u]s']
expected: 'http://bog%3Au%5Ds'
}]
announce 'testBuildUrl'
for test in TESTS
actual = buildUrl.apply undefined, test.args
if actual == test.expected
pass test.args
else
fail test.args, test.expected, actual
###
This test only checks that things work for strings formatted like
document.cookie. Browsers maintain several properties about this string, for
example cookie names are unique with no trailing whitespace. See
http://www.ietf.org/rfc/rfc2965.txt for the grammar.
###
testParseCookieString = ->
TESTS = [{
cs: ''
expected: {}
},{
cs: 'a=b'
expected: { a: 'b' }
},{
cs: 'a=b=c'
expected: { a: 'b=c' }
},{
cs: 'a=b; c=d'
expected: { a: 'b', c: 'd' }
},{
cs: 'a=b ; c=d'
expected: { a: 'b', c: 'd' }
},{
cs: 'a= b',
expected: { a: 'b' }
},{
cs: 'a='
expected: { a: '' }
}, {
cs: 'key',
expected: null
}, {
cs: 'key=%26%20'
expected: { key: '& ' }
}, {
cs: 'a=\'\''
expected: { a: '\'\'' }
}]
announce 'testParseCookieString'
for test in TESTS
actual = Parse.cookie test.cs
if JSON.stringify(actual) == JSON.stringify(test.expected)
pass test.cs
else
fail test.cs, test.expected, actual
testParseQueryString = ->
TESTS = [{
qs: ''
expected: {}
},{
qs: 'a=b'
expected: { a: 'b' }
},{
qs: 'a=b=c'
expected: { a: 'b=c' }
},{
qs: 'a=b&c=d'
expected: { a: 'b', c: 'd' }
},{
qs: 'client=&relay=1.2.3.4%3A9001'
expected: { client: '', relay: '1.2.3.4:9001' }
},{
qs: 'a=b%26c=d'
expected: { a: 'b&c=d' }
},{
qs: 'a%3db=d'
expected: { 'a=b': 'd' }
},{
qs: 'a=b+c%20d'
expected: { 'a': 'b c d' }
},{
qs: 'a=b+c%2bd'
expected: { 'a': 'b c+d' }
},{
qs: 'a+b=c'
expected: { 'a b': 'c' }
},{
qs: 'a=b+c+d'
expected: { a: 'b c d' }
# First appearance wins.
},{
qs: 'a=b&c=d&a=e'
expected: { a: 'b', c: 'd' }
},{
qs: 'a'
expected: { a: '' }
},{
qs: '=b',
expected: { '': 'b' }
},{
qs: '&a=b'
expected: { '': '', a: 'b' }
},{
qs: 'a=b&'
expected: { a: 'b', '':'' }
},{
qs: 'a=b&&c=d'
expected: { a: 'b', '':'', c: 'd' }
}]
announce 'testParseQueryString'
for test in TESTS
actual = Query.parse test.qs
if JSON.stringify(actual) == JSON.stringify(test.expected)
pass test.qs
else
fail test.qs, test.expected, actual
testGetParamBoolean = ->
TESTS = [{
qs: 'param=true'
expected: true
},{
qs: 'param',
expected: true
},{
qs: 'param='
expected: true
},{
qs: 'param=1'
expected: true
},{
qs: 'param=0'
expected: false
},{
qs: 'param=false'
expected: false
},{
qs: 'param=unexpected'
expected: null
},{
qs: 'pram=true'
expected: false
}]
announce 'testGetParamBoolean'
for test in TESTS
query = Query.parse test.qs
actual = Params.getBool(query, 'param', false)
if actual == test.expected
pass test.qs
else
fail test.qs, test.expected, actual
testParseAddress = ->
TESTS = [{
spec: ''
expected: null
},{
spec: '3.3.3.3:4444'
expected: { host: '3.3.3.3', port: 4444 }
},{
spec: '3.3.3.3'
expected: null
},{
spec: '3.3.3.3:0x1111'
expected: null
},{
spec: '3.3.3.3:-4444'
expected: null
},{
spec: '3.3.3.3:65536'
expected: null
},{
spec: '[1:2::a:f]:4444'
expected: { host: '1:2::a:f', port: 4444 }
},{
spec: '[1:2::a:f]'
expected: null
},{
spec: '[1:2::a:f]:0x1111'
expected: null
},{
spec: '[1:2::a:f]:-4444'
expected: null
},{
spec: '[1:2::a:f]:65536'
expected: null
},{
spec: '[1:2::ffff:1.2.3.4]:4444'
expected: { host: '1:2::ffff:1.2.3.4', port: 4444 }
}]
announce 'testParseAddrSpec'
for test in TESTS
actual = Parse.address test.spec
if JSON.stringify(actual) == JSON.stringify(test.expected)
pass test.spec
else
fail test.spec, test.expected, actual
testGetParamAddress = ->
DEFAULT = { host: '1.1.1.1', port: 2222 }
TESTS = [{
query: {}
expected: DEFAULT
},{
query: { addr: '3.3.3.3:4444' },
expected: { host: '3.3.3.3', port: 4444 }
},{
query: { x: '3.3.3.3:4444' }
expected: DEFAULT
},{
query: { addr: '---' }
expected: null
}]
announce 'testGetParamAddress'
for test in TESTS
actual = Params.getAddress test.query, 'addr', DEFAULT
if JSON.stringify(actual) == JSON.stringify(test.expected)
pass test.query
else
fail test.query, test.expected, actual
testProxyPair = ->
announce 'testProxyPair'
fakeRelay = Parse.address '0.0.0.0:12345'
rateLimit = new DummyRateLimit()
destination = []
fakeClient =
send: (d) -> destination.push d
pp = new ProxyPair(fakeClient, fakeRelay, rateLimit)
pp.connectRelay()
if null != pp.relay.onopen then pass 'relay.onopen'
else fail 'relay onopen must not be null.'
if null != pp.relay.onclose then pass 'relay.onclose'
else fail 'relay onclose must not be null.'
if null != pp.relay.onerror then pass 'relay.onerror'
else fail 'relay onerror must not be null.'
if null != pp.relay.onmessage then pass 'relay.onmessage'
else fail 'relay onmessage must not be null.'
# TODO: Test for flush
# pp.c2rSchedule.push { data: 'omg' }
# pp.flush()
# if destination == ['omg'] then pass 'flush'
# else fail 'flush', ['omg'], destination
testBuildUrl()
testParseCookieString()
testParseQueryString()
testGetParamBoolean()
testParseAddress()
testGetParamAddress()
testProxyPair()

180
proxy/spec.coffee Normal file
View file

@ -0,0 +1,180 @@
###
jasmine tests for Snowflake
###
# Stubs to fake browser functionality.
class WebSocket
OPEN: 1
CLOSED: 0
ui = {}
describe 'BuildUrl', ->
it 'should parse just protocol and host', ->
expect(buildUrl('http', 'example.com')).toBe 'http://example.com'
it 'should handle different ports', ->
expect buildUrl 'http', 'example.com', 80
.toBe 'http://example.com'
expect buildUrl 'http', 'example.com', 81
.toBe 'http://example.com:81'
expect buildUrl 'http', 'example.com', 443
.toBe 'http://example.com:443'
expect buildUrl 'http', 'example.com', 444
.toBe 'http://example.com:444'
it 'should handle paths', ->
expect buildUrl 'http', 'example.com', 80, '/'
.toBe 'http://example.com/'
expect buildUrl 'http', 'example.com', 80,'/test?k=%#v'
.toBe 'http://example.com/test%3Fk%3D%25%23v'
expect buildUrl 'http', 'example.com', 80, '/test'
.toBe 'http://example.com/test'
it 'should handle params', ->
expect buildUrl 'http', 'example.com', 80, '/test', [['k', '%#v']]
.toBe 'http://example.com/test?k=%25%23v'
expect buildUrl 'http', 'example.com', 80, '/test', [['a', 'b'], ['c', 'd']]
.toBe 'http://example.com/test?a=b&c=d'
it 'should handle ips', ->
expect buildUrl 'http', '1.2.3.4'
.toBe 'http://1.2.3.4'
expect buildUrl 'http', '1:2::3:4'
.toBe 'http://[1:2::3:4]'
it 'should handle bogus', ->
expect buildUrl 'http', 'bog][us'
.toBe 'http://bog%5D%5Bus'
expect buildUrl 'http', 'bog:u]s'
.toBe 'http://bog%3Au%5Ds'
describe 'Parse', ->
describe 'cookie', ->
it 'parses correctly', ->
expect Parse.cookie ''
.toEqual {}
expect Parse.cookie 'a=b'
.toEqual { a: 'b' }
expect Parse.cookie 'a=b=c'
.toEqual { a: 'b=c' }
expect Parse.cookie 'a=b; c=d'
.toEqual { a: 'b', c: 'd' }
expect Parse.cookie 'a=b ; c=d'
.toEqual { a: 'b', c: 'd' }
expect Parse.cookie 'a= b'
.toEqual { a: 'b' }
expect Parse.cookie 'a='
.toEqual { a: '' }
expect Parse.cookie 'key'
.toBeNull()
expect Parse.cookie 'key=%26%20'
.toEqual { key: '& ' }
expect Parse.cookie 'a=\'\''
.toEqual { a: '\'\'' }
describe 'address', ->
it 'parses IPv4', ->
expect Parse.address ''
.toBeNull()
expect Parse.address '3.3.3.3:4444'
.toEqual { host: '3.3.3.3', port: 4444 }
expect Parse.address '3.3.3.3'
.toBeNull()
expect Parse.address '3.3.3.3:0x1111'
.toBeNull()
expect Parse.address '3.3.3.3:-4444'
.toBeNull()
expect Parse.address '3.3.3.3:65536'
.toBeNull()
it 'parses IPv6', ->
expect Parse.address '[1:2::a:f]:4444'
.toEqual { host: '1:2::a:f', port: 4444 }
expect Parse.address '[1:2::a:f]'
.toBeNull()
expect Parse.address '[1:2::a:f]:0x1111'
.toBeNull()
expect Parse.address '[1:2::a:f]:-4444'
.toBeNull()
expect Parse.address '[1:2::a:f]:65536'
.toBeNull()
expect Parse.address '[1:2::ffff:1.2.3.4]:4444'
.toEqual { host: '1:2::ffff:1.2.3.4', port: 4444 }
describe 'query string', ->
it 'should parse correctly', ->
expect Query.parse ''
.toEqual {}
expect Query.parse 'a=b'
.toEqual { a: 'b' }
expect Query.parse 'a=b=c'
.toEqual { a: 'b=c' }
expect Query.parse 'a=b&c=d'
.toEqual { a: 'b', c: 'd' }
expect Query.parse 'client=&relay=1.2.3.4%3A9001'
.toEqual { client: '', relay: '1.2.3.4:9001' }
expect Query.parse 'a=b%26c=d'
.toEqual { a: 'b&c=d' }
expect Query.parse 'a%3db=d'
.toEqual { 'a=b': 'd' }
expect Query.parse 'a=b+c%20d'
.toEqual { 'a': 'b c d' }
expect Query.parse 'a=b+c%2bd'
.toEqual { 'a': 'b c+d' }
expect Query.parse 'a+b=c'
.toEqual { 'a b': 'c' }
expect Query.parse 'a=b+c+d'
.toEqual { a: 'b c d' }
it 'uses the first appearance of duplicate key', ->
expect Query.parse 'a=b&c=d&a=e'
.toEqual { a: 'b', c: 'd' }
expect Query.parse 'a'
.toEqual { a: '' }
expect Query.parse '=b'
.toEqual { '': 'b' }
expect Query.parse '&a=b'
.toEqual { '': '', a: 'b' }
expect Query.parse 'a=b&'
.toEqual { a: 'b', '':'' }
expect Query.parse 'a=b&&c=d'
.toEqual { a: 'b', '':'', c: 'd' }
describe 'Params', ->
describe 'bool', ->
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=unexpected').toBeNull()
expect(getBool 'pram=true').toEqual false
describe 'address', ->
DEFAULT = { host: '1.1.1.1', port: 2222 }
getAddress = (query) ->
Params.getAddress query, 'addr', DEFAULT
it 'parses correctly', ->
expect(getAddress {}).toEqual DEFAULT
expect getAddress { addr: '3.3.3.3:4444' }
.toEqual { host: '3.3.3.3', port: 4444 }
expect getAddress { x: '3.3.3.3:4444' }
.toEqual DEFAULT
expect getAddress { addr: '---' }
.toBeNull()
describe 'ProxyPair', ->
fakeRelay = Parse.address '0.0.0.0:12345'
rateLimit = new DummyRateLimit()
destination = []
fakeClient = send: (d) -> destination.push d
pp = new ProxyPair(fakeClient, fakeRelay, rateLimit)
it 'handles relay correctly', ->
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

View file

@ -57,3 +57,4 @@ makeWebsocket = (addr) ->
ws.binaryType = 'arraybuffer'
ws
# module.exports.buildUrl = buildUrl