[snowflake/master] Complete broker spec cases

commit 4f18340c163c18d4bcad249b4e4976d3106cd014 Author: Serene Han <keroserene+git@gmail.com> Date: Wed Feb 10 13:05:21 2016 -0800 Complete broker spec cases --- proxy/broker.coffee | 67 +++++++++++++++--------------- proxy/spec/broker.spec.coffee | 94 +++++++++++++++++++++++++++++++------------ 2 files changed, 102 insertions(+), 59 deletions(-) diff --git a/proxy/broker.coffee b/proxy/broker.coffee index 71fe6eb..e989d57 100644 --- a/proxy/broker.coffee +++ b/proxy/broker.coffee @@ -9,6 +9,9 @@ STATUS_OK = 200 STATUS_GONE = 410 STATUS_GATEWAY_TIMEOUT = 504 +MESSAGE_TIMEOUT = 'Timed out waiting for a client offer.' +MESSAGE_UNEXPECTED = 'Unexpected status.' + genSnowflakeID = -> Math.random().toString(36).substring(2) @@ -17,7 +20,6 @@ class Broker clients: 0 id: null - request: null # 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 @@ -29,53 +31,35 @@ class Broker @url = 'https://' + @url if 0 != @url.indexOf('https://', 0) @url += '/' if '/' != @url.substr -1 - # Snowflake registers with the broker using an HTTP POST request, and expects - # a response from the broker containing some client offer. + # Promises some client SDP 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. getClientOffer: => new Promise (fulfill, reject) => xhr = new XMLHttpRequest() - @request = xhr - @fulfill = fulfill - # @request.onreadystatechange = @processOffer - xhr.onreadystatechange = => + xhr.onreadystatechange = -> return if xhr.DONE != xhr.readyState switch xhr.status when STATUS_OK fulfill xhr.responseText # Should contain offer. when STATUS_GATEWAY_TIMEOUT - reject 'Timed out waiting for a client to serve.' + reject MESSAGE_TIMEOUT else log 'Broker ERROR: Unexpected ' + xhr.status + ' - ' + xhr.statusText - Status.set ' failure. Please refresh.' - @sendRequest() - - sendRequest: => - 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 + snowflake.ui.setStatus ' failure. Please refresh.' + reject MESSAGE_UNEXPECTED + @_xhr = xhr # Used by spec to fake async Broker interaction + @_postRequest xhr, 'proxy', @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) -> dbg @id + ' - Sending answer back to broker...\n' dbg answer.sdp 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 = -> return if xhr.DONE != xhr.readyState switch xhr.status @@ -87,5 +71,22 @@ class Broker else dbg 'Broker ERROR: Unexpected ' + xhr.status + ' - ' + xhr.statusText - Status.set ' failure. Please refresh.' - xhr.send JSON.stringify(answer) + snowflake.ui.setStatus ' failure. Please refresh.' + @_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 diff --git a/proxy/spec/broker.spec.coffee b/proxy/spec/broker.spec.coffee index 3b47cd3..db936c1 100644 --- a/proxy/spec/broker.spec.coffee +++ b/proxy/spec/broker.spec.coffee @@ -19,32 +19,74 @@ describe 'Broker', -> expect(b.url).toEqual 'https://fake/' expect(b.id).not.toBeNull() - it 'polls and promises a client offer', (done) -> - b = new Broker 'fake' - # fake successful request - spyOn(b, 'sendRequest').and.callFake -> - b.request.readyState = b.request.DONE - b.request.status = STATUS_OK - b.request.responseText = 'test' - b.request.onreadystatechange() - poll = b.getClientOffer() - expect(poll).not.toBeNull() - poll.then (desc) => - expect(desc).toEqual 'test' - done() - - it 'requests correctly', -> - b = new Broker 'fake' - b.request = new XMLHttpRequest() - spyOn(b.request, 'open') - spyOn(b.request, 'setRequestHeader') - spyOn(b.request, 'send') - b.sendRequest() - expect(b.request.open).toHaveBeenCalled() - expect(b.request.setRequestHeader).toHaveBeenCalled() - expect(b.request.send).toHaveBeenCalled() + 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 = 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 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 = 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 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', -> - # TODO: fix 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()
participants (1)
-
serene@torproject.org