diff --git a/plugins/newrelic/src/api/index.test.ts b/plugins/newrelic/src/api/index.test.ts index 13d9c5304d..69cf74066f 100644 --- a/plugins/newrelic/src/api/index.test.ts +++ b/plugins/newrelic/src/api/index.test.ts @@ -126,7 +126,7 @@ describe('NewRelicClient', () => { headers: new Map([ [ 'link', - '; rel="next", ; rel="next"', + '; rel="next", ; rel="next"', ], ['otherheader', 'otherValue'], ]), @@ -135,7 +135,7 @@ describe('NewRelicClient', () => { ok: true, json: async () => ({ applications: [] }), headers: new Map([ - ['Link', '; rel="next",'], + ['Link', '; rel="next",'], ]), }) .mockResolvedValueOnce({ @@ -170,10 +170,10 @@ describe('NewRelicClient', () => { 'https://test.test/newrelic/apm/api/applications.json', ); expect(mockedFetchApi.fetch).toHaveBeenCalledWith( - 'https://next.page/page2', + 'https://test.test/newrelic/apm/api/applications.json?page=2', ); expect(mockedFetchApi.fetch).toHaveBeenCalledWith( - 'https://next.page/page3', + 'https://test.test/newrelic/apm/api/applications.json?page=3', ); expect(actual).toStrictEqual(expected); }); @@ -220,6 +220,7 @@ describe('NewRelicClient', () => { ['<>; rel:"value"'], ['; rel: "next"'], ['ABCDE'], + ['; rel="next",'], ])( 'It does not attempt pagination when the link header value is invalid (%p)', async linkHeaderValue => { @@ -309,4 +310,29 @@ describe('NewRelicClient', () => { expect(actual).toStrictEqual({ applications: [] }); }); + + it('Generates the base url only once', async () => { + const mockedDiscoveryApi: DiscoveryApi = { + getBaseUrl: jest.fn().mockResolvedValueOnce('https://test.test'), + }; + + const mockedFetchApi: FetchApi = { + fetch: jest.fn().mockResolvedValue({ + ok: true, + json: async () => ({ applications: [] }), + }), + }; + + const client = new NewRelicClient({ + discoveryApi: mockedDiscoveryApi, + fetchApi: mockedFetchApi, + }); + + await client.getApplications(); + await client.getApplications(); + await client.getApplications(); + await client.getApplications(); + + expect(mockedDiscoveryApi.getBaseUrl).toHaveBeenCalledTimes(1); + }); }); diff --git a/plugins/newrelic/src/api/index.ts b/plugins/newrelic/src/api/index.ts index 9c95f3fe1f..b471104139 100644 --- a/plugins/newrelic/src/api/index.ts +++ b/plugins/newrelic/src/api/index.ts @@ -91,16 +91,22 @@ export class NewRelicClient implements NewRelicApi { private readonly discoveryApi: DiscoveryApi; private readonly fetchApi: FetchApi; private readonly proxyPathBase: string; + private baseUrl: string; constructor(options: Options) { this.discoveryApi = options.discoveryApi; this.fetchApi = options.fetchApi; this.proxyPathBase = options.proxyPathBase ?? DEFAULT_PROXY_PATH_BASE; + this.baseUrl = ''; } async getApplications(): Promise { - const proxyUrl = await this.discoveryApi.getBaseUrl('proxy'); - let targetUrl = `${proxyUrl}${this.proxyPathBase}/apm/api/applications.json`; + if (!this.baseUrl) { + const proxyUrl = await this.discoveryApi.getBaseUrl('proxy'); + this.baseUrl = `${proxyUrl}${this.proxyPathBase}/apm/api/applications.json`; + } + + let targetUrl = this.baseUrl; let hasNextPage = true; try { @@ -111,7 +117,7 @@ export class NewRelicClient implements NewRelicApi { await this.fetchNewRelic(targetUrl); hasNextPage = hasMoreApplications; - targetUrl = pagination!.nextPageLink; + targetUrl = hasNextPage ? pagination!.nextPageLink : ''; applications = applications.concat(applicationsFromReadPage); } while (hasNextPage); @@ -155,12 +161,12 @@ export class NewRelicClient implements NewRelicApi { } const nextRelevantLink = linkHeader.replaceAll(' ', '').split(',')[0]; - - // Link should be of the format ;rel="relation" - const linkParts = nextRelevantLink.match(/^<(.+)>;rel="(.+)"$/); - const nextPageLink = linkParts?.[1]; + const linkParts = nextRelevantLink.match(/^<.+(\?page=.+)>;rel="(.+)"$/); + const nextPageNumber = linkParts?.[1]; const relation = linkParts?.[2]; - const isValidLink = !!(!!linkParts && nextPageLink && relation); + + const nextPageLink = `${this.baseUrl}${nextPageNumber}`; + const isValidLink = !!(!!linkParts && nextPageNumber && relation); if (!nextRelevantLink || !isValidLink) { return undefined;