Skip to content

Commit

Permalink
adds timeouts based on #20, with unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
m-mcgowan committed May 16, 2017
1 parent a22810a commit 84519f3
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 10 deletions.
21 changes: 16 additions & 5 deletions src/Agent.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,18 @@ export default class Agent {
* @param {String} query Query parameters
* @param {Object} form Form fields
* @param {Object} files array of file names and file content
* @parma {Object} context the invocation context, describing the tool and project.
* @parma {Object} context the invocation context, describing the tool and project. A timeout for the request
* in milliseconds may be optionally specified. When not specified, the request does not timeout.
* @return {Promise} A promise. fulfilled with {body, statusCode}, rejected with { statusCode, errorDescription, error, body }
*/
request({ uri, method, data = undefined, auth, query = undefined, form = undefined, files = undefined, context = undefined }) {
const requestFiles = this._sanitizeFiles(files);
return this._request({ uri, method, data, auth, query, form, context, files: requestFiles });
const timeout = context && context.timeout;
if (timeout) {
context = Object.assign({}, context);
delete context['timeout'];
}
return this._request({ uri, method, data, auth, query, form, timeout, context, files: requestFiles });
}

/**
Expand All @@ -75,11 +81,13 @@ export default class Agent {
* @param {String} query Query parameters
* @param {Object} form Form fields
* @param {Object} files array of file names and file content
* @param {Number} timeout the number of milliseconds of no response after which the request should timeout.
* When undefined, the request is not timed out.
* @param {Object} context the invocation context
* @return {Promise} A promise. fulfilled with {body, statusCode}, rejected with { statusCode, errorDescription, error, body }
*/
_request({ uri, method, data, auth, query, form, files, context }) {
const req = this._buildRequest({ uri, method, data, auth, query, form, context, files });
_request({ uri, method, data, auth, query, form, files, timeout, context }) {
const req = this._buildRequest({ uri, method, data, auth, query, form, timeout, context, files });
return this._promiseResponse(req);
}

Expand Down Expand Up @@ -125,7 +133,7 @@ export default class Agent {
});
}

_buildRequest({ uri, method, data, auth, query, form, files, context, makerequest=request }) {
_buildRequest({ uri, method, data, auth, query, form, files, timeout, context, makerequest=request }) {
const req = makerequest(method, uri);
if (this.prefix) {
req.use(this.prefix);
Expand All @@ -137,6 +145,9 @@ export default class Agent {
if (query) {
req.query(query);
}
if (timeout!==undefined) {
req.timeout(timeout);
}
if (files) {
for (let [name, file] of Object.entries(files)) {
req._getFormData().append(name, file.data, {
Expand Down
3 changes: 2 additions & 1 deletion src/Defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ export default {
baseUrl: 'https://api.particle.io',
clientSecret: 'particle-api',
clientId: 'particle-api',
tokenDuration: 7776000 // 90 days
tokenDuration: 7776000, // 90 days
timeout: 60000
};
39 changes: 35 additions & 4 deletions test/Agent.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ describe('Agent', () => {
expect(sut._applyContext).to.not.be.called;
});


it('should invoke authorize with the request and auth', () => {
const sut = new Agent();
sut.prefix = undefined;
Expand Down Expand Up @@ -243,6 +242,25 @@ describe('Agent', () => {
expect(field).to.be.calledWith('form1', 'value1');
expect(field).to.be.calledWith('form2', 'value2');
});

it('sets the timeout on the request when defined', () => {
const sut = new Agent();
sut.prefix = undefined;
const req = { timeout: sinon.stub() };
const makerequest = sinon.stub().returns(req);
sut._buildRequest({timeout: 123, makerequest});
expect(req.timeout).calledOnce.calledWith(123);
});

it('does not set the timeout on the request when not defined', () => {
const sut = new Agent();
sut.prefix = undefined;
const req = { timeout: sinon.stub() };
const makerequest = sinon.stub().returns(req);
sut._buildRequest({makerequest});
expect(req.timeout).not.called;
});

});

it('sanitizes files from a request', () => {
Expand All @@ -258,7 +276,19 @@ describe('Agent', () => {
expect(result).to.be.equal('request_result');
expect(sut._sanitizeFiles).calledOnce.calledWith(sinon.match.same(files));
expect(sut._request).calledOnce.calledWith({uri: 'abc', auth: undefined, method: 'post', data: '123', query: 'all', form:form,
files:sanitizedFiles, context: undefined});
files:sanitizedFiles, timeout: undefined, context: undefined});
});

describe('timeout', () => {
it('sets the timeout from the context', () => {
const sut = new Agent();
sut._request = sinon.stub();
const context = { timeout: 123, foo: 'bar' };
sut.request({context});
expect(sut._request).calledOnce.calledWith({uri: undefined, method: undefined,
auth: undefined, data: undefined, files: undefined, form: undefined, query: undefined, timeout: 123,
context: { foo: 'bar' } });
});
});

it('uses default arguments for request', () => {
Expand All @@ -269,20 +299,21 @@ describe('Agent', () => {
const result = sut.request({uri: 'abc', method:'post'});
expect(result).to.equal('123');
expect(sut._request).calledOnce.calledWith({uri: 'abc', method:'post',
auth: undefined, data: undefined, files: undefined, form: undefined, query: undefined, context: undefined });
auth: undefined, data: undefined, files: undefined, form: undefined, query: undefined, timeout: undefined, context: undefined });
});

it('builds and sends the request', () => {
const sut = new Agent();
const buildRequest = sinon.stub();
const promiseResponse = sinon.stub();
const context = {};
sut._buildRequest = buildRequest;
sut._promiseResponse = promiseResponse;
buildRequest.returns('arequest');
promiseResponse.returns('promise');

const requestArgs = {uri:'uri', method:'method', data:'data', auth:'auth', query: 'query',
form: 'form', files: 'files', context};
form: 'form', files: 'files', timeout: undefined, context};
const result = sut._request(requestArgs);
expect(result).to.be.equal('promise');
expect(buildRequest).calledWith(requestArgs);
Expand Down

0 comments on commit 84519f3

Please sign in to comment.