diff --git a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts new file mode 100644 index 0000000000..0b5f0569bb --- /dev/null +++ b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.test.ts @@ -0,0 +1,109 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 { InMemoryCatalogClient } from './InMemoryCatalogClient'; +import { Entity } from '@backstage/catalog-model'; + +const entity1: Entity = { + apiVersion: 'v1', + kind: 'CustomKind', + metadata: { + namespace: 'default', + name: 'e1', + uid: 'u1', + }, +}; + +const entity2: Entity = { + apiVersion: 'v1', + kind: 'CustomKind', + metadata: { + namespace: 'default', + name: 'e2', + uid: 'u2', + }, +}; + +const entities = [entity1, entity2]; + +describe('InMemoryCatalogClient', () => { + it('getEntities', async () => { + const client = new InMemoryCatalogClient({ entities }); + await expect(client.getEntities()).resolves.toEqual({ items: entities }); + }); + + it('getEntitiesByRefs', async () => { + const client = new InMemoryCatalogClient({ entities }); + await expect( + client.getEntitiesByRefs({ + entityRefs: [ + 'customkind:default/e2', + 'customkind:missing/missing', + 'customkind:default/e1', + ], + }), + ).resolves.toEqual({ items: [entity2, undefined, entity1] }); + }); + + it('queryEntities', async () => { + const client = new InMemoryCatalogClient({ entities }); + await expect(client.queryEntities()).resolves.toEqual({ + items: entities, + totalItems: 2, + pageInfo: {}, + }); + }); + + it('getEntityAncestors', async () => { + const client = new InMemoryCatalogClient({ entities }); + await expect( + client.getEntityAncestors({ entityRef: 'customkind:default/e2' }), + ).resolves.toEqual({ + rootEntityRef: 'customkind:default/e2', + items: [{ entity: entity2, parentEntityRefs: [] }], + }); + }); + + it('getEntityByRef', async () => { + const client = new InMemoryCatalogClient({ entities }); + await expect( + client.getEntityByRef('customkind:default/e2'), + ).resolves.toEqual(entity2); + await expect( + client.getEntityByRef('customkind:missing/missing'), + ).resolves.toBeUndefined(); + }); + + it('removeEntityByUid', async () => { + const client = new InMemoryCatalogClient({ entities }); + await expect(client.getEntities()).resolves.toEqual({ + items: expect.arrayContaining([entity2]), + }); + await expect( + client.removeEntityByUid(entity2.metadata.uid!), + ).resolves.toBeUndefined(); + await expect(client.getEntities()).resolves.not.toEqual({ + items: expect.arrayContaining([entity2]), + }); + }); + + it('refreshEntity', async () => { + const client = new InMemoryCatalogClient({ entities }); + await expect( + client.refreshEntity('customkind:default/e2'), + ).resolves.toBeUndefined(); + }); +}); diff --git a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts index cde018a55c..745273c6bc 100644 --- a/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts +++ b/packages/catalog-client/src/testUtils/InMemoryCatalogClient.ts @@ -49,14 +49,14 @@ export class InMemoryCatalogClient implements CatalogApi { #entities: Entity[]; constructor(options?: { entities?: Entity[] }) { - this.#entities = options?.entities ?? []; + this.#entities = options?.entities?.slice() ?? []; } async getEntities( _request?: GetEntitiesRequest, ): Promise { // TODO(freben): Fields, filters etc - return { items: this.#entities }; + return { items: this.#entities.slice() }; } async getEntitiesByRefs( @@ -80,7 +80,7 @@ export class InMemoryCatalogClient implements CatalogApi { ): Promise { // TODO(freben): Fields, filters etc return { - items: this.#entities, + items: this.#entities.slice(), totalItems: this.#entities.length, pageInfo: {}, }; diff --git a/plugins/catalog-node/src/testUtils/catalogServiceMock.test.ts b/plugins/catalog-node/src/testUtils/catalogServiceMock.test.ts new file mode 100644 index 0000000000..47850dd600 --- /dev/null +++ b/plugins/catalog-node/src/testUtils/catalogServiceMock.test.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2024 The Backstage Authors + * + * 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 { Entity } from '@backstage/catalog-model'; +import { catalogServiceMock } from './catalogServiceMock'; + +const entity1: Entity = { + apiVersion: 'v1', + kind: 'CustomKind', + metadata: { + namespace: 'default', + name: 'e1', + uid: 'u1', + }, +}; + +const entity2: Entity = { + apiVersion: 'v1', + kind: 'CustomKind', + metadata: { + namespace: 'default', + name: 'e2', + uid: 'u2', + }, +}; + +const entities = [entity1, entity2]; + +describe('catalogServiceMock', () => { + it('exports the expected functionality', async () => { + const emptyFake = catalogServiceMock(); + const notEmptyFake = catalogServiceMock({ entities }); + + await expect(emptyFake.getEntities()).resolves.toEqual({ items: [] }); + await expect(notEmptyFake.getEntities()).resolves.toEqual({ + items: entities, + }); + + const mock = catalogServiceMock.mock(); + expect(mock.getEntities).toHaveBeenCalledTimes(0); + expect(mock.getEntities()).toBeUndefined(); + mock.getEntities.mockResolvedValue({ items: entities }); + await expect(mock.getEntities()).resolves.toEqual({ items: entities }); + + const mock2 = catalogServiceMock.mock({ + getEntities: async () => ({ items: [entity1] }), + }); + await expect(mock2.getEntities()).resolves.toEqual({ items: [entity1] }); + }); +});