Skip to content

Commit

Permalink
perf(openapi): upload improvements (#518)
Browse files Browse the repository at this point in the history
* chore(deps): install ora

* chore: add ora to dependabot and reformat

* feat: add spinner for file validation

* feat: initial registry upload function

* refactor: move ora opts into shared function

* refactor: use shared ora opts in new function also

* feat: first pass at rewriting openapi command to support new flow

- also i realphabetized the imports

* chore: making the spinners spin

* test: refactor existing tests to work with new flow

* test: add coverage for if registry endpoint fails

* chore: test coverage in ora opts

* chore: spinner language
  • Loading branch information
kanadgupta authored Jun 23, 2022
1 parent 6dc896c commit e1aeac0
Show file tree
Hide file tree
Showing 8 changed files with 551 additions and 56 deletions.
14 changes: 8 additions & 6 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: 2
updates:
- package-ecosystem: github-actions
directory: "/"
directory: '/'
schedule:
interval: monthly
reviewers:
Expand All @@ -13,7 +13,7 @@ updates:
prefix-development: chore(deps-dev)

- package-ecosystem: npm
directory: "/"
directory: '/'
schedule:
interval: monthly
open-pull-requests-limit: 10
Expand All @@ -28,11 +28,13 @@ updates:
# All of these packages are now ESM-only and can't be used here without a rewrite.
- dependency-name: chalk
versions:
- ">= 5"
- '>= 5'
- dependency-name: configstore
versions:
- ">= 6"
- '>= 6'
- dependency-name: node-fetch
versions:
- ">= 3"

- '>= 3'
- dependency-name: ora
versions:
- '>= 6'
104 changes: 87 additions & 17 deletions __tests__/cmds/openapi.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ const getCommandOutput = () => {
return [console.warn.mock.calls.join('\n\n'), console.info.mock.calls.join('\n\n')].filter(Boolean).join('\n\n');
};

const getRandomRegistryId = () => Math.random().toString(36).substring(2);

describe('rdme openapi', () => {
beforeAll(() => nock.disableNetConnect());

Expand All @@ -69,14 +71,18 @@ describe('rdme openapi', () => {
['OpenAPI 3.1', 'json', '3.1', 'OpenAPI'],
['OpenAPI 3.1', 'yaml', '3.1', 'OpenAPI'],
])('should support uploading a %s definition (format: %s)', async (_, format, specVersion, type) => {
const registryUUID = getRandomRegistryId();

const mock = getApiNock()
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(201, { registryUUID, spec: { openapi: specVersion } })
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.get(`/api/v1/version/${version}`)
.basicAuth({ user: key })
.reply(200, { version: '1.0.0' })
.post('/api/v1/api-specification', body => body.match('form-data; name="spec"'))
.post('/api/v1/api-specification', { registryUUID })
.basicAuth({ user: key })
.reply(201, { _id: 1 }, { location: exampleRefLocation });

Expand All @@ -98,17 +104,21 @@ describe('rdme openapi', () => {
it('should discover and upload an API definition if none is provided', async () => {
promptHandler.createOasPrompt.mockResolvedValue({ option: 'create' });

const registryUUID = getRandomRegistryId();

const mock = getApiNock()
.get('/api/v1/version')
.basicAuth({ user: key })
.reply(200, [{ version }])
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(201, { registryUUID, spec: { openapi: '3.0.0' } })
.post('/api/v1/version')
.basicAuth({ user: key })
.reply(200, { from: '1.0.1', version: '1.0.1' })
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.post('/api/v1/api-specification', body => body.match('form-data; name="spec"'))
.post('/api/v1/api-specification', { registryUUID })
.delayConnection(1000)
.basicAuth({ user: key })
.reply(201, { _id: 1 }, { location: exampleRefLocation });
Expand Down Expand Up @@ -139,8 +149,12 @@ describe('rdme openapi', () => {
['OpenAPI 3.1', 'json', '3.1', 'OpenAPI'],
['OpenAPI 3.1', 'yaml', '3.1', 'OpenAPI'],
])('should support updating a %s definition (format: %s)', async (_, format, specVersion, type) => {
const registryUUID = getRandomRegistryId();

const mock = getApiNock()
.put(`/api/v1/api-specification/${id}`, body => body.match('form-data; name="spec"'))
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(201, { registryUUID, spec: { openapi: specVersion } })
.put(`/api/v1/api-specification/${id}`, { registryUUID })
.basicAuth({ user: key })
.reply(201, { _id: 1 }, { location: exampleRefLocation });

Expand All @@ -159,8 +173,12 @@ describe('rdme openapi', () => {
});

it('should return warning if providing `id` and `version`', async () => {
const registryUUID = getRandomRegistryId();

const mock = getApiNock()
.put(`/api/v1/api-specification/${id}`, body => body.match('form-data; name="spec"'))
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(201, { registryUUID, spec: { openapi: '3.0.0' } })
.put(`/api/v1/api-specification/${id}`, { registryUUID })
.basicAuth({ user: key })
.reply(201, { _id: 1 }, { location: exampleRefLocation });

Expand Down Expand Up @@ -217,17 +235,21 @@ describe('rdme openapi', () => {
newVersion: '1.0.1',
});

const registryUUID = getRandomRegistryId();

const mock = getApiNock()
.get('/api/v1/version')
.basicAuth({ user: key })
.reply(200, [{ version: '1.0.0' }])
.post('/api/v1/version')
.basicAuth({ user: key })
.reply(200, { from: '1.0.0', version: '1.0.1' })
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(201, { registryUUID, spec: { openapi: '3.0.0' } })
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.post('/api/v1/api-specification', body => body.match('form-data; name="spec"'))
.post('/api/v1/api-specification', { registryUUID })
.basicAuth({ user: key })
.reply(201, { _id: 1 }, { location: exampleRefLocation });

Expand All @@ -241,19 +263,22 @@ describe('rdme openapi', () => {

it('should bundle and upload the expected content', async () => {
let requestBody = null;
const registryUUID = getRandomRegistryId();
const mock = getApiNock()
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.get(`/api/v1/version/${version}`)
.basicAuth({ user: key })
.reply(200, { version: '1.0.0' })
.post('/api/v1/api-specification', body => {
.post('/api/v1/api-registry', body => {
requestBody = body.substring(body.indexOf('{'), body.lastIndexOf('}') + 1);
requestBody = JSON.parse(requestBody);

return body.match('form-data; name="spec"');
})
.reply(201, { registryUUID, spec: { openapi: '3.0.0' } })
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.post('/api/v1/api-specification', { registryUUID })
.basicAuth({ user: key })
.reply(201, { _id: 1 }, { location: exampleRefLocation });

Expand All @@ -270,19 +295,22 @@ describe('rdme openapi', () => {

it('should use specified working directory and upload the expected content', async () => {
let requestBody = null;
const registryUUID = getRandomRegistryId();
const mock = getApiNock()
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.get(`/api/v1/version/${version}`)
.basicAuth({ user: key })
.reply(200, { version: '1.0.0' })
.post('/api/v1/api-specification', body => {
.post('/api/v1/api-registry', body => {
requestBody = body.substring(body.indexOf('{'), body.lastIndexOf('}') + 1);
requestBody = JSON.parse(requestBody);

return body.match('form-data; name="spec"');
})
.reply(201, { registryUUID, spec: { openapi: '3.0.0' } })
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.post('/api/v1/api-specification', { registryUUID })
.basicAuth({ user: key })
.reply(201, { _id: 1 }, { location: exampleRefLocation });

Expand Down Expand Up @@ -367,14 +395,18 @@ describe('rdme openapi', () => {
help: 'If you need help, email [email protected] and mention log "fake-metrics-uuid".',
};

const registryUUID = getRandomRegistryId();

const mock = getApiNock()
.get(`/api/v1/version/${version}`)
.basicAuth({ user: key })
.reply(200, { version: '1.0.0' })
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(201, { registryUUID, spec: { openapi: '3.0.0' } })
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.post('/api/v1/api-specification', body => body.match('form-data; name="spec"'))
.post('/api/v1/api-specification', { registryUUID })
.delayConnection(1000)
.basicAuth({ user: key })
.reply(500, errorObject);
Expand All @@ -390,6 +422,32 @@ describe('rdme openapi', () => {
return mock.done();
});

it('should throw an error if registry upload fails', async () => {
const errorObject = {
error: 'INTERNAL_ERROR',
message: 'Unknown error (Registry is offline? lol idk)',
suggestion: '...a suggestion to resolve the issue...',
help: 'If you need help, email [email protected] and mention log "fake-metrics-uuid".',
};

const mock = getApiNock()
.get(`/api/v1/version/${version}`)
.basicAuth({ user: key })
.reply(200, { version: '1.0.0' })
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(400, errorObject);

await expect(
openapi.run({
spec: './__tests__/__fixtures__/swagger-with-invalid-extensions.json',
key,
version,
})
).rejects.toStrictEqual(new APIError(errorObject));

return mock.done();
});

it('should error if API errors', async () => {
const errorObject = {
error: 'SPEC_VERSION_NOTFOUND',
Expand All @@ -399,14 +457,18 @@ describe('rdme openapi', () => {
help: 'If you need help, email [email protected] and mention log "fake-metrics-uuid".',
};

const registryUUID = getRandomRegistryId();

const mock = getApiNock()
.get(`/api/v1/version/${version}`)
.basicAuth({ user: key })
.reply(200, { version: '1.0.0' })
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(201, { registryUUID, spec: { openapi: '3.0.0' } })
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.post('/api/v1/api-specification', body => body.match('form-data; name="spec"'))
.post('/api/v1/api-specification', { registryUUID })
.delayConnection(1000)
.basicAuth({ user: key })
.reply(400, errorObject);
Expand All @@ -419,14 +481,18 @@ describe('rdme openapi', () => {
});

it('should error if API errors (generic upload error)', async () => {
const registryUUID = getRandomRegistryId();

const mock = getApiNock()
.get(`/api/v1/version/${version}`)
.basicAuth({ user: key })
.reply(200, { version: '1.0.0' })
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(201, { registryUUID, spec: { openapi: '3.0.0' } })
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.post('/api/v1/api-specification', body => body.match('form-data; name="spec"'))
.post('/api/v1/api-specification', { registryUUID })
.delayConnection(1000)
.basicAuth({ user: key })
.reply(400, 'some non-JSON upload error');
Expand All @@ -439,14 +505,18 @@ describe('rdme openapi', () => {
});

it('should error if API errors (request timeout)', async () => {
const registryUUID = getRandomRegistryId();

const mock = getApiNock()
.get(`/api/v1/version/${version}`)
.basicAuth({ user: key })
.reply(200, { version: '1.0.0' })
.post('/api/v1/api-registry', body => body.match('form-data; name="spec"'))
.reply(201, { registryUUID, spec: { openapi: '3.0.0' } })
.get('/api/v1/api-specification')
.basicAuth({ user: key })
.reply(200, [])
.post('/api/v1/api-specification', body => body.match('form-data; name="spec"'))
.post('/api/v1/api-specification', { registryUUID })
.delayConnection(1000)
.basicAuth({ user: key })
.reply(400, '<html></html>');
Expand Down
Loading

0 comments on commit e1aeac0

Please sign in to comment.