From 0d2e6197d8e775fcf9b146f8b7735d2a45b2f893 Mon Sep 17 00:00:00 2001 From: Johan Haals Date: Fri, 12 Aug 2022 15:30:24 +0200 Subject: [PATCH] =?UTF-8?q?Refactor=20backend-test-utils=20Co-authored-by:?= =?UTF-8?q?=20Fredrik=20Adel=C3=B6w=20=20?= =?UTF-8?q?Co-authored-by:=20Patrik=20Oldsberg=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Johan Haals --- .../src/wiring/BackendInitializer.ts | 21 +++--- packages/backend-app-api/src/wiring/index.ts | 6 +- packages/backend-app-api/src/wiring/types.ts | 14 +++- .../backend-plugin-api/src/wiring/types.ts | 8 ++- .../src/next/wiring/TestBackend.test.ts | 6 +- .../src/next/wiring/TestBackend.ts | 64 ++++++++++++++----- .../src/next/wiring/index.ts | 2 +- plugins/catalog-node/src/extensions.ts | 4 +- .../extension/ScaffolderCatalogModule.test.ts | 5 +- 9 files changed, 89 insertions(+), 41 deletions(-) diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index 0c2cd3e541..c1b7089827 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -19,15 +19,17 @@ import { ExtensionPoint, ServiceRef, } from '@backstage/backend-plugin-api'; -import { BackendRegisterInit, ServiceHolder } from './types'; - -type ServiceOrExtensionPoint = ExtensionPoint | ServiceRef; +import { + BackendRegisterInit, + ServiceHolder, + ServiceOrExtensionPoint, +} from './types'; export class BackendInitializer { #started = false; #features = new Map(); #registerInits = new Array(); - #extensionPoints = new Map(); + #extensionPoints = new Map, unknown>(); #serviceHolder: ServiceHolder; constructor(serviceHolder: ServiceHolder) { @@ -42,7 +44,7 @@ export class BackendInitializer { await Promise.all( Object.entries(deps).map(async ([name, ref]) => [ name, - this.#extensionPoints.get(ref) || + this.#extensionPoints.get(ref as ExtensionPoint) || (await this.#serviceHolder.get(ref as ServiceRef)!( pluginId, )), @@ -66,7 +68,7 @@ export class BackendInitializer { this.#started = true; for (const [feature] of this.#features) { - const provides = new Set>(); + const provides = new Set>(); let registerInit: BackendRegisterInit | undefined = undefined; @@ -129,13 +131,13 @@ export class BackendInitializer { for (const registerInit of registerInitsToOrder) { const unInitializedDependents = []; - for (const serviceRef of registerInit.provides) { + for (const provided of registerInit.provides) { if ( registerInitsToOrder.some( - init => init !== registerInit && init.consumes.has(serviceRef), + init => init !== registerInit && init.consumes.has(provided), ) ) { - unInitializedDependents.push(serviceRef); + unInitializedDependents.push(provided); } } @@ -148,6 +150,7 @@ export class BackendInitializer { registerInitsToOrder = registerInitsToOrder.filter(r => !toRemove.has(r)); } + return orderedRegisterInits; } } diff --git a/packages/backend-app-api/src/wiring/index.ts b/packages/backend-app-api/src/wiring/index.ts index d6e4de9145..2f55076922 100644 --- a/packages/backend-app-api/src/wiring/index.ts +++ b/packages/backend-app-api/src/wiring/index.ts @@ -14,5 +14,9 @@ * limitations under the License. */ -export type { Backend, CreateSpecializedBackendOptions } from './types'; +export type { + Backend, + CreateSpecializedBackendOptions, + ServiceOrExtensionPoint, +} from './types'; export { createSpecializedBackend } from './types'; diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index cdd4578789..0ca40b5660 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -17,6 +17,7 @@ import { AnyServiceFactory, BackendFeature, + ExtensionPoint, FactoryFunc, ServiceRef, } from '@backstage/backend-plugin-api'; @@ -32,9 +33,9 @@ export interface Backend { export interface BackendRegisterInit { id: string; - consumes: Set>; - provides: Set>; - deps: { [name: string]: ServiceRef }; + consumes: Set; + provides: Set; + deps: { [name: string]: ServiceOrExtensionPoint }; init: (deps: { [name: string]: unknown }) => Promise; } @@ -57,3 +58,10 @@ export function createSpecializedBackend( ): Backend { return new BackstageBackend(options.services); } + +/** + * @public + */ +export type ServiceOrExtensionPoint = + | ExtensionPoint + | ServiceRef; diff --git a/packages/backend-plugin-api/src/wiring/types.ts b/packages/backend-plugin-api/src/wiring/types.ts index 1801127ddb..cdb56ea2e4 100644 --- a/packages/backend-plugin-api/src/wiring/types.ts +++ b/packages/backend-plugin-api/src/wiring/types.ts @@ -38,12 +38,14 @@ export type ExtensionPoint = { /** @public */ export interface BackendRegistrationPoints { registerExtensionPoint( - ref: ServiceRef, + ref: ExtensionPoint, impl: TExtensionPoint, ): void; registerInit(options: { - deps: { [name in keyof Deps]: ServiceRef }; - init: (deps: Deps) => Promise; + deps: { + [name in keyof Deps]: ServiceRef | ExtensionPoint; + }; + init(deps: Deps): Promise; }): void; } diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts index 279667560f..6b3f8e270f 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts @@ -19,12 +19,12 @@ import { createServiceFactory, createServiceRef, } from '@backstage/backend-plugin-api'; -import { createTestBackend, startTestBackend } from './TestBackend'; +import { startTestBackend } from './TestBackend'; describe('TestBackend', () => { it('should get a type error if service implementation does not match', () => { const serviceRef = createServiceRef<{ a: string; b: string }>({ id: 'a' }); - const backend = createTestBackend({ + const backend = startTestBackend({ services: [ [serviceRef, { a: 'a' }], [serviceRef, { a: 'a', b: 'b' }], @@ -68,7 +68,7 @@ describe('TestBackend', () => { await startTestBackend({ services: [sf], - registrables: [testModule({})], + features: [testModule({})], }); expect(testFn).toBeCalledWith('winning'); diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 150d4ce2af..b9276fa9b9 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -14,31 +14,54 @@ * limitations under the License. */ -import { Backend, createSpecializedBackend } from '@backstage/backend-app-api'; +import { createSpecializedBackend } from '@backstage/backend-app-api'; import { AnyServiceFactory, ServiceRef, createServiceFactory, BackendFeature, + ExtensionPoint, } from '@backstage/backend-plugin-api'; /** @alpha */ -export interface TestBackendOptions { - services: readonly [ +export interface TestBackendOptions< + TServices extends any[], + TExtensionPoints extends any[], +> { + services?: readonly [ ...{ [index in keyof TServices]: | AnyServiceFactory | [ServiceRef, Partial]; }, ]; + extensionPoints?: readonly [ + ...{ + [index in keyof TExtensionPoints]: [ + ExtensionPoint, + Partial, + ]; + }, + ]; + features?: BackendFeature[]; } /** @alpha */ -export function createTestBackend( - options: TestBackendOptions, -): Backend { - const factories = options.services?.map(serviceDef => { +export async function startTestBackend< + TServices extends any[], + TExtensionPoints extends any[], +>(options: TestBackendOptions): Promise { + const { + services = [], + extensionPoints = [], + features = [], + ...otherOptions + } = options; + + const factories = services.map(serviceDef => { if (Array.isArray(serviceDef)) { + // if type is ExtensionPoint? + // do something differently? return createServiceFactory({ service: serviceDef[0], deps: {}, @@ -47,19 +70,26 @@ export function createTestBackend( } return serviceDef as AnyServiceFactory; }); - return createSpecializedBackend({ services: factories ?? [] }); -} -/** @alpha */ -export async function startTestBackend( - options: TestBackendOptions & { - features?: BackendFeature[]; - }, -): Promise { - const { features = [], ...otherOptions } = options; - const backend = createTestBackend(otherOptions); + const backend = createSpecializedBackend({ + ...otherOptions, + services: factories, + }); + + backend.add({ + id: `---test-extension-point-registrar`, + register(reg) { + for (const [ref, impl] of extensionPoints) { + reg.registerExtensionPoint(ref, impl); + } + + reg.registerInit({ deps: {}, async init() {} }); + }, + }); + for (const feature of features) { backend.add(feature); } + await backend.start(); } diff --git a/packages/backend-test-utils/src/next/wiring/index.ts b/packages/backend-test-utils/src/next/wiring/index.ts index 18a35c2b66..eb7b773e33 100644 --- a/packages/backend-test-utils/src/next/wiring/index.ts +++ b/packages/backend-test-utils/src/next/wiring/index.ts @@ -14,5 +14,5 @@ * limitations under the License. */ -export { createTestBackend, startTestBackend } from './TestBackend'; +export { startTestBackend } from './TestBackend'; export type { TestBackendOptions } from './TestBackend'; diff --git a/plugins/catalog-node/src/extensions.ts b/plugins/catalog-node/src/extensions.ts index 9f76946d30..80fbd7630f 100644 --- a/plugins/catalog-node/src/extensions.ts +++ b/plugins/catalog-node/src/extensions.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { createServiceRef } from '@backstage/backend-plugin-api'; +import { createExtensionPoint } from '@backstage/backend-plugin-api'; import { EntityProvider } from './api'; import { CatalogProcessor } from './api/processor'; @@ -29,6 +29,6 @@ export interface CatalogProcessingExtensionPoint { * @alpha */ export const catalogProcessingExtensionPoint = - createServiceRef({ + createExtensionPoint({ id: 'catalog.processing', }); diff --git a/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.test.ts b/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.test.ts index a969d80a1b..e8ed3bf505 100644 --- a/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.test.ts +++ b/plugins/scaffolder-backend/src/extension/ScaffolderCatalogModule.test.ts @@ -23,8 +23,9 @@ describe('ScaffolderCatalogModule', () => { it('should register the extension point', async () => { const extensionPoint = { addProcessor: jest.fn() }; await startTestBackend({ - services: [[catalogProcessingExtensionPoint, extensionPoint]], - registrables: [scaffolderCatalogModule({})], + services: [], + extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], + features: [scaffolderCatalogModule({})], }); expect(extensionPoint.addProcessor).toHaveBeenCalledWith(