Compile coffee files and remove them

With,

  ./node_modules/.bin/coffee -b -c Cakefile `find . -path ./node_modules -prune -o -name '*.coffee'`
This commit is contained in:
Arlo Breault 2019-07-06 15:13:06 +02:00
parent 82562fb21d
commit 31ad9566e6
38 changed files with 2277 additions and 1725 deletions

View file

@ -1,92 +0,0 @@
###
jasmine tests for Snowflake broker
###
# fake xhr
# class XMLHttpRequest
class XMLHttpRequest
constructor: ->
@onreadystatechange = null
open: ->
setRequestHeader: ->
send: ->
DONE: 1
describe 'Broker', ->
it 'can be created', ->
b = new Broker 'fake'
expect(b.url).toEqual 'https://fake/'
expect(b.id).not.toBeNull()
describe 'getClientOffer', ->
it 'polls and promises a client offer', (done) ->
b = new Broker 'fake'
# fake successful request and response from broker.
spyOn(b, '_postRequest').and.callFake ->
b._xhr.readyState = b._xhr.DONE
b._xhr.status = Broker.STATUS.OK
b._xhr.responseText = 'fake offer'
b._xhr.onreadystatechange()
poll = b.getClientOffer()
expect(poll).not.toBeNull()
expect(b._postRequest).toHaveBeenCalled()
poll.then (desc) ->
expect(desc).toEqual 'fake offer'
done()
.catch ->
fail 'should not reject on Broker.STATUS.OK'
done()
it 'rejects if the broker timed-out', (done) ->
b = new Broker 'fake'
# fake timed-out request from broker
spyOn(b, '_postRequest').and.callFake ->
b._xhr.readyState = b._xhr.DONE
b._xhr.status = Broker.STATUS.GATEWAY_TIMEOUT
b._xhr.onreadystatechange()
poll = b.getClientOffer()
expect(poll).not.toBeNull()
expect(b._postRequest).toHaveBeenCalled()
poll.then (desc) ->
fail 'should not fulfill on Broker.STATUS.GATEWAY_TIMEOUT'
done()
, (err) ->
expect(err).toBe Broker.MESSAGE.TIMEOUT
done()
it 'rejects on any other status', (done) ->
b = new Broker 'fake'
# fake timed-out request from broker
spyOn(b, '_postRequest').and.callFake ->
b._xhr.readyState = b._xhr.DONE
b._xhr.status = 1337
b._xhr.onreadystatechange()
poll = b.getClientOffer()
expect(poll).not.toBeNull()
expect(b._postRequest).toHaveBeenCalled()
poll.then (desc) ->
fail 'should not fulfill on non-OK status'
done()
, (err) ->
expect(err).toBe Broker.MESSAGE.UNEXPECTED
expect(b._xhr.status).toBe 1337
done()
it 'responds to the broker with answer', ->
b = new Broker 'fake'
spyOn(b, '_postRequest')
b.sendAnswer 'fake id', 123
expect(b._postRequest).toHaveBeenCalledWith(
'fake id', jasmine.any(Object), 'answer', '123')
it 'POST XMLHttpRequests to the broker', ->
b = new Broker 'fake'
b._xhr = new XMLHttpRequest()
spyOn(b._xhr, 'open')
spyOn(b._xhr, 'setRequestHeader')
spyOn(b._xhr, 'send')
b._postRequest 0, b._xhr, 'test', 'data'
expect(b._xhr.open).toHaveBeenCalled()
expect(b._xhr.setRequestHeader).toHaveBeenCalled()
expect(b._xhr.send).toHaveBeenCalled()

119
proxy/spec/broker.spec.js Normal file
View file

@ -0,0 +1,119 @@
// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake broker
*/
var XMLHttpRequest;
XMLHttpRequest = (function() {
// fake xhr
// class XMLHttpRequest
class XMLHttpRequest {
constructor() {
this.onreadystatechange = null;
}
open() {}
setRequestHeader() {}
send() {}
};
XMLHttpRequest.prototype.DONE = 1;
return XMLHttpRequest;
}).call(this);
describe('Broker', function() {
it('can be created', function() {
var b;
b = new Broker('fake');
expect(b.url).toEqual('https://fake/');
return expect(b.id).not.toBeNull();
});
describe('getClientOffer', function() {
it('polls and promises a client offer', function(done) {
var b, poll;
b = new Broker('fake');
// fake successful request and response from broker.
spyOn(b, '_postRequest').and.callFake(function() {
b._xhr.readyState = b._xhr.DONE;
b._xhr.status = Broker.STATUS.OK;
b._xhr.responseText = 'fake offer';
return b._xhr.onreadystatechange();
});
poll = b.getClientOffer();
expect(poll).not.toBeNull();
expect(b._postRequest).toHaveBeenCalled();
return poll.then(function(desc) {
expect(desc).toEqual('fake offer');
return done();
}).catch(function() {
fail('should not reject on Broker.STATUS.OK');
return done();
});
});
it('rejects if the broker timed-out', function(done) {
var b, poll;
b = new Broker('fake');
// fake timed-out request from broker
spyOn(b, '_postRequest').and.callFake(function() {
b._xhr.readyState = b._xhr.DONE;
b._xhr.status = Broker.STATUS.GATEWAY_TIMEOUT;
return b._xhr.onreadystatechange();
});
poll = b.getClientOffer();
expect(poll).not.toBeNull();
expect(b._postRequest).toHaveBeenCalled();
return poll.then(function(desc) {
fail('should not fulfill on Broker.STATUS.GATEWAY_TIMEOUT');
return done();
}, function(err) {
expect(err).toBe(Broker.MESSAGE.TIMEOUT);
return done();
});
});
return it('rejects on any other status', function(done) {
var b, poll;
b = new Broker('fake');
// fake timed-out request from broker
spyOn(b, '_postRequest').and.callFake(function() {
b._xhr.readyState = b._xhr.DONE;
b._xhr.status = 1337;
return b._xhr.onreadystatechange();
});
poll = b.getClientOffer();
expect(poll).not.toBeNull();
expect(b._postRequest).toHaveBeenCalled();
return poll.then(function(desc) {
fail('should not fulfill on non-OK status');
return done();
}, function(err) {
expect(err).toBe(Broker.MESSAGE.UNEXPECTED);
expect(b._xhr.status).toBe(1337);
return done();
});
});
});
it('responds to the broker with answer', function() {
var b;
b = new Broker('fake');
spyOn(b, '_postRequest');
b.sendAnswer('fake id', 123);
return expect(b._postRequest).toHaveBeenCalledWith('fake id', jasmine.any(Object), 'answer', '123');
});
return it('POST XMLHttpRequests to the broker', function() {
var b;
b = new Broker('fake');
b._xhr = new XMLHttpRequest();
spyOn(b._xhr, 'open');
spyOn(b._xhr, 'setRequestHeader');
spyOn(b._xhr, 'send');
b._postRequest(0, b._xhr, 'test', 'data');
expect(b._xhr.open).toHaveBeenCalled();
expect(b._xhr.setRequestHeader).toHaveBeenCalled();
return expect(b._xhr.send).toHaveBeenCalled();
});
});

View file

@ -1,28 +0,0 @@
# Fake snowflake to interact with
snowflake =
ui: new UI
broker:
sendAnswer: ->
state: Snowflake.MODE.INIT
describe 'Init', ->
it 'gives a dialog when closing, only while active', ->
silenceNotifications = false
snowflake.state = Snowflake.MODE.WEBRTC_READY
msg = window.onbeforeunload()
expect(snowflake.state).toBe Snowflake.MODE.WEBRTC_READY
expect(msg).toBe Snowflake.MESSAGE.CONFIRMATION
snowflake.state = Snowflake.MODE.INIT
msg = window.onbeforeunload()
expect(snowflake.state).toBe Snowflake.MODE.INIT
expect(msg).toBe null
it 'does not give a dialog when silent flag is on', ->
silenceNotifications = true
snowflake.state = Snowflake.MODE.WEBRTC_READY
msg = window.onbeforeunload()
expect(snowflake.state).toBe Snowflake.MODE.WEBRTC_READY
expect(msg).toBe null

34
proxy/spec/init.spec.js Normal file
View file

@ -0,0 +1,34 @@
// Generated by CoffeeScript 2.4.1
// Fake snowflake to interact with
var snowflake;
snowflake = {
ui: new UI,
broker: {
sendAnswer: function() {}
},
state: Snowflake.MODE.INIT
};
describe('Init', function() {
it('gives a dialog when closing, only while active', function() {
var msg, silenceNotifications;
silenceNotifications = false;
snowflake.state = Snowflake.MODE.WEBRTC_READY;
msg = window.onbeforeunload();
expect(snowflake.state).toBe(Snowflake.MODE.WEBRTC_READY);
expect(msg).toBe(Snowflake.MESSAGE.CONFIRMATION);
snowflake.state = Snowflake.MODE.INIT;
msg = window.onbeforeunload();
expect(snowflake.state).toBe(Snowflake.MODE.INIT);
return expect(msg).toBe(null);
});
return it('does not give a dialog when silent flag is on', function() {
var msg, silenceNotifications;
silenceNotifications = true;
snowflake.state = Snowflake.MODE.WEBRTC_READY;
msg = window.onbeforeunload();
expect(snowflake.state).toBe(Snowflake.MODE.WEBRTC_READY);
return expect(msg).toBe(null);
});
});

View file

@ -1,125 +0,0 @@
###
jasmine tests for Snowflake proxypair
###
# Replacement for MessageEvent constructor.
# https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/MessageEvent
MessageEvent = (type, init) ->
init
# Asymmetic matcher that checks that two arrays have the same contents.
arrayMatching = (sample) -> {
asymmetricMatch: (other) ->
a = new Uint8Array(sample)
b = new Uint8Array(other)
if a.length != b.length
return false
for _, i in a
if a[i] != b[i]
return false
true
jasmineToString: ->
'<arrayMatchine(' + jasmine.pp(sample) + ')>'
}
describe 'ProxyPair', ->
fakeRelay = Parse.address '0.0.0.0:12345'
rateLimit = new DummyRateLimit
config = new Config
destination = []
# Using the mock PeerConnection definition from spec/snowflake.spec.coffee.
pp = new ProxyPair(fakeRelay, rateLimit, config.pcConfig)
beforeEach ->
pp.begin()
it 'begins webrtc connection', ->
expect(pp.pc).not.toBeNull()
describe 'accepts WebRTC offer from some client', ->
beforeEach ->
pp.begin()
it 'rejects invalid offers', ->
expect(typeof(pp.pc.setRemoteDescription)).toBe("function")
expect(pp.pc).not.toBeNull()
expect(pp.receiveWebRTCOffer {}).toBe false
expect(pp.receiveWebRTCOffer {
type: 'answer'
}).toBe false
it 'accepts valid offers', ->
expect(pp.pc).not.toBeNull()
expect(pp.receiveWebRTCOffer {
type: 'offer'
sdp: 'foo'
}).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()
describe 'flushes data between client and relay', ->
it 'proxies data from client to relay', ->
pp.pc.ondatachannel {
channel: {
bufferedAmount: 0
readyState: "open"
send: (data) ->
}
}
spyOn pp.client, 'send'
spyOn pp.relay, 'send'
msg = new MessageEvent("message", {
data: Uint8Array.from([1, 2, 3]).buffer
})
pp.onClientToRelayMessage(msg)
pp.flush()
expect(pp.client.send).not.toHaveBeenCalled()
expect(pp.relay.send).toHaveBeenCalledWith arrayMatching([1, 2, 3])
it 'proxies data from relay to client', ->
spyOn pp.client, 'send'
spyOn pp.relay, 'send'
msg = new MessageEvent("message", {
data: Uint8Array.from([4, 5, 6]).buffer
})
pp.onRelayToClientMessage(msg)
pp.flush()
expect(pp.client.send).toHaveBeenCalledWith arrayMatching([4, 5, 6])
expect(pp.relay.send).not.toHaveBeenCalled()
it 'sends nothing with nothing to flush', ->
spyOn pp.client, 'send'
spyOn pp.relay, 'send'
pp.flush()
expect(pp.client.send).not.toHaveBeenCalled()
expect(pp.relay.send).not.toHaveBeenCalled()
# TODO: rate limit tests

View file

@ -0,0 +1,143 @@
// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake proxypair
*/
var MessageEvent, arrayMatching;
// Replacement for MessageEvent constructor.
// https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/MessageEvent
MessageEvent = function(type, init) {
return init;
};
// Asymmetic matcher that checks that two arrays have the same contents.
arrayMatching = function(sample) {
return {
asymmetricMatch: function(other) {
var _, a, b, i, j, len;
a = new Uint8Array(sample);
b = new Uint8Array(other);
if (a.length !== b.length) {
return false;
}
for (i = j = 0, len = a.length; j < len; i = ++j) {
_ = a[i];
if (a[i] !== b[i]) {
return false;
}
}
return true;
},
jasmineToString: function() {
return '<arrayMatchine(' + jasmine.pp(sample) + ')>';
}
};
};
describe('ProxyPair', function() {
var config, destination, fakeRelay, pp, rateLimit;
fakeRelay = Parse.address('0.0.0.0:12345');
rateLimit = new DummyRateLimit;
config = new Config;
destination = [];
// Using the mock PeerConnection definition from spec/snowflake.spec.coffee.
pp = new ProxyPair(fakeRelay, rateLimit, config.pcConfig);
beforeEach(function() {
return pp.begin();
});
it('begins webrtc connection', function() {
return expect(pp.pc).not.toBeNull();
});
describe('accepts WebRTC offer from some client', function() {
beforeEach(function() {
return pp.begin();
});
it('rejects invalid offers', function() {
expect(typeof pp.pc.setRemoteDescription).toBe("function");
expect(pp.pc).not.toBeNull();
expect(pp.receiveWebRTCOffer({})).toBe(false);
return expect(pp.receiveWebRTCOffer({
type: 'answer'
})).toBe(false);
});
return it('accepts valid offers', function() {
expect(pp.pc).not.toBeNull();
return expect(pp.receiveWebRTCOffer({
type: 'offer',
sdp: 'foo'
})).toBe(true);
});
});
it('responds with a WebRTC answer correctly', function() {
spyOn(snowflake.broker, 'sendAnswer');
pp.pc.onicecandidate({
candidate: null
});
return expect(snowflake.broker.sendAnswer).toHaveBeenCalled();
});
it('handles a new data channel correctly', function() {
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();
return expect(pp.client.onmessage).not.toBeNull();
});
it('connects to the relay once datachannel opens', function() {
spyOn(pp, 'connectRelay');
pp.client.onopen();
return expect(pp.connectRelay).toHaveBeenCalled();
});
it('connects to a relay', function() {
pp.connectRelay();
expect(pp.relay.onopen).not.toBeNull();
expect(pp.relay.onclose).not.toBeNull();
expect(pp.relay.onerror).not.toBeNull();
return expect(pp.relay.onmessage).not.toBeNull();
});
return describe('flushes data between client and relay', function() {
it('proxies data from client to relay', function() {
var msg;
pp.pc.ondatachannel({
channel: {
bufferedAmount: 0,
readyState: "open",
send: function(data) {}
}
});
spyOn(pp.client, 'send');
spyOn(pp.relay, 'send');
msg = new MessageEvent("message", {
data: Uint8Array.from([1, 2, 3]).buffer
});
pp.onClientToRelayMessage(msg);
pp.flush();
expect(pp.client.send).not.toHaveBeenCalled();
return expect(pp.relay.send).toHaveBeenCalledWith(arrayMatching([1, 2, 3]));
});
it('proxies data from relay to client', function() {
var msg;
spyOn(pp.client, 'send');
spyOn(pp.relay, 'send');
msg = new MessageEvent("message", {
data: Uint8Array.from([4, 5, 6]).buffer
});
pp.onRelayToClientMessage(msg);
pp.flush();
expect(pp.client.send).toHaveBeenCalledWith(arrayMatching([4, 5, 6]));
return expect(pp.relay.send).not.toHaveBeenCalled();
});
return it('sends nothing with nothing to flush', function() {
spyOn(pp.client, 'send');
spyOn(pp.relay, 'send');
pp.flush();
expect(pp.client.send).not.toHaveBeenCalled();
return expect(pp.relay.send).not.toHaveBeenCalled();
});
});
});
// TODO: rate limit tests

View file

@ -1,67 +0,0 @@
###
jasmine tests for Snowflake
###
# Fake browser functionality:
class PeerConnection
setRemoteDescription: ->
true
send: (data) ->
class SessionDescription
type: 'offer'
class WebSocket
OPEN: 1
CLOSED: 0
constructor: ->
@bufferedAmount = 0
send: (data) ->
log = ->
config = new Config
ui = new UI
class FakeBroker
getClientOffer: -> new Promise((F,R) -> {})
describe 'Snowflake', ->
it 'constructs correctly', ->
s = new Snowflake(config, ui, { fake: 'broker' })
expect(s.rateLimit).not.toBeNull()
expect(s.broker).toEqual { fake: 'broker' }
expect(s.ui).not.toBeNull()
expect(s.retries).toBe 0
it 'sets relay address correctly', ->
s = new Snowflake(config, ui, null)
s.setRelayAddr 'foo'
expect(s.relayAddr).toEqual 'foo'
it 'initalizes WebRTC connection', ->
s = new Snowflake(config, ui, new FakeBroker())
spyOn(s.broker, 'getClientOffer').and.callThrough()
s.beginWebRTC()
expect(s.retries).toBe 1
expect(s.broker.getClientOffer).toHaveBeenCalled()
it 'receives SDP offer and sends answer', ->
s = new Snowflake(config, ui, new FakeBroker())
pair = { receiveWebRTCOffer: -> }
spyOn(pair, 'receiveWebRTCOffer').and.returnValue true
spyOn(s, 'sendAnswer')
s.receiveOffer pair, '{"type":"offer","sdp":"foo"}'
expect(s.sendAnswer).toHaveBeenCalled()
it 'does not send answer when receiving invalid offer', ->
s = new Snowflake(config, ui, new FakeBroker())
pair = { receiveWebRTCOffer: -> }
spyOn(pair, 'receiveWebRTCOffer').and.returnValue false
spyOn(s, 'sendAnswer')
s.receiveOffer pair, '{"type":"not a good offer","sdp":"foo"}'
expect(s.sendAnswer).not.toHaveBeenCalled()
it 'can make a proxypair', ->
s = new Snowflake(config, ui, new FakeBroker())
s.makeProxyPair()
expect(s.proxyPairs.length).toBe 1

View file

@ -0,0 +1,114 @@
// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake
*/
var FakeBroker, PeerConnection, SessionDescription, WebSocket, config, log, ui;
// Fake browser functionality:
PeerConnection = class PeerConnection {
setRemoteDescription() {
return true;
}
send(data) {}
};
SessionDescription = (function() {
class SessionDescription {};
SessionDescription.prototype.type = 'offer';
return SessionDescription;
}).call(this);
WebSocket = (function() {
class WebSocket {
constructor() {
this.bufferedAmount = 0;
}
send(data) {}
};
WebSocket.prototype.OPEN = 1;
WebSocket.prototype.CLOSED = 0;
return WebSocket;
}).call(this);
log = function() {};
config = new Config;
ui = new UI;
FakeBroker = class FakeBroker {
getClientOffer() {
return new Promise(function(F, R) {
return {};
});
}
};
describe('Snowflake', function() {
it('constructs correctly', function() {
var s;
s = new Snowflake(config, ui, {
fake: 'broker'
});
expect(s.rateLimit).not.toBeNull();
expect(s.broker).toEqual({
fake: 'broker'
});
expect(s.ui).not.toBeNull();
return expect(s.retries).toBe(0);
});
it('sets relay address correctly', function() {
var s;
s = new Snowflake(config, ui, null);
s.setRelayAddr('foo');
return expect(s.relayAddr).toEqual('foo');
});
it('initalizes WebRTC connection', function() {
var s;
s = new Snowflake(config, ui, new FakeBroker());
spyOn(s.broker, 'getClientOffer').and.callThrough();
s.beginWebRTC();
expect(s.retries).toBe(1);
return expect(s.broker.getClientOffer).toHaveBeenCalled();
});
it('receives SDP offer and sends answer', function() {
var pair, s;
s = new Snowflake(config, ui, new FakeBroker());
pair = {
receiveWebRTCOffer: function() {}
};
spyOn(pair, 'receiveWebRTCOffer').and.returnValue(true);
spyOn(s, 'sendAnswer');
s.receiveOffer(pair, '{"type":"offer","sdp":"foo"}');
return expect(s.sendAnswer).toHaveBeenCalled();
});
it('does not send answer when receiving invalid offer', function() {
var pair, s;
s = new Snowflake(config, ui, new FakeBroker());
pair = {
receiveWebRTCOffer: function() {}
};
spyOn(pair, 'receiveWebRTCOffer').and.returnValue(false);
spyOn(s, 'sendAnswer');
s.receiveOffer(pair, '{"type":"not a good offer","sdp":"foo"}');
return expect(s.sendAnswer).not.toHaveBeenCalled();
});
return it('can make a proxypair', function() {
var s;
s = new Snowflake(config, ui, new FakeBroker());
s.makeProxyPair();
return expect(s.proxyPairs.length).toBe(1);
});
});

View file

@ -1,57 +0,0 @@
###
jasmine tests for Snowflake UI
###
document =
getElementById: (id) -> {}
createTextNode: (txt) -> txt
describe 'UI', ->
it 'activates debug mode when badge does not exist', ->
spyOn(document, 'getElementById').and.callFake (id) ->
return null if 'badge' == id
return {}
u = new DebugUI()
expect(document.getElementById.calls.count()).toEqual 2
expect(u.$status).not.toBeNull()
expect(u.$msglog).not.toBeNull()
it 'is not debug mode when badge exists', ->
spyOn(document, 'getElementById').and.callFake (id) ->
return {} if 'badge' == id
return null
u = new BadgeUI()
expect(document.getElementById).toHaveBeenCalled()
expect(document.getElementById.calls.count()).toEqual 1
expect(u.$badge).not.toBeNull()
it 'sets status message when in debug mode', ->
u = new DebugUI()
u.$status =
innerHTML: ''
appendChild: (txt) -> @innerHTML = txt
u.setStatus('test')
expect(u.$status.innerHTML).toEqual 'Status: test'
it 'sets message log css correctly for debug mode', ->
u = new DebugUI()
u.setActive true
expect(u.$msglog.className).toEqual 'active'
u.setActive false
expect(u.$msglog.className).toEqual ''
it 'sets badge css correctly for non-debug mode', ->
u = new BadgeUI()
u.$badge = {}
u.setActive true
expect(u.$badge.className).toEqual 'active'
u.setActive false
expect(u.$badge.className).toEqual ''
it 'logs to the textarea correctly when debug mode', ->
u = new DebugUI()
u.$msglog = { value: '', scrollTop: 0, scrollHeight: 1337 }
u.log 'test'
expect(u.$msglog.value).toEqual 'test\n'
expect(u.$msglog.scrollTop).toEqual 1337

84
proxy/spec/ui.spec.js Normal file
View file

@ -0,0 +1,84 @@
// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake UI
*/
var document;
document = {
getElementById: function(id) {
return {};
},
createTextNode: function(txt) {
return txt;
}
};
describe('UI', function() {
it('activates debug mode when badge does not exist', function() {
var u;
spyOn(document, 'getElementById').and.callFake(function(id) {
if ('badge' === id) {
return null;
}
return {};
});
u = new DebugUI();
expect(document.getElementById.calls.count()).toEqual(2);
expect(u.$status).not.toBeNull();
return expect(u.$msglog).not.toBeNull();
});
it('is not debug mode when badge exists', function() {
var u;
spyOn(document, 'getElementById').and.callFake(function(id) {
if ('badge' === id) {
return {};
}
return null;
});
u = new BadgeUI();
expect(document.getElementById).toHaveBeenCalled();
expect(document.getElementById.calls.count()).toEqual(1);
return expect(u.$badge).not.toBeNull();
});
it('sets status message when in debug mode', function() {
var u;
u = new DebugUI();
u.$status = {
innerHTML: '',
appendChild: function(txt) {
return this.innerHTML = txt;
}
};
u.setStatus('test');
return expect(u.$status.innerHTML).toEqual('Status: test');
});
it('sets message log css correctly for debug mode', function() {
var u;
u = new DebugUI();
u.setActive(true);
expect(u.$msglog.className).toEqual('active');
u.setActive(false);
return expect(u.$msglog.className).toEqual('');
});
it('sets badge css correctly for non-debug mode', function() {
var u;
u = new BadgeUI();
u.$badge = {};
u.setActive(true);
expect(u.$badge.className).toEqual('active');
u.setActive(false);
return expect(u.$badge.className).toEqual('');
});
return it('logs to the textarea correctly when debug mode', function() {
var u;
u = new DebugUI();
u.$msglog = {
value: '',
scrollTop: 0,
scrollHeight: 1337
};
u.log('test');
expect(u.$msglog.value).toEqual('test\n');
return expect(u.$msglog.scrollTop).toEqual(1337);
});
});

View file

@ -1,236 +0,0 @@
###
jasmine tests for Snowflake utils
###
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 'ipFromSDP', ->
testCases = [
# https://tools.ietf.org/html/rfc4566#section-5
sdp: """
v=0
o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
s=SDP Seminar
i=A Seminar on the session description protocol
u=http://www.example.com/seminars/sdp.pdf
e=j.doe@example.com (Jane Doe)
c=IN IP4 224.2.17.12/127
t=2873397496 2873404696
a=recvonly
m=audio 49170 RTP/AVP 0
m=video 51372 RTP/AVP 99
a=rtpmap:99 h263-1998/90000
"""
expected: '224.2.17.12'
,
# Missing c= line
sdp: """
v=0
o=jdoe 2890844526 2890842807 IN IP4 10.47.16.5
s=SDP Seminar
i=A Seminar on the session description protocol
u=http://www.example.com/seminars/sdp.pdf
e=j.doe@example.com (Jane Doe)
t=2873397496 2873404696
a=recvonly
m=audio 49170 RTP/AVP 0
m=video 51372 RTP/AVP 99
a=rtpmap:99 h263-1998/90000
"""
expected: undefined
,
# Single line, IP address only
sdp: "c=IN IP4 224.2.1.1\n"
expected: '224.2.1.1'
,
# Same, with TTL
sdp: "c=IN IP4 224.2.1.1/127\n"
expected: '224.2.1.1'
,
# Same, with TTL and multicast addresses
sdp: "c=IN IP4 224.2.1.1/127/3\n"
expected: '224.2.1.1'
,
# IPv6, address only
sdp: "c=IN IP6 FF15::101\n"
expected: 'ff15::101'
,
# Same, with multicast addresses
sdp: "c=IN IP6 FF15::101/3\n"
expected: 'ff15::101'
,
# Multiple c= lines
sdp: """
c=IN IP4 1.2.3.4
c=IN IP4 5.6.7.8
"""
expected: '1.2.3.4'
,
# Modified from SDP sent by snowflake-client.
# coffeelint: disable
sdp: """
v=0
o=- 7860378660295630295 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE data
a=msid-semantic: WMS
m=application 54653 DTLS/SCTP 5000
c=IN IP4 1.2.3.4
a=candidate:3581707038 1 udp 2122260223 192.168.0.1 54653 typ host generation 0 network-id 1 network-cost 50
a=candidate:2617212910 1 tcp 1518280447 192.168.0.1 59673 typ host tcptype passive generation 0 network-id 1 network-cost 50
a=candidate:2082671819 1 udp 1686052607 1.2.3.4 54653 typ srflx raddr 192.168.0.1 rport 54653 generation 0 network-id 1 network-cost 50
a=ice-ufrag:IBdf
a=ice-pwd:G3lTrrC9gmhQx481AowtkhYz
a=fingerprint:sha-256 53:F8:84:D9:3C:1F:A0:44:AA:D6:3C:65:80:D3:CB:6F:23:90:17:41:06:F9:9C:10:D8:48:4A:A8:B6:FA:14:A1
a=setup:actpass
a=mid:data
a=sctpmap:5000 webrtc-datachannel 1024
"""
# coffeelint: enable
expected: '1.2.3.4'
,
# Improper character within IPv4
sdp: """
c=IN IP4 224.2z.1.1
"""
expected: undefined
,
# Improper character within IPv6
sdp: """
c=IN IP6 ff15:g::101
"""
expected: undefined
,
# Bogus "IP7" addrtype
sdp: "c=IN IP7 1.2.3.4\n"
expected: undefined
]
it 'parses SDP', ->
for test in testCases
# https://tools.ietf.org/html/rfc4566#section-5: "The sequence # CRLF
# (0x0d0a) is used to end a record, although parsers SHOULD be tolerant
# and also accept records terminated with a single newline character."
# We represent the test cases with LF line endings for convenience, and
# test them both that way and with CRLF line endings.
expect(Parse.ipFromSDP(test.sdp)?.toLowerCase()).toEqual(test.expected)
expect(
Parse.ipFromSDP(test.sdp.replace(/\n/, "\r\n"))?.toLowerCase()
).toEqual(test.expected)
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').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').toBe 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()

254
proxy/spec/util.spec.js Normal file
View file

@ -0,0 +1,254 @@
// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake utils
*/
describe('Parse', function() {
describe('cookie', function() {
return it('parses correctly', function() {
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: '& '
});
return expect(Parse.cookie('a=\'\'')).toEqual({
a: '\'\''
});
});
});
describe('address', function() {
it('parses IPv4', function() {
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();
return expect(Parse.address('3.3.3.3:65536')).toBeNull();
});
return it('parses IPv6', function() {
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();
return expect(Parse.address('[1:2::ffff:1.2.3.4]:4444')).toEqual({
host: '1:2::ffff:1.2.3.4',
port: 4444
});
});
});
return describe('ipFromSDP', function() {
var testCases;
testCases = [
{
// https://tools.ietf.org/html/rfc4566#section-5
sdp: "v=0\no=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\ns=SDP Seminar\ni=A Seminar on the session description protocol\nu=http://www.example.com/seminars/sdp.pdf\ne=j.doe@example.com (Jane Doe)\nc=IN IP4 224.2.17.12/127\nt=2873397496 2873404696\na=recvonly\nm=audio 49170 RTP/AVP 0\nm=video 51372 RTP/AVP 99\na=rtpmap:99 h263-1998/90000",
expected: '224.2.17.12'
},
{
// Missing c= line
sdp: "v=0\no=jdoe 2890844526 2890842807 IN IP4 10.47.16.5\ns=SDP Seminar\ni=A Seminar on the session description protocol\nu=http://www.example.com/seminars/sdp.pdf\ne=j.doe@example.com (Jane Doe)\nt=2873397496 2873404696\na=recvonly\nm=audio 49170 RTP/AVP 0\nm=video 51372 RTP/AVP 99\na=rtpmap:99 h263-1998/90000",
expected: void 0
},
{
// Single line, IP address only
sdp: "c=IN IP4 224.2.1.1\n",
expected: '224.2.1.1'
},
{
// Same, with TTL
sdp: "c=IN IP4 224.2.1.1/127\n",
expected: '224.2.1.1'
},
{
// Same, with TTL and multicast addresses
sdp: "c=IN IP4 224.2.1.1/127/3\n",
expected: '224.2.1.1'
},
{
// IPv6, address only
sdp: "c=IN IP6 FF15::101\n",
expected: 'ff15::101'
},
{
// Same, with multicast addresses
sdp: "c=IN IP6 FF15::101/3\n",
expected: 'ff15::101'
},
{
// Multiple c= lines
sdp: "c=IN IP4 1.2.3.4\nc=IN IP4 5.6.7.8",
expected: '1.2.3.4'
},
{
// Modified from SDP sent by snowflake-client.
// coffeelint: disable
sdp: "v=0\no=- 7860378660295630295 2 IN IP4 127.0.0.1\ns=-\nt=0 0\na=group:BUNDLE data\na=msid-semantic: WMS\nm=application 54653 DTLS/SCTP 5000\nc=IN IP4 1.2.3.4\na=candidate:3581707038 1 udp 2122260223 192.168.0.1 54653 typ host generation 0 network-id 1 network-cost 50\na=candidate:2617212910 1 tcp 1518280447 192.168.0.1 59673 typ host tcptype passive generation 0 network-id 1 network-cost 50\na=candidate:2082671819 1 udp 1686052607 1.2.3.4 54653 typ srflx raddr 192.168.0.1 rport 54653 generation 0 network-id 1 network-cost 50\na=ice-ufrag:IBdf\na=ice-pwd:G3lTrrC9gmhQx481AowtkhYz\na=fingerprint:sha-256 53:F8:84:D9:3C:1F:A0:44:AA:D6:3C:65:80:D3:CB:6F:23:90:17:41:06:F9:9C:10:D8:48:4A:A8:B6:FA:14:A1\na=setup:actpass\na=mid:data\na=sctpmap:5000 webrtc-datachannel 1024",
// coffeelint: enable
expected: '1.2.3.4'
},
{
// Improper character within IPv4
sdp: "c=IN IP4 224.2z.1.1",
expected: void 0
},
{
// Improper character within IPv6
sdp: "c=IN IP6 ff15:g::101",
expected: void 0
},
{
// Bogus "IP7" addrtype
sdp: "c=IN IP7 1.2.3.4\n",
expected: void 0
}
];
return it('parses SDP', function() {
var i, len, ref, ref1, results, test;
results = [];
for (i = 0, len = testCases.length; i < len; i++) {
test = testCases[i];
// https://tools.ietf.org/html/rfc4566#section-5: "The sequence # CRLF
// (0x0d0a) is used to end a record, although parsers SHOULD be tolerant
// and also accept records terminated with a single newline character."
// We represent the test cases with LF line endings for convenience, and
// test them both that way and with CRLF line endings.
expect((ref = Parse.ipFromSDP(test.sdp)) != null ? ref.toLowerCase() : void 0).toEqual(test.expected);
results.push(expect((ref1 = Parse.ipFromSDP(test.sdp.replace(/\n/, "\r\n"))) != null ? ref1.toLowerCase() : void 0).toEqual(test.expected));
}
return results;
});
});
});
describe('query string', function() {
it('should parse correctly', function() {
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'
});
return expect(Query.parse('a=b+c+d')).toEqual({
a: 'b c d'
});
});
return it('uses the first appearance of duplicate key', function() {
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',
'': ''
});
return expect(Query.parse('a=b&&c=d')).toEqual({
a: 'b',
'': '',
c: 'd'
});
});
});
describe('Params', function() {
describe('bool', function() {
var getBool;
getBool = function(query) {
return Params.getBool(Query.parse(query), 'param', false);
};
return it('parses correctly', function() {
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();
return expect(getBool('pram=true')).toBe(false);
});
});
return describe('address', function() {
var DEFAULT, getAddress;
DEFAULT = {
host: '1.1.1.1',
port: 2222
};
getAddress = function(query) {
return Params.getAddress(query, 'addr', DEFAULT);
};
return it('parses correctly', function() {
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);
return expect(getAddress({
addr: '---'
})).toBeNull();
});
});
});

View file

@ -1,39 +0,0 @@
###
jasmine tests for Snowflake websocket
###
describe 'BuildUrl', ->
it 'should parse just protocol and host', ->
expect(WS.buildUrl('http', 'example.com')).toBe 'http://example.com'
it 'should handle different ports', ->
expect WS.buildUrl 'http', 'example.com', 80
.toBe 'http://example.com'
expect WS.buildUrl 'http', 'example.com', 81
.toBe 'http://example.com:81'
expect WS.buildUrl 'http', 'example.com', 443
.toBe 'http://example.com:443'
expect WS.buildUrl 'http', 'example.com', 444
.toBe 'http://example.com:444'
it 'should handle paths', ->
expect WS.buildUrl 'http', 'example.com', 80, '/'
.toBe 'http://example.com/'
expect WS.buildUrl 'http', 'example.com', 80,'/test?k=%#v'
.toBe 'http://example.com/test%3Fk%3D%25%23v'
expect WS.buildUrl 'http', 'example.com', 80, '/test'
.toBe 'http://example.com/test'
it 'should handle params', ->
expect WS.buildUrl 'http', 'example.com', 80, '/test', [['k', '%#v']]
.toBe 'http://example.com/test?k=%25%23v'
expect(WS.buildUrl(
'http', 'example.com', 80, '/test', [['a', 'b'], ['c', 'd']]
)).toBe 'http://example.com/test?a=b&c=d'
it 'should handle ips', ->
expect WS.buildUrl 'http', '1.2.3.4'
.toBe 'http://1.2.3.4'
expect WS.buildUrl 'http', '1:2::3:4'
.toBe 'http://[1:2::3:4]'
it 'should handle bogus', ->
expect WS.buildUrl 'http', 'bog][us'
.toBe 'http://bog%5D%5Bus'
expect WS.buildUrl 'http', 'bog:u]s'
.toBe 'http://bog%3Au%5Ds'

View file

@ -0,0 +1,32 @@
// Generated by CoffeeScript 2.4.1
/*
jasmine tests for Snowflake websocket
*/
describe('BuildUrl', function() {
it('should parse just protocol and host', function() {
return expect(WS.buildUrl('http', 'example.com')).toBe('http://example.com');
});
it('should handle different ports', function() {
expect(WS.buildUrl('http', 'example.com', 80)).toBe('http://example.com');
expect(WS.buildUrl('http', 'example.com', 81)).toBe('http://example.com:81');
expect(WS.buildUrl('http', 'example.com', 443)).toBe('http://example.com:443');
return expect(WS.buildUrl('http', 'example.com', 444)).toBe('http://example.com:444');
});
it('should handle paths', function() {
expect(WS.buildUrl('http', 'example.com', 80, '/')).toBe('http://example.com/');
expect(WS.buildUrl('http', 'example.com', 80, '/test?k=%#v')).toBe('http://example.com/test%3Fk%3D%25%23v');
return expect(WS.buildUrl('http', 'example.com', 80, '/test')).toBe('http://example.com/test');
});
it('should handle params', function() {
expect(WS.buildUrl('http', 'example.com', 80, '/test', [['k', '%#v']])).toBe('http://example.com/test?k=%25%23v');
return expect(WS.buildUrl('http', 'example.com', 80, '/test', [['a', 'b'], ['c', 'd']])).toBe('http://example.com/test?a=b&c=d');
});
it('should handle ips', function() {
expect(WS.buildUrl('http', '1.2.3.4')).toBe('http://1.2.3.4');
return expect(WS.buildUrl('http', '1:2::3:4')).toBe('http://[1:2::3:4]');
});
return it('should handle bogus', function() {
expect(WS.buildUrl('http', 'bog][us')).toBe('http://bog%5D%5Bus');
return expect(WS.buildUrl('http', 'bog:u]s')).toBe('http://bog%3Au%5Ds');
});
});