Complete broker spec cases

This commit is contained in:
Serene Han 2016-02-10 13:05:21 -08:00
parent bb9eb721e2
commit 4f18340c16
2 changed files with 101 additions and 58 deletions

View file

@ -9,6 +9,9 @@ STATUS_OK = 200
STATUS_GONE = 410 STATUS_GONE = 410
STATUS_GATEWAY_TIMEOUT = 504 STATUS_GATEWAY_TIMEOUT = 504
MESSAGE_TIMEOUT = 'Timed out waiting for a client offer.'
MESSAGE_UNEXPECTED = 'Unexpected status.'
genSnowflakeID = -> genSnowflakeID = ->
Math.random().toString(36).substring(2) Math.random().toString(36).substring(2)
@ -17,7 +20,6 @@ class Broker
clients: 0 clients: 0
id: null id: null
request: null
# When interacting with the Broker, snowflake must generate a unique session # When interacting with the Broker, snowflake must generate a unique session
# ID so the Broker can keep track of which signalling channel it's speaking # ID so the Broker can keep track of which signalling channel it's speaking
@ -29,53 +31,35 @@ class Broker
@url = 'https://' + @url if 0 != @url.indexOf('https://', 0) @url = 'https://' + @url if 0 != @url.indexOf('https://', 0)
@url += '/' if '/' != @url.substr -1 @url += '/' if '/' != @url.substr -1
# Snowflake registers with the broker using an HTTP POST request, and expects # Promises some client SDP Offer.
# a response from the broker containing some client offer. # Registers this Snowfalke with the broker using an HTTP POST request, and
# waits for a response containing some client offer that the Broker chooses
# for this proxy..
# TODO: Actually support multiple clients. # TODO: Actually support multiple clients.
getClientOffer: => getClientOffer: =>
new Promise (fulfill, reject) => new Promise (fulfill, reject) =>
xhr = new XMLHttpRequest() xhr = new XMLHttpRequest()
@request = xhr xhr.onreadystatechange = ->
@fulfill = fulfill
# @request.onreadystatechange = @processOffer
xhr.onreadystatechange = =>
return if xhr.DONE != xhr.readyState return if xhr.DONE != xhr.readyState
switch xhr.status switch xhr.status
when STATUS_OK when STATUS_OK
fulfill xhr.responseText # Should contain offer. fulfill xhr.responseText # Should contain offer.
when STATUS_GATEWAY_TIMEOUT when STATUS_GATEWAY_TIMEOUT
reject 'Timed out waiting for a client to serve.' reject MESSAGE_TIMEOUT
else else
log 'Broker ERROR: Unexpected ' + xhr.status + log 'Broker ERROR: Unexpected ' + xhr.status +
' - ' + xhr.statusText ' - ' + xhr.statusText
Status.set ' failure. Please refresh.' snowflake.ui.setStatus ' failure. Please refresh.'
@sendRequest() reject MESSAGE_UNEXPECTED
@_xhr = xhr # Used by spec to fake async Broker interaction
sendRequest: => @_postRequest xhr, 'proxy', @id
try
@request.open 'POST', @url + 'proxy'
@request.setRequestHeader('X-Session-ID', @id)
catch err
###
An exception happens here when, for example, NoScript allows the domain
on which the proxy badge runs, but not the domain to which it's trying
to make the HTTP request. The exception message is like "Component
returned failure code: 0x805e0006 [nsIXMLHttpRequest.open]" on Firefox.
###
log 'Broker: exception while connecting: ' + err.message
return
@request.send @id
# Assumes getClientOffer happened, and a WebRTC SDP answer has been generated.
# Sends it back to the broker, which passes it to back to the original client.
sendAnswer: (answer) -> sendAnswer: (answer) ->
dbg @id + ' - Sending answer back to broker...\n' dbg @id + ' - Sending answer back to broker...\n'
dbg answer.sdp dbg answer.sdp
xhr = new XMLHttpRequest() xhr = new XMLHttpRequest()
try
xhr.open 'POST', @url + 'answer'
xhr.setRequestHeader('X-Session-ID', @id)
catch err
log 'Broker: exception while connecting: ' + err.message
return
xhr.onreadystatechange = -> xhr.onreadystatechange = ->
return if xhr.DONE != xhr.readyState return if xhr.DONE != xhr.readyState
switch xhr.status switch xhr.status
@ -87,5 +71,22 @@ class Broker
else else
dbg 'Broker ERROR: Unexpected ' + xhr.status + dbg 'Broker ERROR: Unexpected ' + xhr.status +
' - ' + xhr.statusText ' - ' + xhr.statusText
Status.set ' failure. Please refresh.' snowflake.ui.setStatus ' failure. Please refresh.'
xhr.send JSON.stringify(answer) @_postRequest xhr, 'answer', JSON.stringify(answer)
# urlSuffix for the broker is different depending on what action
# is desired.
_postRequest: (xhr, urlSuffix, payload) =>
try
xhr.open 'POST', @url + urlSuffix
xhr.setRequestHeader('X-Session-ID', @id)
catch err
###
An exception happens here when, for example, NoScript allows the domain
on which the proxy badge runs, but not the domain to which it's trying
to make the HTTP xhr. The exception message is like "Component
returned failure code: 0x805e0006 [nsIXMLHttpRequest.open]" on Firefox.
###
log 'Broker: exception while connecting: ' + err.message
return
xhr.send payload

View file

@ -19,32 +19,74 @@ describe 'Broker', ->
expect(b.url).toEqual 'https://fake/' expect(b.url).toEqual 'https://fake/'
expect(b.id).not.toBeNull() expect(b.id).not.toBeNull()
it 'polls and promises a client offer', (done) -> describe 'getClientOffer', ->
b = new Broker 'fake' it 'polls and promises a client offer', (done) ->
# fake successful request b = new Broker 'fake'
spyOn(b, 'sendRequest').and.callFake -> # fake successful request and response from broker.
b.request.readyState = b.request.DONE spyOn(b, '_postRequest').and.callFake ->
b.request.status = STATUS_OK b._xhr.readyState = b._xhr.DONE
b.request.responseText = 'test' b._xhr.status = STATUS_OK
b.request.onreadystatechange() b._xhr.responseText = 'fake offer'
poll = b.getClientOffer() b._xhr.onreadystatechange()
expect(poll).not.toBeNull() poll = b.getClientOffer()
poll.then (desc) => expect(poll).not.toBeNull()
expect(desc).toEqual 'test' expect(b._postRequest).toHaveBeenCalled()
done() poll.then (desc) ->
expect(desc).toEqual 'fake offer'
done()
.catch ->
fail 'should not reject on STATUS_OK'
done()
it 'requests correctly', -> it 'rejects if the broker timed-out', (done) ->
b = new Broker 'fake' b = new Broker 'fake'
b.request = new XMLHttpRequest() # fake timed-out request from broker
spyOn(b.request, 'open') spyOn(b, '_postRequest').and.callFake ->
spyOn(b.request, 'setRequestHeader') b._xhr.readyState = b._xhr.DONE
spyOn(b.request, 'send') b._xhr.status = STATUS_GATEWAY_TIMEOUT
b.sendRequest() b._xhr.onreadystatechange()
expect(b.request.open).toHaveBeenCalled() poll = b.getClientOffer()
expect(b.request.setRequestHeader).toHaveBeenCalled() expect(poll).not.toBeNull()
expect(b.request.send).toHaveBeenCalled() expect(b._postRequest).toHaveBeenCalled()
poll.then (desc) ->
fail 'should not fulfill on GATEWAY_TIMEOUT'
done()
, (err) ->
expect(err).toBe 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 MESSAGE_UNEXPECTED
expect(b._xhr.status).toBe 1337
done()
it 'responds to the broker with answer', -> it 'responds to the broker with answer', ->
# TODO: fix
b = new Broker 'fake' b = new Broker 'fake'
b.sendAnswer 'foo' spyOn(b, '_postRequest')
b.sendAnswer 123
expect(b._postRequest).toHaveBeenCalledWith(
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 b._xhr, 'test', 'data'
expect(b._xhr.open).toHaveBeenCalled()
expect(b._xhr.setRequestHeader).toHaveBeenCalled()
expect(b._xhr.send).toHaveBeenCalled()