From 8e9f1675829c97c02fada54d0f0368f22ccf1f10 Mon Sep 17 00:00:00 2001 From: Andrew Shirley Date: Fri, 11 Jun 2021 18:52:23 +0100 Subject: [PATCH] Add jenkinsInfoProvider tests (and fix bug :-) ) Signed-off-by: Andrew Shirley Signed-off-by: blam --- .../src/service/jenkinsInfoProvider.test.ts | 266 ++++++++++++++++++ .../src/service/jenkinsInfoProvider.ts | 4 +- 2 files changed, 268 insertions(+), 2 deletions(-) create mode 100644 plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts diff --git a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts new file mode 100644 index 0000000000000..e26809406e16d --- /dev/null +++ b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.test.ts @@ -0,0 +1,266 @@ +/* + * Copyright 2021 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { DefaultJenkinsInfoProvider, JenkinsInfo } from './jenkinsInfoProvider'; +import { CatalogClient } from '@backstage/catalog-client'; +import { ConfigReader } from '@backstage/config'; +import { Entity, EntityName } from '@backstage/catalog-model'; + +describe('DefaultJenkinsInfoProvider', () => { + const mockCatalog: jest.Mocked = ({ + getEntityByName: jest.fn(), + } as any) as jest.Mocked; + + const entityRef: EntityName = { + kind: 'Component', + namespace: 'foo', + name: 'bar', + }; + + function configureProvider(configData: any, entityData: any) { + const config = new ConfigReader(configData); + mockCatalog.getEntityByName.mockReturnValueOnce( + Promise.resolve(entityData as Entity), + ); + + return new DefaultJenkinsInfoProvider(mockCatalog, config); + } + + it('Handles entity not found', async () => { + const provider = configureProvider({}, undefined); + await expect(provider.getInstance({ entityRef })).rejects.toThrowError(); + + expect(mockCatalog.getEntityByName).toBeCalledWith(entityRef); + }); + + it('Reads simple config and annotation', async () => { + const provider = configureProvider( + { + jenkins: { + baseUrl: 'https://jenkins.example.com', + username: 'backstage - bot', + apiKey: '123456789abcdef0123456789abcedf012', + }, + }, + { + metadata: { + annotations: { + 'jenkins.io/job-slug': 'teamA/artistLookup-build', + }, + }, + }, + ); + const info: JenkinsInfo = await provider.getInstance({ entityRef }); + + expect(mockCatalog.getEntityByName).toBeCalledWith(entityRef); + expect(info).toStrictEqual({ + baseUrl: 'https://jenkins.example.com', + headers: { + Authorization: + 'Basic YmFja3N0YWdlIC0gYm90OjEyMzQ1Njc4OWFiY2RlZjAxMjM0NTY3ODlhYmNlZGYwMTI=', + }, + jobName: 'teamA/artistLookup-build', + }); + }); + + it('Reads named default config and annotation', async () => { + const provider = configureProvider( + { + jenkins: { + instances: [ + { + name: 'default', + baseUrl: 'https://jenkins.example.com', + username: 'backstage - bot', + apiKey: '123456789abcdef0123456789abcedf012', + }, + ], + }, + }, + { + metadata: { + annotations: { + 'jenkins.io/job-slug': 'teamA/artistLookup-build', + }, + }, + }, + ); + const info: JenkinsInfo = await provider.getInstance({ entityRef }); + + expect(mockCatalog.getEntityByName).toBeCalledWith(entityRef); + expect(info).toMatchObject({ + baseUrl: 'https://jenkins.example.com', + jobName: 'teamA/artistLookup-build', + }); + }); + + it('Reads named default config (amongst named other configs) and annotation', async () => { + const provider = configureProvider( + { + jenkins: { + instances: [ + { + name: 'default', + baseUrl: 'https://jenkins.example.com', + username: 'backstage - bot', + apiKey: '123456789abcdef0123456789abcedf012', + }, + { + name: 'other', + baseUrl: 'https://jenkins-other.example.com', + username: 'backstage - bot', + apiKey: '123456789abcdef0123456789abcedf012', + }, + ], + }, + }, + { + metadata: { + annotations: { + 'jenkins.io/job-slug': 'teamA/artistLookup-build', + }, + }, + }, + ); + const info: JenkinsInfo = await provider.getInstance({ entityRef }); + + expect(mockCatalog.getEntityByName).toBeCalledWith(entityRef); + expect(info).toMatchObject({ + baseUrl: 'https://jenkins.example.com', + jobName: 'teamA/artistLookup-build', + }); + }); + + it('Reads named other config and named annotation', async () => { + const provider = configureProvider( + { + jenkins: { + instances: [ + { + name: 'default', + baseUrl: 'https://jenkins.example.com', + username: 'backstage - bot', + apiKey: '123456789abcdef0123456789abcedf012', + }, + { + name: 'other', + baseUrl: 'https://jenkins-other.example.com', + username: 'backstage - bot', + apiKey: '123456789abcdef0123456789abcedf012', + }, + ], + }, + }, + { + metadata: { + annotations: { + 'jenkins.io/job-slug': 'other:teamA/artistLookup-build', + }, + }, + }, + ); + const info: JenkinsInfo = await provider.getInstance({ entityRef }); + + expect(mockCatalog.getEntityByName).toBeCalledWith(entityRef); + expect(info).toMatchObject({ + baseUrl: 'https://jenkins-other.example.com', + jobName: 'teamA/artistLookup-build', + }); + }); + + it('Reads simple config and default named annotation', async () => { + const provider = configureProvider( + { + jenkins: { + baseUrl: 'https://jenkins.example.com', + username: 'backstage - bot', + apiKey: '123456789abcdef0123456789abcedf012', + }, + }, + { + metadata: { + annotations: { + 'jenkins.io/job-slug': 'default:teamA/artistLookup-build', + }, + }, + }, + ); + const info: JenkinsInfo = await provider.getInstance({ entityRef }); + + expect(mockCatalog.getEntityByName).toBeCalledWith(entityRef); + expect(info).toMatchObject({ + baseUrl: 'https://jenkins.example.com', + jobName: 'teamA/artistLookup-build', + }); + }); + + it('Reads simple config and old annotation', async () => { + const provider = configureProvider( + { + jenkins: { + baseUrl: 'https://jenkins.example.com', + username: 'backstage - bot', + apiKey: '123456789abcdef0123456789abcedf012', + }, + }, + { + metadata: { + annotations: { + 'jenkins.io/github-folder': 'teamA/artistLookup-build', + }, + }, + }, + ); + const info: JenkinsInfo = await provider.getInstance({ entityRef }); + + expect(mockCatalog.getEntityByName).toBeCalledWith(entityRef); + expect(info).toMatchObject({ + baseUrl: 'https://jenkins.example.com', + jobName: 'teamA/artistLookup-build', + }); + }); + + it('Reads named other config (with on default config) and named annotation', async () => { + const provider = configureProvider( + { + jenkins: { + instances: [ + { + name: 'other', + baseUrl: 'https://jenkins-other.example.com', + username: 'backstage - bot', + apiKey: '123456789abcdef0123456789abcedf012', + }, + ], + }, + }, + { + metadata: { + annotations: { + 'jenkins.io/job-slug': 'other:teamA/artistLookup-build', + }, + }, + }, + ); + const info: JenkinsInfo = await provider.getInstance({ entityRef }); + + expect(mockCatalog.getEntityByName).toBeCalledWith(entityRef); + expect(info).toMatchObject({ + baseUrl: 'https://jenkins-other.example.com', + jobName: 'teamA/artistLookup-build', + }); + }); +}); diff --git a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts index 51c6c3e383433..0a712187399c7 100644 --- a/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts +++ b/plugins/jenkins-backend/src/service/jenkinsInfoProvider.ts @@ -155,8 +155,8 @@ export class DefaultJenkinsInfoProvider implements JenkinsInfoProvider { // (jenkins.baseUrl, jenkins.username, jenkins.apiKey) or // the entry with default name in jenkins.instances const namedInstanceConfig = jenkinsConfig - .getConfigArray('instances') - .filter(c => c.getString('name') === DEFAULT_JENKINS_NAME)[0]; + .getOptionalConfigArray('instances') + ?.filter(c => c.getString('name') === DEFAULT_JENKINS_NAME)[0]; if (namedInstanceConfig) { return namedInstanceConfig; }