Skip to content

Commit

Permalink
fix api tests - baseline working with 0 retries
Browse files Browse the repository at this point in the history
  • Loading branch information
m5r committed Oct 25, 2023
1 parent 6985575 commit 766ae6d
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 41 deletions.
4 changes: 0 additions & 4 deletions src/lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,8 @@ const cache = new Map();
const _request = (method) => (...args) => retry(() => rpn[method](...args), { retries: 0 });
const request = {
get: _request('get'),
head: _request('head'),
options: _request('options'),
post: _request('post'),
put: _request('put'),
patch: _request('patch'),
delete: _request('delete'),
};

const logDeprecatedTransitions = (settings) => {
Expand Down
78 changes: 41 additions & 37 deletions test/lib/api.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ const log = require('../../src/lib/log');
describe('api', () => {
let mockRequest;
beforeEach(() => {
mockRequest = sinon.stub().resolves();
mockRequest = {
get: sinon.stub().resolves(),
post: sinon.stub().resolves(),
put: sinon.stub().resolves(),
};
api.__set__('request', mockRequest);
sinon.stub(environment, 'apiUrl').get(() => 'http://example.com/db-name');
});
Expand All @@ -21,15 +25,14 @@ describe('api', () => {
it('defaults to live requests', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
await api().version();
expect(mockRequest.callCount).to.eq(1);
expect(mockRequest.get.callCount).to.eq(1);
});

describe('formsValidate', async () => {

it('should fail if validate endpoint returns invalid JSON', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
mockRequest = sinon.stub().resolves('--NOT JSON--');
api.__set__('request', mockRequest);
mockRequest.post.resolves('--NOT JSON--');
try {
await api().formsValidate('<xml></xml>');
assert.fail('Expected assertion');
Expand All @@ -41,28 +44,25 @@ describe('api', () => {

it('should not fail if validate endpoint does not exist', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
mockRequest = sinon.stub().rejects({name: 'StatusCodeError', statusCode: 404});
api.__set__('request', mockRequest);
mockRequest.post.rejects({name: 'StatusCodeError', statusCode: 404});
let result = await api().formsValidate('<xml></xml>');
expect(result).to.deep.eq({ok: true, formsValidateEndpointFound: false});
expect(mockRequest.callCount).to.eq(1);
expect(mockRequest.post.callCount).to.eq(1);
// second call
result = await api().formsValidate('<xml>Another XML</xml>');
expect(result).to.deep.eq({ok: true, formsValidateEndpointFound: false});
expect(mockRequest.callCount).to.eq(1); // still HTTP client called only once
expect(mockRequest.post.callCount).to.eq(1); // still HTTP client called only once
});

it('should not call API when --archive mode and response still ok', async () => {
mockRequest = sinon.spy();
api.__set__('request', mockRequest);
api.__set__('environment', sinon.stub({ isArchiveMode: true }));
let result = await api().formsValidate('<xml></xml>');
expect(result).to.deep.eq({ok: true});
expect(mockRequest.callCount).to.eq(0);
expect(mockRequest.post.callCount).to.eq(0);
// second call
result = await api().formsValidate('<xml>Another XML</xml>');
expect(result).to.deep.eq({ok: true});
expect(mockRequest.callCount).to.eq(0); // still HTTP not called even once
expect(mockRequest.post.callCount).to.eq(0); // still HTTP not called even once
});
});

Expand All @@ -71,7 +71,7 @@ describe('api', () => {

it('does not initiate requests to api', async () => {
await api().version();
expect(mockRequest.callCount).to.eq(0);
expect(mockRequest.get.callCount).to.eq(0);
});

it('throws not supported for undefined interfaces', () => {
Expand All @@ -83,38 +83,42 @@ describe('api', () => {

it('changes settings on server', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
mockRequest.onCall(0).resolves([]);
mockRequest.onCall(1).resolves({ ok: true });
// GET /api/v1/settings/deprecated-transitions from logDeprecatedTransitions()
mockRequest.get.onCall(0).resolves([]);
// PUT /_design/medic/_rewrite/update_settings/medic?replace=1 from updateAppSettings()
mockRequest.put.onCall(0).resolves({ ok: true });
const response = await api().updateAppSettings(JSON.stringify({
transitions: [ 'test' ]
}));
expect(response.ok).to.equal(true);
expect(mockRequest.callCount).to.equal(2);
expect(mockRequest.args[1][0].body).to.equal('{"transitions":["test"]}');
expect(mockRequest.get.callCount).to.equal(1);
expect(mockRequest.put.callCount).to.equal(1);
expect(mockRequest.put.args[0][0].body).to.equal('{"transitions":["test"]}');
});

it('throws error when server throws', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
mockRequest.onCall(0).resolves([]);
mockRequest.onCall(1).rejects({ error: 'random' });
mockRequest.get.onCall(0).resolves([]);
mockRequest.put.onCall(0).resolves({ ok: true });
try {
await api().updateAppSettings(JSON.stringify({}));
} catch(err) {
expect(err.error).to.equal('random');
expect(mockRequest.callCount).to.equal(1);
expect(mockRequest.get.callCount).to.equal(0);
expect(mockRequest.put.callCount).to.equal(1);
}
});

it('logs and continues when using deprecated transitions', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
sinon.stub(log, 'warn');
mockRequest.onCall(0).resolves([ {
mockRequest.get.onCall(0).resolves([ {
name: 'go',
deprecated: true,
deprecatedIn: '3.10.0',
deprecationMessage: 'Use go2 instead'
} ]);
mockRequest.onCall(1).resolves({ ok: true });
mockRequest.put.onCall(0).resolves({ ok: true });
await api().updateAppSettings(JSON.stringify({
transitions: { go: { disable: false } }
}));
Expand All @@ -125,8 +129,8 @@ describe('api', () => {
it('continues when deprecated transitions call throws', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
sinon.stub(log, 'warn');
mockRequest.onCall(0).rejects({ statusCode: 500, message: 'some error' });
mockRequest.onCall(1).resolves({ ok: true });
mockRequest.get.onCall(0).rejects({ statusCode: 500, message: 'some error' });
mockRequest.put.onCall(0).resolves({ ok: true });
await api().updateAppSettings(JSON.stringify({
transitions: [ 'test' ]
}));
Expand All @@ -139,59 +143,59 @@ describe('api', () => {
it('call the API and parse types from string correctly', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
sinon.stub(environment, 'force').get(() => false);
mockRequest.resolves({'compressible_types':'text/*, application/*', 'compression_level':'8'});
mockRequest.get.resolves({'compressible_types':'text/*, application/*', 'compression_level':'8'});
const cacheSpy = new Map();
const cacheGetSpy = sinon.spy(cacheSpy, 'get');
api.__set__('cache', cacheSpy);
let compressibleTypes = await api().getCompressibleTypes();
expect(compressibleTypes).to.deep.eq(['text/*', 'application/*']);
assert.equal(mockRequest.callCount, 1);
assert.equal(mockRequest.get.callCount, 1);
assert.equal(cacheGetSpy.callCount, 0);

// second time the cache is used
compressibleTypes = await api().getCompressibleTypes();
expect(compressibleTypes).to.deep.eq(['text/*', 'application/*']); // same values from cache
assert.equal(mockRequest.callCount, 1); // still 1 request
assert.equal(mockRequest.get.callCount, 1); // still 1 request
assert.equal(cacheGetSpy.callCount, 1);
});

it('returns empty if API returns 404', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
sinon.stub(environment, 'force').get(() => false);
mockRequest.rejects({statusCode:404});
mockRequest.get.rejects({statusCode:404});
const cacheSpy = new Map();
const cacheGetSpy = sinon.spy(cacheSpy, 'get');
api.__set__('cache', cacheSpy);
let compressibleTypes = await api().getCompressibleTypes();
expect(compressibleTypes).to.deep.eq([]);
assert.equal(mockRequest.callCount, 1);
assert.equal(mockRequest.get.callCount, 1);
assert.equal(cacheGetSpy.callCount, 0);

// second time the cache is used
compressibleTypes = await api().getCompressibleTypes();
expect(compressibleTypes).to.deep.eq([]); // same values from cache
assert.equal(mockRequest.callCount, 1); // still 1 request
assert.equal(mockRequest.get.callCount, 1); // still 1 request
assert.equal(cacheGetSpy.callCount, 1);
});

it('returns empty if API returns error and without caching result', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
sinon.stub(environment, 'force').get(() => false);
const getReqStub = mockRequest;
const getReqStub = mockRequest.get;
getReqStub.onCall(0).rejects('The error');
getReqStub.onCall(1).resolves({'compressible_types':'text/*, application/*', 'compression_level':'8'});
const cacheSpy = new Map();
const cacheGetSpy = sinon.spy(cacheSpy, 'get');
api.__set__('cache', cacheSpy);
let compressibleTypes = await api().getCompressibleTypes();
expect(compressibleTypes).to.deep.eq([]);
assert.equal(mockRequest.callCount, 1);
assert.equal(mockRequest.get.callCount, 1);
assert.equal(cacheGetSpy.callCount, 0);

// second time cache is NOT used and value from API is returned
compressibleTypes = await api().getCompressibleTypes();
expect(compressibleTypes).to.deep.eq(['text/*', 'application/*']); // values from API second call
assert.equal(mockRequest.callCount, 2); // 2 requests total
assert.equal(mockRequest.get.callCount, 2); // 2 requests total
assert.equal(cacheGetSpy.callCount, 0); // cache not used
});
});
Expand All @@ -202,7 +206,7 @@ describe('api', () => {

async function testAvailableError(response, expected) {
sinon.stub(environment, 'isArchiveMode').get(() => false);
mockRequest.rejects(response);
mockRequest.get.rejects(response);
try {
await api().available();
assert.fail('Expected error to be thrown');
Expand All @@ -213,7 +217,7 @@ describe('api', () => {

it('should not throw if no error found in request', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => false);
sinon.stub(mockRequest).resolves('okey dokey');
mockRequest.get.resolves('okey dokey');
await api().available();
});

Expand Down Expand Up @@ -251,9 +255,9 @@ describe('api', () => {

it('should return if archive mode is enabled even when api is not available', async () => {
sinon.stub(environment, 'isArchiveMode').get(() => true);
sinon.stub(mockRequest).rejects('Ups');
mockRequest.get.rejects('Ups');
await api().available();
expect(mockRequest.callCount).to.eq(0); // api is not called
expect(mockRequest.get.callCount).to.eq(0); // api is not called
});
});
});

0 comments on commit 766ae6d

Please sign in to comment.