diff --git a/plugins/newrelic/src/api/index.test.ts b/plugins/newrelic/src/api/index.test.ts index f45482be87..d4ed4a1691 100644 --- a/plugins/newrelic/src/api/index.test.ts +++ b/plugins/newrelic/src/api/index.test.ts @@ -20,6 +20,10 @@ import { rest } from 'msw'; import { setupServer } from 'msw/node'; import { MockFetchApi, setupRequestMockHandlers } from '@backstage/test-utils'; +const mockedDiscoveryApi: DiscoveryApi = { + getBaseUrl: async () => 'https://test.test', +}; + beforeEach(() => { jest.resetAllMocks(); }); @@ -46,10 +50,6 @@ describe('NewRelicClient', () => { ), ); - const mockedDiscoveryApi: DiscoveryApi = { - getBaseUrl: jest.fn().mockResolvedValueOnce('https://test.test'), - }; - const mockedFetchApi = new MockFetchApi(); const fetchSpy = jest.spyOn(mockedFetchApi, 'fetch'); @@ -65,10 +65,6 @@ describe('NewRelicClient', () => { ); it('Correctly reads all pages of results and returns the expected results', async () => { - const mockedDiscoveryApi: DiscoveryApi = { - getBaseUrl: jest.fn().mockResolvedValueOnce('https://test.test'), - }; - const mockedApplicationOne: NewRelicApplication = { id: 1, application_summary: { @@ -219,10 +215,6 @@ describe('NewRelicClient', () => { test.each([['Link'], ['LINK'], ['lINK']])( 'It does not attempt pagination when the link header name is invalid (%p)', async linkHeaderName => { - const mockedDiscoveryApi: DiscoveryApi = { - getBaseUrl: jest.fn().mockResolvedValueOnce('https://test.test'), - }; - const mockedFetchApi = new MockFetchApi(); const fetchSpy = jest.spyOn(mockedFetchApi, 'fetch'); @@ -271,10 +263,6 @@ describe('NewRelicClient', () => { ])( 'It does not attempt pagination when the link header value is invalid (%p)', async linkHeaderValue => { - const mockedDiscoveryApi: DiscoveryApi = { - getBaseUrl: jest.fn().mockResolvedValueOnce('https://test.test'), - }; - const mockedFetchApi = new MockFetchApi(); const fetchSpy = jest.spyOn(mockedFetchApi, 'fetch'); @@ -309,19 +297,38 @@ describe('NewRelicClient', () => { ); test.each([ - [404, { error: { title: 'TESTING' } }], - [500, {}], + ['Error communicating with New Relic: Not Found', 404, JSON.stringify({})], + [ + 'Error communicating with New Relic: ERROR TITLE', + 404, + JSON.stringify({ + error: { + title: 'ERROR TITLE', + }, + }), + ], + [ + 'Error communicating with New Relic: Internal Server Error', + 500, + JSON.stringify(undefined), + ], + [ + 'Error communicating with New Relic: Internal Server Error', + 500, + JSON.stringify(null), + ], + [ + 'Error communicating with New Relic: Internal Server Error', + 500, + ' { - const mockedDiscoveryApi: DiscoveryApi = { - getBaseUrl: jest.fn().mockResolvedValueOnce('https://test.test'), - }; - + 'It throws this error: %p when the status code is %p and the body is %j', + async (expectedErrorMessage, statusCode, body) => { server.use( rest.get( 'https://test.test/newrelic/apm/api/applications.json', - (_, res, ctx) => res(ctx.status(statusCode), ctx.json(jsonBody)), + (_, res, ctx) => res(ctx.status(statusCode), ctx.body(body)), ), ); @@ -329,36 +336,31 @@ describe('NewRelicClient', () => { discoveryApi: mockedDiscoveryApi, fetchApi: new MockFetchApi(), }); - const actual = await client.getApplications(); - expect(actual).toStrictEqual({ applications: [] }); + await expect(client.getApplications()).rejects.toThrow( + expectedErrorMessage, + ); }, ); - it('Returns an empty array when the fetch itself throws an error', async () => { - const mockedDiscoveryApi: DiscoveryApi = { - getBaseUrl: jest.fn().mockResolvedValueOnce('https://test.test'), - }; - + it('Throws an error when the body is invalid json but the status code is 200', async () => { server.use( - rest.get('https://test.test/newrelic/apm/api/applications.json', () => { - throw new Error('Network Error'); - }), + rest.get( + 'https://test.test/newrelic/apm/api/applications.json', + (_, res, ctx) => res(ctx.status(200), ctx.body(' { - const mockedDiscoveryApi: DiscoveryApi = { - getBaseUrl: jest.fn().mockResolvedValueOnce('https://test.test'), - }; + const getBaseUrlSpy = jest.spyOn(mockedDiscoveryApi, 'getBaseUrl'); server.use( rest.get( @@ -377,6 +379,6 @@ describe('NewRelicClient', () => { await client.getApplications(); await client.getApplications(); - expect(mockedDiscoveryApi.getBaseUrl).toHaveBeenCalledTimes(1); + expect(getBaseUrlSpy).toHaveBeenCalledTimes(1); }); }); diff --git a/plugins/newrelic/src/api/index.ts b/plugins/newrelic/src/api/index.ts index 3fdebd1494..b37575b163 100644 --- a/plugins/newrelic/src/api/index.ts +++ b/plugins/newrelic/src/api/index.ts @@ -102,39 +102,41 @@ export class NewRelicClient implements NewRelicApi { this.baseUrl = `${proxyUrl}${this.proxyPathBase}/apm/api/applications.json`; } - try { - const applications: NewRelicApplication[] = []; - let targetUrl = this.baseUrl; + const applications: NewRelicApplication[] = []; + let targetUrl = this.baseUrl; - do { - const { nextPageUrl, applicationsFromReadPage } = - await this.fetchNewRelic(targetUrl); + do { + const { nextPageUrl, applicationsFromReadPage } = + await this.fetchNewRelic(targetUrl); - targetUrl = nextPageUrl ?? ''; - applications.push(...applicationsFromReadPage); - } while (!!targetUrl); + targetUrl = nextPageUrl ?? ''; + applications.push(...applicationsFromReadPage); + } while (!!targetUrl); - return { applications }; - } catch (e) { - return { applications: [] }; - } + return { applications }; } private async fetchNewRelic( targetUrl: string, ): Promise { const response = await this.fetchApi.fetch(targetUrl); - const responseJson = await response.json(); if (!response.ok) { + let specificErrorTitle = undefined; + try { + specificErrorTitle = (await response.json())?.error?.title; + } catch (e) { + /* empty */ + } + throw new Error( `Error communicating with New Relic: ${ - responseJson?.error?.title || response.statusText + specificErrorTitle || response.statusText }`, ); } - const readResponse = responseJson as NewRelicApplications; + const readResponse = (await response.json()) as NewRelicApplications; const linkHeader = response.headers.get('link'); const parseResult = parseLinkHeader(linkHeader); const nextPageNumber = parseResult?.next?.page;