diff --git a/.changeset/young-lies-attack.md b/.changeset/young-lies-attack.md new file mode 100644 index 0000000000..02a23e38e5 --- /dev/null +++ b/.changeset/young-lies-attack.md @@ -0,0 +1,19 @@ +--- +'@backstage/backend-plugin-api': patch +'@backstage/backend-test-utils': minor +'@backstage/backend-defaults': minor +'@backstage/backend-app-api': minor +--- + +**BREAKING**: Removed the `services` option from `createBackend`. Service factories are now `BackendFeature`s and should be installed with `backend.add(...)` instead. The following should be migrated: + +```ts +const backend = createBackend({ services: [myCustomServiceFactory] }); +``` + +To instead pass the service factory via `backend.add(...)`: + +```ts +const backend = createBackend(); +backend.add(customRootLoggerServiceFactory); +``` diff --git a/packages/backend-app-api/api-report.md b/packages/backend-app-api/api-report.md index 675a7755fc..0fa1ff376e 100644 --- a/packages/backend-app-api/api-report.md +++ b/packages/backend-app-api/api-report.md @@ -43,7 +43,7 @@ import { UrlReader } from '@backstage/backend-common'; // @public (undocumented) export interface Backend { // (undocumented) - add(feature: BackendFeature): void; + add(feature: BackendFeature | (() => BackendFeature)): void; // (undocumented) start(): Promise; // (undocumented) @@ -81,7 +81,7 @@ export function createSpecializedBackend( // @public (undocumented) export interface CreateSpecializedBackendOptions { // (undocumented) - services: ServiceFactoryOrFunction[]; + defaultServiceFactories: ServiceFactoryOrFunction[]; } // @public (undocumented) diff --git a/packages/backend-app-api/src/alpha/featureDiscoveryServiceFactory.test.ts b/packages/backend-app-api/src/alpha/featureDiscoveryServiceFactory.test.ts index 5a5917dd3b..5d4b1fc551 100644 --- a/packages/backend-app-api/src/alpha/featureDiscoveryServiceFactory.test.ts +++ b/packages/backend-app-api/src/alpha/featureDiscoveryServiceFactory.test.ts @@ -95,7 +95,7 @@ describe('featureDiscoveryServiceFactory', () => { const fn = jest.fn().mockResolvedValue({}); await startTestBackend({ - services: [ + features: [ createServiceFactory({ service: coreServices.identity, deps: {}, diff --git a/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts b/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts index 7af9de44da..d771c5dd11 100644 --- a/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts +++ b/packages/backend-app-api/src/services/implementations/scheduler/schedulerServiceFactory.test.ts @@ -61,8 +61,7 @@ describe('schedulerFactory', () => { }); await startTestBackend({ - features: [plugin()], - services: [subject], + features: [plugin(), subject], }); }); }); diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts index b90bcf6691..791b9b1c3a 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.test.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.test.ts @@ -23,7 +23,7 @@ import { createExtensionPoint, } from '@backstage/backend-plugin-api'; import { BackendInitializer } from './BackendInitializer'; -import { ServiceRegistry } from './ServiceRegistry'; + import { lifecycleServiceFactory, loggerServiceFactory, @@ -65,7 +65,7 @@ describe('BackendInitializer', () => { const rootFactory = jest.fn(); const pluginFactory = jest.fn(); - const registry = new ServiceRegistry([ + const services = [ createServiceFactory({ service: rootRef, deps: {}, @@ -82,9 +82,9 @@ describe('BackendInitializer', () => { deps: {}, factory: () => new MockLogger(), })(), - ]); + ]; - const init = new BackendInitializer(registry); + const init = new BackendInitializer(services); await init.start(); expect(rootFactory).toHaveBeenCalled(); @@ -97,7 +97,7 @@ describe('BackendInitializer', () => { const extensionPoint = createExtensionPoint<{ values: string[] }>({ id: 'a', }); - const init = new BackendInitializer(new ServiceRegistry(baseFactories)); + const init = new BackendInitializer(baseFactories); init.add( createBackendModule({ @@ -151,7 +151,7 @@ describe('BackendInitializer', () => { }); it('should forward errors when plugins fail to start', async () => { - const init = new BackendInitializer(new ServiceRegistry([])); + const init = new BackendInitializer([]); init.add( createBackendPlugin({ pluginId: 'test', @@ -171,7 +171,7 @@ describe('BackendInitializer', () => { }); it('should forward errors when modules fail to start', async () => { - const init = new BackendInitializer(new ServiceRegistry([])); + const init = new BackendInitializer([]); init.add( createBackendModule({ pluginId: 'test', @@ -192,7 +192,7 @@ describe('BackendInitializer', () => { }); it('should reject duplicate plugins', async () => { - const init = new BackendInitializer(new ServiceRegistry([])); + const init = new BackendInitializer([]); init.add( createBackendPlugin({ pluginId: 'test', @@ -221,7 +221,7 @@ describe('BackendInitializer', () => { }); it('should reject duplicate modules', async () => { - const init = new BackendInitializer(new ServiceRegistry([])); + const init = new BackendInitializer([]); init.add( createBackendModule({ pluginId: 'test', @@ -254,16 +254,14 @@ describe('BackendInitializer', () => { it('should reject modules with circular dependencies', async () => { const extA = createExtensionPoint({ id: 'a' }); const extB = createExtensionPoint({ id: 'b' }); - const init = new BackendInitializer( - new ServiceRegistry([ - rootLifecycleServiceFactory(), - createServiceFactory({ - service: coreServices.rootLogger, - deps: {}, - factory: () => new MockLogger(), - })(), - ]), - ); + const init = new BackendInitializer([ + rootLifecycleServiceFactory(), + createServiceFactory({ + service: coreServices.rootLogger, + deps: {}, + factory: () => new MockLogger(), + })(), + ]); init.add( createBackendModule({ pluginId: 'test', @@ -296,7 +294,7 @@ describe('BackendInitializer', () => { }); it('should reject modules that depend on extension points other plugins', async () => { - const init = new BackendInitializer(new ServiceRegistry(baseFactories)); + const init = new BackendInitializer(baseFactories); const extA = createExtensionPoint({ id: 'a' }); init.add( createBackendPlugin({ diff --git a/packages/backend-app-api/src/wiring/BackendInitializer.ts b/packages/backend-app-api/src/wiring/BackendInitializer.ts index f71256d04e..93d2f6942a 100644 --- a/packages/backend-app-api/src/wiring/BackendInitializer.ts +++ b/packages/backend-app-api/src/wiring/BackendInitializer.ts @@ -19,6 +19,7 @@ import { ExtensionPoint, coreServices, ServiceRef, + ServiceFactory, } from '@backstage/backend-plugin-api'; import { BackendLifecycleImpl } from '../services/implementations/rootLifecycle/rootLifecycleServiceFactory'; import { BackendPluginLifecycleImpl } from '../services/implementations/lifecycle/lifecycleServiceFactory'; @@ -29,6 +30,7 @@ import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring import { ForwardedError, ConflictError } from '@backstage/errors'; import { featureDiscoveryServiceRef } from '@backstage/backend-plugin-api/alpha'; import { DependencyGraph } from '../lib/DependencyGraph'; +import { ServiceRegistry } from './ServiceRegistry'; export interface BackendRegisterInit { consumes: Set; @@ -46,10 +48,12 @@ export class BackendInitializer { ExtensionPoint, { impl: unknown; pluginId: string } >(); - #serviceHolder: EnumerableServiceHolder; + #serviceHolder: EnumerableServiceHolder | undefined; + #providedServiceFactories = new Array(); + #defaultApiFactories: ServiceFactory[]; - constructor(serviceHolder: EnumerableServiceHolder) { - this.#serviceHolder = serviceHolder; + constructor(defaultApiFactories: ServiceFactory[]) { + this.#defaultApiFactories = defaultApiFactories; } async #getInitDeps( @@ -69,7 +73,7 @@ export class BackendInitializer { } result.set(name, ep.impl); } else { - const impl = await this.#serviceHolder.get( + const impl = await this.#serviceHolder!.get( ref as ServiceRef, pluginId, ); @@ -104,13 +108,35 @@ export class BackendInitializer { `Failed to add feature, invalid type '${feature.$$type}'`, ); } - const internalFeature = feature as InternalBackendFeature; - if (internalFeature.version !== 'v1') { + + if (isServiceFactory(feature)) { + if (feature.service.id === coreServices.pluginMetadata.id) { + throw new Error( + `The ${coreServices.pluginMetadata.id} service cannot be overridden`, + ); + } + if ( + this.#providedServiceFactories.find( + sf => sf.service.id === feature.service.id, + ) + ) { + throw new Error( + `Duplicate service implementations provided for ${feature.service.id}`, + ); + } + this.#providedServiceFactories.push(feature); + } else if (isInternalBackendFeature(feature)) { + if (feature.version !== 'v1') { + throw new Error( + `Failed to add feature, invalid version '${feature.version}'`, + ); + } + this.#features.push(feature); + } else { throw new Error( - `Failed to add feature, invalid version '${internalFeature.version}'`, + `Failed to add feature, invalid feature ${JSON.stringify(feature)}`, ); } - this.#features.push(internalFeature); } async start(): Promise { @@ -141,6 +167,11 @@ export class BackendInitializer { } async #doStart(): Promise { + this.#serviceHolder = new ServiceRegistry([ + ...this.#defaultApiFactories, + ...this.#providedServiceFactories, + ]); + const featureDiscovery = await this.#serviceHolder.get( featureDiscoveryServiceRef, 'root', @@ -319,7 +350,7 @@ export class BackendInitializer { // Bit of a hacky way to grab the lifecycle services, potentially find a nicer way to do this async #getRootLifecycleImpl(): Promise { - const lifecycleService = await this.#serviceHolder.get( + const lifecycleService = await this.#serviceHolder!.get( coreServices.rootLifecycle, 'root', ); @@ -332,7 +363,7 @@ export class BackendInitializer { async #getPluginLifecycleImpl( pluginId: string, ): Promise { - const lifecycleService = await this.#serviceHolder.get( + const lifecycleService = await this.#serviceHolder!.get( coreServices.lifecycle, pluginId, ); @@ -342,3 +373,15 @@ export class BackendInitializer { throw new Error('Unexpected plugin lifecycle service implementation'); } } + +function isServiceFactory(feature: BackendFeature): feature is ServiceFactory { + return !!(feature as ServiceFactory).service; +} + +function isInternalBackendFeature( + feature: BackendFeature, +): feature is InternalBackendFeature { + return ( + typeof (feature as InternalBackendFeature).getRegistrations === 'function' + ); +} diff --git a/packages/backend-app-api/src/wiring/BackstageBackend.ts b/packages/backend-app-api/src/wiring/BackstageBackend.ts index c53f47b685..0ea55bc1c7 100644 --- a/packages/backend-app-api/src/wiring/BackstageBackend.ts +++ b/packages/backend-app-api/src/wiring/BackstageBackend.ts @@ -14,22 +14,19 @@ * limitations under the License. */ -import { ServiceFactory, BackendFeature } from '@backstage/backend-plugin-api'; +import { BackendFeature, ServiceFactory } from '@backstage/backend-plugin-api'; import { BackendInitializer } from './BackendInitializer'; -import { ServiceRegistry } from './ServiceRegistry'; import { Backend } from './types'; export class BackstageBackend implements Backend { - #services: ServiceRegistry; #initializer: BackendInitializer; - constructor(apiFactories: ServiceFactory[]) { - this.#services = new ServiceRegistry(apiFactories); - this.#initializer = new BackendInitializer(this.#services); + constructor(defaultServiceFactories: ServiceFactory[]) { + this.#initializer = new BackendInitializer(defaultServiceFactories); } - add(feature: BackendFeature): void { - this.#initializer.add(feature); + add(feature: BackendFeature | (() => BackendFeature)): void { + this.#initializer.add(typeof feature === 'function' ? feature() : feature); } async start(): Promise { diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts index e698ade348..b60a24c8d8 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.test.ts @@ -31,7 +31,7 @@ const sf1 = createServiceFactory({ async factory() { return { x: 1 }; }, -})(); +}); const ref2 = createServiceRef<{ x: number }>({ scope: 'root', @@ -43,14 +43,14 @@ const sf2 = createServiceFactory({ async factory() { return { x: 2 }; }, -})(); +}); const sf2b = createServiceFactory({ service: ref2, deps: {}, async factory() { return { x: 22 }; }, -})(); +}); const refDefault1 = createServiceRef<{ x: number }>({ id: '1', @@ -61,7 +61,7 @@ const refDefault1 = createServiceRef<{ x: number }>({ async factory() { return { x: 10 }; }, - })(), + }), }); const refDefault2a = createServiceRef<{ x: number }>({ @@ -95,7 +95,7 @@ describe('ServiceRegistry', () => { }); it('should return an implementation for a registered ref', async () => { - const registry = new ServiceRegistry([sf1]); + const registry = new ServiceRegistry([sf1()]); await expect(registry.get(ref1, 'catalog')).resolves.toEqual({ x: 1 }); await expect(registry.get(ref1, 'scaffolder')).resolves.toEqual({ x: 1 }); expect(await registry.get(ref1, 'catalog')).toBe( @@ -110,7 +110,7 @@ describe('ServiceRegistry', () => { }); it('should handle multiple factories with different serviceRefs', async () => { - const registry = new ServiceRegistry([sf1, sf2]); + const registry = new ServiceRegistry([sf1(), sf2()]); await expect(registry.get(ref1, 'catalog')).resolves.toEqual({ x: 1, @@ -131,7 +131,7 @@ describe('ServiceRegistry', () => { return { x: 2 }; }, }); - const registry = new ServiceRegistry([factory(), sf1]); + const registry = new ServiceRegistry([factory(), sf1()]); await expect(registry.get(ref2, 'catalog')).rejects.toThrow( "Failed to instantiate 'root' scoped service '2' because it depends on 'plugin' scoped service '1'.", ); @@ -145,7 +145,7 @@ describe('ServiceRegistry', () => { return { x: rootDep.x }; }, }); - const registry = new ServiceRegistry([factory(), sf2]); + const registry = new ServiceRegistry([factory(), sf2()]); await expect(registry.get(ref1, 'catalog')).resolves.toEqual({ x: 2, }); @@ -160,7 +160,7 @@ describe('ServiceRegistry', () => { return { x: rootDep.x }; }, }); - const registry = new ServiceRegistry([factory(), sf2]); + const registry = new ServiceRegistry([factory(), sf2()]); await expect(registry.get(ref, 'catalog')).resolves.toEqual({ x: 2, }); @@ -182,7 +182,7 @@ describe('ServiceRegistry', () => { }); it('should use the last factory for each ref', async () => { - const registry = new ServiceRegistry([sf2, sf2b]); + const registry = new ServiceRegistry([sf2(), sf2b()]); await expect(registry.get(ref2, 'catalog')).resolves.toEqual({ x: 22, }); @@ -196,7 +196,7 @@ describe('ServiceRegistry', () => { }); it('should not use the defaultFactory from the ref if provided to the registry', async () => { - const registry = new ServiceRegistry([sf1]); + const registry = new ServiceRegistry([sf1()]); await expect(registry.get(refDefault1, 'catalog')).resolves.toEqual({ x: 1, }); diff --git a/packages/backend-app-api/src/wiring/ServiceRegistry.ts b/packages/backend-app-api/src/wiring/ServiceRegistry.ts index 61f95ff4a4..b6de05b361 100644 --- a/packages/backend-app-api/src/wiring/ServiceRegistry.ts +++ b/packages/backend-app-api/src/wiring/ServiceRegistry.ts @@ -39,7 +39,7 @@ function toInternalServiceFactory( factory: ServiceFactory, ): InternalServiceFactory { const f = factory as InternalServiceFactory; - if (f.$$type !== '@backstage/ServiceFactory') { + if (f.$$type !== '@backstage/BackendFeature') { throw new Error(`Invalid service factory, bad type '${f.$$type}'`); } if (f.version !== 'v1') { diff --git a/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts b/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts index dc9a0cc085..1fd7fcbbec 100644 --- a/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts +++ b/packages/backend-app-api/src/wiring/createSpecializedBackend.test.ts @@ -22,13 +22,15 @@ import { createSpecializedBackend } from './createSpecializedBackend'; describe('createSpecializedBackend', () => { it('should create a backend without services', () => { - expect(() => createSpecializedBackend({ services: [] })).not.toThrow(); + expect(() => + createSpecializedBackend({ defaultServiceFactories: [] }), + ).not.toThrow(); }); it('should throw on duplicate service implementations', () => { expect(() => createSpecializedBackend({ - services: [ + defaultServiceFactories: [ createServiceFactory({ service: coreServices.rootLifecycle, deps: {}, @@ -55,7 +57,7 @@ describe('createSpecializedBackend', () => { it('should throw when providing a plugin metadata service implementation', () => { expect(() => createSpecializedBackend({ - services: [ + defaultServiceFactories: [ createServiceFactory({ service: coreServices.pluginMetadata, deps: {}, diff --git a/packages/backend-app-api/src/wiring/createSpecializedBackend.ts b/packages/backend-app-api/src/wiring/createSpecializedBackend.ts index 15e51f7c4c..f5c4d8b152 100644 --- a/packages/backend-app-api/src/wiring/createSpecializedBackend.ts +++ b/packages/backend-app-api/src/wiring/createSpecializedBackend.ts @@ -24,7 +24,7 @@ import { Backend, CreateSpecializedBackendOptions } from './types'; export function createSpecializedBackend( options: CreateSpecializedBackendOptions, ): Backend { - const services = options.services.map(sf => + const services = options.defaultServiceFactories.map(sf => typeof sf === 'function' ? sf() : sf, ); diff --git a/packages/backend-app-api/src/wiring/types.ts b/packages/backend-app-api/src/wiring/types.ts index ffedb40324..552a69a792 100644 --- a/packages/backend-app-api/src/wiring/types.ts +++ b/packages/backend-app-api/src/wiring/types.ts @@ -25,7 +25,7 @@ import { * @public */ export interface Backend { - add(feature: BackendFeature): void; + add(feature: BackendFeature | (() => BackendFeature)): void; start(): Promise; stop(): Promise; } @@ -34,7 +34,7 @@ export interface Backend { * @public */ export interface CreateSpecializedBackendOptions { - services: ServiceFactoryOrFunction[]; + defaultServiceFactories: ServiceFactoryOrFunction[]; } export interface ServiceHolder { diff --git a/packages/backend-defaults/api-report.md b/packages/backend-defaults/api-report.md index 6cc58de663..ab9cc5775c 100644 --- a/packages/backend-defaults/api-report.md +++ b/packages/backend-defaults/api-report.md @@ -4,14 +4,7 @@ ```ts import { Backend } from '@backstage/backend-app-api'; -import { ServiceFactoryOrFunction } from '@backstage/backend-plugin-api'; // @public (undocumented) -export function createBackend(options?: CreateBackendOptions): Backend; - -// @public (undocumented) -export interface CreateBackendOptions { - // (undocumented) - services?: ServiceFactoryOrFunction[]; -} +export function createBackend(): Backend; ``` diff --git a/packages/backend-defaults/src/CreateBackend.test.ts b/packages/backend-defaults/src/CreateBackend.test.ts index de04d4e350..0b36b57069 100644 --- a/packages/backend-defaults/src/CreateBackend.test.ts +++ b/packages/backend-defaults/src/CreateBackend.test.ts @@ -22,60 +22,63 @@ import { createBackend } from './CreateBackend'; describe('createBackend', () => { it('should not throw when overriding a default service implementation', () => { - expect(() => - createBackend({ - services: [ - createServiceFactory({ - service: coreServices.rootLifecycle, - deps: {}, - factory: async () => ({ - addStartupHook: () => {}, - addShutdownHook: () => {}, - }), + const backend = createBackend(); + + expect(() => { + backend.add( + createServiceFactory({ + service: coreServices.rootLifecycle, + deps: {}, + factory: async () => ({ + addStartupHook: () => {}, + addShutdownHook: () => {}, }), - ], - }), - ).not.toThrow(); + }), + ); + }).not.toThrow(); }); it('should throw on duplicate service implementations', () => { - expect(() => - createBackend({ - services: [ - createServiceFactory({ - service: coreServices.rootLifecycle, - deps: {}, - factory: async () => ({ - addStartupHook: () => {}, - addShutdownHook: () => {}, - }), - }), - createServiceFactory({ - service: coreServices.rootLifecycle, - deps: {}, - factory: async () => ({ - addStartupHook: () => {}, - addShutdownHook: () => {}, - }), - }), - ], + const backend = createBackend(); + + backend.add( + createServiceFactory({ + service: coreServices.rootLifecycle, + deps: {}, + factory: async () => ({ + addStartupHook: () => {}, + addShutdownHook: () => {}, + }), }), - ).toThrow( + ); + + expect(() => { + backend.add( + createServiceFactory({ + service: coreServices.rootLifecycle, + deps: {}, + factory: async () => ({ + addStartupHook: () => {}, + addShutdownHook: () => {}, + }), + }), + ); + }).toThrow( 'Duplicate service implementations provided for core.rootLifecycle', ); }); it('should throw when providing a plugin metadata service implementation', () => { + const backend = createBackend(); + expect(() => - createBackend({ - services: [ - createServiceFactory({ - service: coreServices.pluginMetadata, - deps: {}, - factory: async () => ({ getId: () => 'test' }), - }), - ], - }), + backend.add( + createServiceFactory({ + service: coreServices.pluginMetadata, + deps: {}, + factory: async () => ({ getId: () => 'test' }), + }), + ), ).toThrow('The core.pluginMetadata service cannot be overridden'); }); }); diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 3db013a290..c07d1cc38a 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -33,10 +33,6 @@ import { urlReaderServiceFactory, identityServiceFactory, } from '@backstage/backend-app-api'; -import { - ServiceFactory, - ServiceFactoryOrFunction, -} from '@backstage/backend-plugin-api'; export const defaultServiceFactories = [ cacheServiceFactory(), @@ -59,27 +55,6 @@ export const defaultServiceFactories = [ /** * @public */ -export interface CreateBackendOptions { - services?: ServiceFactoryOrFunction[]; -} - -/** - * @public - */ -export function createBackend(options?: CreateBackendOptions): Backend { - const services = new Array(); - - // Highest priority: Services passed directly to createBackend - const providedServices = (options?.services ?? []).map(sf => - typeof sf === 'function' ? sf() : sf, - ); - services.push(...providedServices); - - // Lowest priority: Default services that are not already provided by environment or directly to createBackend - const defaultServices = defaultServiceFactories.filter( - sf => !services.some(({ service }) => service.id === sf.service.id), - ); - services.push(...defaultServices); - - return createSpecializedBackend({ services }); +export function createBackend(): Backend { + return createSpecializedBackend({ defaultServiceFactories }); } diff --git a/packages/backend-defaults/src/index.ts b/packages/backend-defaults/src/index.ts index 833878744e..d3e36cf0fb 100644 --- a/packages/backend-defaults/src/index.ts +++ b/packages/backend-defaults/src/index.ts @@ -25,5 +25,4 @@ // TODO(Rugvip): Remove this once backend-common is no longer used by backend-app-api import '@backstage/backend-common'; -export type { CreateBackendOptions } from './CreateBackend'; export { createBackend } from './CreateBackend'; diff --git a/packages/backend-plugin-api/api-report.md b/packages/backend-plugin-api/api-report.md index 0789168926..17cc521499 100644 --- a/packages/backend-plugin-api/api-report.md +++ b/packages/backend-plugin-api/api-report.md @@ -409,9 +409,7 @@ export type SearchResponseFile = { export interface ServiceFactory< TService = unknown, TScope extends 'plugin' | 'root' = 'plugin' | 'root', -> { - // (undocumented) - $$type: '@backstage/ServiceFactory'; +> extends BackendFeature { // (undocumented) service: ServiceRef; } diff --git a/packages/backend-plugin-api/src/index.ts b/packages/backend-plugin-api/src/index.ts index 452fa046f9..8e0b23d20b 100644 --- a/packages/backend-plugin-api/src/index.ts +++ b/packages/backend-plugin-api/src/index.ts @@ -21,4 +21,5 @@ */ export * from './services'; +export type { BackendFeature } from './types'; export * from './wiring'; diff --git a/packages/backend-plugin-api/src/services/system/types.ts b/packages/backend-plugin-api/src/services/system/types.ts index 9465d4a9cb..bea53dc1ed 100644 --- a/packages/backend-plugin-api/src/services/system/types.ts +++ b/packages/backend-plugin-api/src/services/system/types.ts @@ -14,6 +14,8 @@ * limitations under the License. */ +import { BackendFeature } from '../../types'; + /** * TODO * @@ -51,9 +53,7 @@ export type ServiceRef< export interface ServiceFactory< TService = unknown, TScope extends 'plugin' | 'root' = 'plugin' | 'root', -> { - $$type: '@backstage/ServiceFactory'; - +> extends BackendFeature { service: ServiceRef; } @@ -248,7 +248,7 @@ export function createServiceFactory< if (anyConf.service.scope === 'root') { const c = anyConf as RootServiceFactoryConfig; return { - $$type: '@backstage/ServiceFactory', + $$type: '@backstage/BackendFeature', version: 'v1', service: c.service, deps: c.deps, @@ -262,7 +262,7 @@ export function createServiceFactory< TDeps >; return { - $$type: '@backstage/ServiceFactory', + $$type: '@backstage/BackendFeature', version: 'v1', service: c.service, ...('createRootContext' in c diff --git a/packages/backend-plugin-api/src/types.ts b/packages/backend-plugin-api/src/types.ts new file mode 100644 index 0000000000..59f1106fab --- /dev/null +++ b/packages/backend-plugin-api/src/types.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2023 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. + */ + +/** @internal */ +export interface BackendFeatureFactory< + TOptions extends [options?: object] = [], +> { + (...options: TOptions): BackendFeature; + $$type: '@backstage/BackendFeatureFactory'; +} + +/** @public */ +export interface BackendFeature { + // NOTE: This type is opaque in order to simplify future API evolution. + $$type: '@backstage/BackendFeature'; +} diff --git a/packages/backend-plugin-api/src/wiring/factories.ts b/packages/backend-plugin-api/src/wiring/factories.ts index af40256411..9fa0f87bab 100644 --- a/packages/backend-plugin-api/src/wiring/factories.ts +++ b/packages/backend-plugin-api/src/wiring/factories.ts @@ -14,14 +14,13 @@ * limitations under the License. */ +import { BackendFeature, BackendFeatureFactory } from '../types'; import { BackendModuleRegistrationPoints, BackendPluginRegistrationPoints, ExtensionPoint, InternalBackendModuleRegistration, InternalBackendPluginRegistration, - BackendFeatureFactory, - BackendFeature, } from './types'; /** diff --git a/packages/backend-plugin-api/src/wiring/index.ts b/packages/backend-plugin-api/src/wiring/index.ts index 9cb767b8ac..49f15c0b55 100644 --- a/packages/backend-plugin-api/src/wiring/index.ts +++ b/packages/backend-plugin-api/src/wiring/index.ts @@ -27,6 +27,5 @@ export { export type { BackendModuleRegistrationPoints, BackendPluginRegistrationPoints, - BackendFeature, ExtensionPoint, } from './types'; diff --git a/packages/backend-plugin-api/src/wiring/types.ts b/packages/backend-plugin-api/src/wiring/types.ts index d416ce7f9a..55d43ccb7c 100644 --- a/packages/backend-plugin-api/src/wiring/types.ts +++ b/packages/backend-plugin-api/src/wiring/types.ts @@ -15,6 +15,7 @@ */ import { ServiceRef } from '../services/system/types'; +import { BackendFeature } from '../types'; /** * TODO @@ -71,18 +72,6 @@ export interface BackendModuleRegistrationPoints { }): void; } -/** @internal */ -export interface BackendFeatureFactory { - (): BackendFeature; - $$type: '@backstage/BackendFeatureFactory'; -} - -/** @public */ -export interface BackendFeature { - // NOTE: This type is opaque in order to simplify future API evolution. - $$type: '@backstage/BackendFeature'; -} - /** @internal */ export interface InternalBackendFeature extends BackendFeature { version: 'v1'; diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 1cb7a83a0e..d086b1d2ae 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -21,7 +21,6 @@ import { RootConfigService } from '@backstage/backend-plugin-api'; import { RootLifecycleService } from '@backstage/backend-plugin-api'; import { SchedulerService } from '@backstage/backend-plugin-api'; import { ServiceFactory } from '@backstage/backend-plugin-api'; -import { ServiceRef } from '@backstage/backend-plugin-api'; import { TokenManagerService } from '@backstage/backend-plugin-api'; import { UrlReaderService } from '@backstage/backend-plugin-api'; @@ -127,11 +126,8 @@ export function setupRequestMockHandlers(worker: { }): void; // @public (undocumented) -export function startTestBackend< - TServices extends any[], - TExtensionPoints extends any[], ->( - options: TestBackendOptions, +export function startTestBackend( + options: TestBackendOptions, ): Promise; // @public (undocumented) @@ -140,10 +136,7 @@ export interface TestBackend extends Backend { } // @public (undocumented) -export interface TestBackendOptions< - TServices extends any[], - TExtensionPoints extends any[], -> { +export interface TestBackendOptions { // (undocumented) extensionPoints?: readonly [ ...{ @@ -154,16 +147,7 @@ export interface TestBackendOptions< }, ]; // (undocumented) - features?: BackendFeature[]; - // (undocumented) - services?: readonly [ - ...{ - [index in keyof TServices]: - | ServiceFactory - | (() => ServiceFactory) - | [ServiceRef, Partial]; - }, - ]; + features?: Array BackendFeature)>; } // @public 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 13b57f54ba..b127712927 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.test.ts @@ -31,7 +31,6 @@ import { startTestBackend } from './TestBackend'; let globalTestBackendHasBeenStopped = false; beforeAll(async () => { await startTestBackend({ - services: [], features: [ createBackendModule({ moduleId: 'test.module', @@ -46,7 +45,7 @@ beforeAll(async () => { }, }); }, - })(), + }), ], }); }); @@ -68,17 +67,37 @@ describe('TestBackend', () => { const extensionPoint5 = createExtensionPoint({ id: 'b5' }); await expect( startTestBackend({ - services: [ + features: [ // @ts-expect-error [extensionPoint1, { a: 'a' }], - [serviceRef, { a: 'a' }], - [serviceRef, { a: 'a', b: 'b' }], - // @ts-expect-error - [serviceRef, { c: 'c' }], - // @ts-expect-error - [serviceRef, { a: 'a', c: 'c' }], - // @ts-expect-error - [serviceRef, { a: 'a', b: 'b', c: 'c' }], + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + // @ts-expect-error + factory: async () => ({ a: 'a' }), + })), + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + factory: async () => ({ a: 'a', b: 'b' }), + })), + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + // @ts-expect-error + factory: async () => ({ c: 'c' }), + })), + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + // @ts-expect-error + factory: async () => ({ a: 'a', c: 'c' }), + })), + createServiceFactory(() => ({ + service: serviceRef, + deps: {}, + factory: async () => ({ a: 'a', b: 'b', c: 'c' }), + })), ], extensionPoints: [ // @ts-expect-error @@ -124,8 +143,7 @@ describe('TestBackend', () => { }); await startTestBackend({ - services: [sf], - features: [testModule()], + features: [testModule(), sf()], }); expect(testFn).toHaveBeenCalledWith('winning'); @@ -150,7 +168,6 @@ describe('TestBackend', () => { }); const backend = await startTestBackend({ - services: [], features: [testModule()], }); @@ -192,7 +209,6 @@ describe('TestBackend', () => { }); await startTestBackend({ - services: [], features: [testPlugin()], }); }); @@ -244,7 +260,7 @@ describe('TestBackend', () => { }, }); }, - })(), + }), createBackendModule({ pluginId: 'testB', moduleId: 'test', @@ -256,7 +272,7 @@ describe('TestBackend', () => { }, }); }, - })(), + }), ], }), ).resolves.not.toBeUndefined(); @@ -277,7 +293,7 @@ describe('TestBackend', () => { async init() {}, }); }, - })(), + }), createBackendModule({ pluginId: 'testB', moduleId: 'test', @@ -287,7 +303,7 @@ describe('TestBackend', () => { async init() {}, }); }, - })(), + }), ], }), ).rejects.toThrow( diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 06e27e5c07..97da3543ae 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -24,8 +24,6 @@ import { } from '@backstage/backend-app-api'; import { HostDiscovery } from '@backstage/backend-common'; import { - ServiceFactory, - ServiceRef, createServiceFactory, BackendFeature, ExtensionPoint, @@ -40,18 +38,7 @@ import express from 'express'; import { InternalBackendFeature } from '@backstage/backend-plugin-api/src/wiring/types'; /** @public */ -export interface TestBackendOptions< - TServices extends any[], - TExtensionPoints extends any[], -> { - services?: readonly [ - ...{ - [index in keyof TServices]: - | ServiceFactory - | (() => ServiceFactory) - | [ServiceRef, Partial]; - }, - ]; +export interface TestBackendOptions { extensionPoints?: readonly [ ...{ [index in keyof TExtensionPoints]: [ @@ -60,7 +47,7 @@ export interface TestBackendOptions< ]; }, ]; - features?: BackendFeature[]; + features?: Array BackendFeature)>; } /** @public */ @@ -95,29 +82,37 @@ const defaultServiceFactories = [ * @returns */ function createExtensionPointTestModules( - features: BackendFeature[], + features: Array BackendFeature)>, extensionPointTuples?: readonly [ ref: ExtensionPoint, impl: unknown, ][], -): BackendFeature[] { +): Array<() => BackendFeature> { if (!extensionPointTuples) { return []; } - const registrations = features.flatMap(feature => { + const registrations = features.flatMap(featureOrFunction => { + const feature = + typeof featureOrFunction === 'function' + ? featureOrFunction() + : featureOrFunction; + if (feature.$$type !== '@backstage/BackendFeature') { throw new Error( `Failed to add feature, invalid type '${feature.$$type}'`, ); } - const internalFeature = feature as InternalBackendFeature; - if (internalFeature.version !== 'v1') { - throw new Error( - `Failed to add feature, invalid version '${internalFeature.version}'`, - ); + + if (isInternalBackendFeature(feature)) { + if (feature.version !== 'v1') { + throw new Error( + `Failed to add feature, invalid version '${feature.version}'`, + ); + } + return feature.getRegistrations(); } - return internalFeature.getRegistrations(); + return []; }); const extensionPointMap = new Map( @@ -170,7 +165,7 @@ function createExtensionPointTestModules( reg.registerInit({ deps: {}, async init() {} }); }, - })(), + }), ); } @@ -180,18 +175,10 @@ function createExtensionPointTestModules( const backendInstancesToCleanUp = new Array(); /** @public */ -export async function startTestBackend< - TServices extends any[], - TExtensionPoints extends any[], ->( - options: TestBackendOptions, +export async function startTestBackend( + options: TestBackendOptions, ): Promise { - const { - services = [], - extensionPoints, - features = [], - ...otherOptions - } = options; + const { extensionPoints, features = [], ...otherOptions } = options; let server: ExtendedHttpServer; @@ -247,39 +234,13 @@ export async function startTestBackend< }, }); - const factories = services.map(serviceDef => { - if (Array.isArray(serviceDef)) { - // if type is ExtensionPoint? - // do something differently? - const [ref, impl] = serviceDef; - if (ref.scope === 'plugin') { - return createServiceFactory({ - service: ref as ServiceRef, - deps: {}, - factory: async () => impl, - })(); - } - return createServiceFactory({ - service: ref as ServiceRef, - deps: {}, - factory: async () => impl, - })(); - } - if (typeof serviceDef === 'function') { - return serviceDef(); - } - return serviceDef as ServiceFactory; - }); - - for (const factory of defaultServiceFactories) { - if (!factories.some(f => f.service.id === factory.service.id)) { - factories.push(factory); - } - } - const backend = createSpecializedBackend({ ...otherOptions, - services: [...factories, rootHttpRouterFactory, discoveryFactory], + defaultServiceFactories: [ + ...defaultServiceFactories, + rootHttpRouterFactory, + discoveryFactory, + ], }); backendInstancesToCleanUp.push(backend); @@ -329,3 +290,11 @@ function registerTestHooks() { } registerTestHooks(); + +function isInternalBackendFeature( + feature: BackendFeature, +): feature is InternalBackendFeature { + return ( + typeof (feature as InternalBackendFeature).getRegistrations === 'function' + ); +} diff --git a/plugins/app-backend/src/service/appPlugin.test.ts b/plugins/app-backend/src/service/appPlugin.test.ts index 37d38663ef..b6a972b4c7 100644 --- a/plugins/app-backend/src/service/appPlugin.test.ts +++ b/plugins/app-backend/src/service/appPlugin.test.ts @@ -39,8 +39,8 @@ describe('appPlugin', () => { it('boots', async () => { const { server } = await startTestBackend({ - features: [appPlugin()], - services: [ + features: [ + appPlugin(), mockServices.rootConfig.factory({ data: { app: { diff --git a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts index 7599f8446f..c9fea8aa28 100644 --- a/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts +++ b/plugins/catalog-backend-module-aws/src/module/catalogModuleAwsS3EntityProvider.test.ts @@ -15,13 +15,15 @@ */ import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleAwsS3EntityProvider } from './catalogModuleAwsS3EntityProvider'; @@ -45,7 +47,7 @@ describe('catalogModuleAwsS3EntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { awsS3: { @@ -57,16 +59,24 @@ describe('catalogModuleAwsS3EntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleAwsS3EntityProvider(), + mockServices.rootConfig.factory({ data: config }), + createServiceFactory(() => ({ + service: coreServices.logger, + deps: {}, + factory: getVoidLogger, + }))(), + createServiceFactory(() => ({ + service: coreServices.scheduler, + deps: {}, + factory: () => scheduler, + }))(), ], - features: [catalogModuleAwsS3EntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts index e3140f4583..3147a0871b 100644 --- a/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts +++ b/plugins/catalog-backend-module-azure/src/module/catalogModuleAzureDevOpsEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleAzureDevOpsEntityProvider } from './catalogModuleAzureDevOpsEntityProvider'; @@ -45,7 +46,7 @@ describe('catalogModuleAzureDevOpsEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { azureDevOps: { @@ -60,16 +61,20 @@ describe('catalogModuleAzureDevOpsEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleAzureDevOpsEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + mockServices.logger.factory(), + createServiceFactory(() => ({ + deps: {}, + service: coreServices.scheduler, + factory: async () => scheduler, + })), ], - features: [catalogModuleAzureDevOpsEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts index b46304d4e3..83769fc3f5 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/module/catalogModuleBitbucketCloudEntityProvider.test.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, @@ -55,7 +58,8 @@ describe('catalogModuleBitbucketCloudEntityProvider', () => { [catalogProcessingExtensionPoint, catalogExtensionPointImpl], [eventsExtensionPoint, eventsExtensionPointImpl], ], - services: [ + features: [ + catalogModuleBitbucketCloudEntityProvider(), mockServices.rootConfig.factory({ data: { catalog: { @@ -71,9 +75,12 @@ describe('catalogModuleBitbucketCloudEntityProvider', () => { }, }, }), - [coreServices.scheduler, scheduler], + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: async () => scheduler, + }), ], - features: [catalogModuleBitbucketCloudEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts index f072823052..ae4a636008 100644 --- a/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts +++ b/plugins/catalog-backend-module-bitbucket-server/src/module/catalogModuleBitbucketServerEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { ConfigReader } from '@backstage/config'; -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { catalogModuleBitbucketServerEntityProvider } from './catalogModuleBitbucketServerEntityProvider'; import { Duration } from 'luxon'; @@ -45,7 +46,7 @@ describe('catalogModuleBitbucketServerEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { bitbucketServer: { @@ -64,16 +65,20 @@ describe('catalogModuleBitbucketServerEntityProvider', () => { }, ], }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleBitbucketServerEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + mockServices.logger.factory(), + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: async () => scheduler, + }), ], - features: [catalogModuleBitbucketServerEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts index 464837124f..9807814f61 100644 --- a/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gerrit/src/module/catalogModuleGerritEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleGerritEntityProvider } from './catalogModuleGerritEntityProvider'; @@ -45,7 +46,7 @@ describe('catalogModuleGerritEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { gerrit: { @@ -70,16 +71,20 @@ describe('catalogModuleGerritEntityProvider', () => { }, ], }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleGerritEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + mockServices.logger.factory(), + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: async () => scheduler, + }), ], - features: [catalogModuleGerritEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts index ca82e58e26..9e36966eec 100644 --- a/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts +++ b/plugins/catalog-backend-module-github/src/module/catalogModuleGithubEntityProvider.test.ts @@ -14,18 +14,19 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleGithubEntityProvider } from './catalogModuleGithubEntityProvider'; import { GithubEntityProvider } from '../providers/GithubEntityProvider'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; describe('catalogModuleGithubEntityProvider', () => { it('should register provider at the catalog extension point', async () => { @@ -45,7 +46,7 @@ describe('catalogModuleGithubEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { github: { @@ -57,16 +58,19 @@ describe('catalogModuleGithubEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleGithubEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: async () => scheduler, + }), ], - features: [catalogModuleGithubEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts index da11601f09..22759cafa0 100644 --- a/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts +++ b/plugins/catalog-backend-module-gitlab/src/module/catalogModuleGitlabDiscoveryEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleGitlabDiscoveryEntityProvider } from './catalogModuleGitlabDiscoveryEntityProvider'; @@ -45,7 +46,7 @@ describe('catalogModuleGitlabDiscoveryEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { integrations: { gitlab: [ { @@ -69,16 +70,20 @@ describe('catalogModuleGitlabDiscoveryEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleGitlabDiscoveryEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + mockServices.logger.factory(), + createServiceFactory({ + deps: {}, + service: coreServices.scheduler, + factory: async () => scheduler, + }), ], - features: [catalogModuleGitlabDiscoveryEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('P1M')); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts index 7c3dfdf226..ed0c776fa8 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/module/catalogModuleIncrementalIngestionEntityProvider.test.ts @@ -14,13 +14,12 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; import { coreServices, createBackendModule, + createServiceFactory, } from '@backstage/backend-plugin-api'; import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { IncrementalEntityProvider } from '../types'; import { @@ -43,26 +42,16 @@ describe('catalogModuleIncrementalIngestionEntityProvider', () => { const addEntityProvider = jest.fn(); const httpRouterUse = jest.fn(); - const scheduler = {}; - const database = { - getClient: jest.fn(), - }; - const httpRouter = { - use: httpRouterUse, - }; - await startTestBackend({ extensionPoints: [ [catalogProcessingExtensionPoint, { addEntityProvider }], ], - services: [ - [coreServices.rootConfig, new ConfigReader({})], - [coreServices.database, database], - [coreServices.httpRouter, httpRouter], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], - ], features: [ + createServiceFactory({ + service: coreServices.httpRouter, + deps: {}, + factory: () => ({ use: httpRouterUse }), + }), catalogModuleIncrementalIngestionEntityProvider(), createBackendModule({ pluginId: 'catalog', @@ -82,7 +71,7 @@ describe('catalogModuleIncrementalIngestionEntityProvider', () => { }, }); }, - })(), + }), ], }); diff --git a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts index be1a6dcfc0..cfb4c20def 100644 --- a/plugins/catalog-backend-module-incremental-ingestion/src/run.ts +++ b/plugins/catalog-backend-module-incremental-ingestion/src/run.ts @@ -55,16 +55,15 @@ async function main() { }, }; - const backend = createBackend({ - services: [ - createServiceFactory({ - service: coreServices.rootConfig, - deps: {}, - factory: () => new ConfigReader(config), - }), - ], - }); + const backend = createBackend(); + backend.add( + createServiceFactory({ + service: coreServices.rootConfig, + deps: {}, + factory: () => new ConfigReader(config), + }), + ); backend.add(catalogPlugin()); backend.add(catalogModuleIncrementalIngestionEntityProvider()); backend.add( @@ -86,7 +85,7 @@ async function main() { }, }); }, - })(), + }), ); await backend.start(); diff --git a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts index 9f1a4ead8b..96fec41cbe 100644 --- a/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts +++ b/plugins/catalog-backend-module-msgraph/src/module/catalogModuleMicrosoftGraphOrgEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { Duration } from 'luxon'; import { catalogModuleMicrosoftGraphOrgEntityProvider } from './catalogModuleMicrosoftGraphOrgEntityProvider'; @@ -45,7 +46,7 @@ describe('catalogModuleMicrosoftGraphOrgEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { microsoftGraphOrg: { @@ -62,16 +63,19 @@ describe('catalogModuleMicrosoftGraphOrgEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModuleMicrosoftGraphOrgEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + createServiceFactory(() => ({ + deps: {}, + service: coreServices.scheduler, + factory: async () => scheduler, + })), ], - features: [catalogModuleMicrosoftGraphOrgEntityProvider()], }); expect(usedSchedule?.frequency).toEqual(Duration.fromISO('PT30M')); diff --git a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts index c167035917..3ea54d8c8f 100644 --- a/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts +++ b/plugins/catalog-backend-module-puppetdb/src/module/catalogModulePuppetDbEntityProvider.test.ts @@ -14,14 +14,15 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; +import { + coreServices, + createServiceFactory, +} from '@backstage/backend-plugin-api'; import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha'; import { catalogModulePuppetDbEntityProvider } from './catalogModulePuppetDbEntityProvider'; import { PuppetDbEntityProvider } from '../providers/PuppetDbEntityProvider'; @@ -44,7 +45,7 @@ describe('catalogModulePuppetDbEntityProvider', () => { }, } as unknown as PluginTaskScheduler; - const config = new ConfigReader({ + const config = { catalog: { providers: { puppetdb: { @@ -56,16 +57,19 @@ describe('catalogModulePuppetDbEntityProvider', () => { }, }, }, - }); + }; await startTestBackend({ extensionPoints: [[catalogProcessingExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + catalogModulePuppetDbEntityProvider(), + mockServices.rootConfig.factory({ data: config }), + createServiceFactory(() => ({ + deps: {}, + service: coreServices.scheduler, + factory: async () => scheduler, + })), ], - features: [catalogModulePuppetDbEntityProvider()], }); expect(usedSchedule?.frequency).toEqual({ minutes: 10 }); diff --git a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts index 9cb20d557d..fb2bd06b96 100644 --- a/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts +++ b/plugins/catalog-backend/src/tests/performance/stitchingPerformance.test.ts @@ -180,7 +180,6 @@ describePerformanceTest('stitchingPerformance', () => { const tracker = new Tracker(knex, load); const backend = await startTestBackend({ - services: [staticDatabase(knex)], features: [ catalogPlugin(), createBackendModule({ @@ -201,7 +200,8 @@ describePerformanceTest('stitchingPerformance', () => { }, }); }, - })(), + }), + staticDatabase(knex), ], }); diff --git a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts index 849ad733de..a76817c3c0 100644 --- a/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts +++ b/plugins/events-backend-module-aws-sqs/src/service/eventsModuleAwsSqsConsumingEventPublisher.test.ts @@ -14,10 +14,12 @@ * limitations under the License. */ -import { getVoidLogger } from '@backstage/backend-common'; -import { coreServices } from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { + coreServices, + createServiceFactory, + SchedulerService, +} from '@backstage/backend-plugin-api'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { TestEventBroker } from '@backstage/plugin-events-backend-test-utils'; import { eventsModuleAwsSqsConsumingEventPublisher } from './eventsModuleAwsSqsConsumingEventPublisher'; @@ -25,31 +27,6 @@ import { AwsSqsConsumingEventPublisher } from '../publisher/AwsSqsConsumingEvent describe('eventsModuleAwsSqsConsumingEventPublisher', () => { it('should be correctly wired and set up', async () => { - const config = new ConfigReader({ - events: { - modules: { - awsSqs: { - awsSqsConsumingEventPublisher: { - topics: { - fake1: { - queue: { - region: 'eu-west-1', - url: 'https://fake1.queue.url', - }, - }, - fake2: { - queue: { - region: 'us-east-1', - url: 'https://fake2.queue.url', - }, - }, - }, - }, - }, - }, - }, - }); - let addedPublishers: AwsSqsConsumingEventPublisher[] | undefined; const extensionPoint = { addPublishers: (publishers: any) => { @@ -59,16 +36,44 @@ describe('eventsModuleAwsSqsConsumingEventPublisher', () => { const scheduler = { scheduleTask: jest.fn(), - }; + } as unknown as SchedulerService; await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [ - [coreServices.rootConfig, config], - [coreServices.logger, getVoidLogger()], - [coreServices.scheduler, scheduler], + features: [ + eventsModuleAwsSqsConsumingEventPublisher(), + mockServices.rootConfig.factory({ + data: { + events: { + modules: { + awsSqs: { + awsSqsConsumingEventPublisher: { + topics: { + fake1: { + queue: { + region: 'eu-west-1', + url: 'https://fake1.queue.url', + }, + }, + fake2: { + queue: { + region: 'us-east-1', + url: 'https://fake2.queue.url', + }, + }, + }, + }, + }, + }, + }, + }, + }), + createServiceFactory({ + service: coreServices.scheduler, + deps: {}, + factory: () => scheduler, + }), ], - features: [eventsModuleAwsSqsConsumingEventPublisher()], }); expect(addedPublishers).not.toBeUndefined(); diff --git a/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.test.ts b/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.test.ts index 1ff756a2d2..d67b5eb071 100644 --- a/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.test.ts +++ b/plugins/events-backend-module-azure/src/service/eventsModuleAzureDevOpsEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleAzureDevOpsEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleAzureDevOpsEventRouter()], }); diff --git a/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.test.ts b/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.test.ts index 17d2252c7b..025d994b4b 100644 --- a/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.test.ts +++ b/plugins/events-backend-module-bitbucket-cloud/src/service/eventsModuleBitbucketCloudEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleBitbucketCloudEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleBitbucketCloudEventRouter()], }); diff --git a/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.test.ts b/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.test.ts index 88ef995966..c11f4c42db 100644 --- a/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.test.ts +++ b/plugins/events-backend-module-gerrit/src/service/eventsModuleGerritEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleGerritEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleGerritEventRouter()], }); diff --git a/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.test.ts b/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.test.ts index bfa186c7bc..02151d0dcf 100644 --- a/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.test.ts +++ b/plugins/events-backend-module-github/src/service/eventsModuleGithubEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleGithubEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleGithubEventRouter()], }); diff --git a/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.test.ts b/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.test.ts index f5bb07f0d6..4effa62dd0 100644 --- a/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.test.ts +++ b/plugins/events-backend-module-github/src/service/eventsModuleGithubWebhook.test.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { coreServices } from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { HttpPostIngressOptions, @@ -47,20 +45,22 @@ describe('eventsModuleGithubWebhook', () => { }, }; - const config = new ConfigReader({ - events: { - modules: { - github: { - webhookSecret: secret, - }, - }, - }, - }); - await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [[coreServices.rootConfig, config]], - features: [eventsModuleGithubWebhook()], + features: [ + eventsModuleGithubWebhook(), + mockServices.rootConfig.factory({ + data: { + events: { + modules: { + github: { + webhookSecret: secret, + }, + }, + }, + }, + }), + ], }); expect(addedIngress).not.toBeUndefined(); diff --git a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.test.ts b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.test.ts index 86a0df6e68..34a68ccbe4 100644 --- a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.test.ts +++ b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabEventRouter.test.ts @@ -34,7 +34,6 @@ describe('eventsModuleGitlabEventRouter', () => { await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [], features: [eventsModuleGitlabEventRouter()], }); diff --git a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.test.ts b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.test.ts index 92e803c439..1ab116ee3d 100644 --- a/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.test.ts +++ b/plugins/events-backend-module-gitlab/src/service/eventsModuleGitlabWebhook.test.ts @@ -14,9 +14,7 @@ * limitations under the License. */ -import { coreServices } from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; -import { ConfigReader } from '@backstage/config'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { HttpPostIngressOptions, @@ -42,20 +40,22 @@ describe('gitlabWebhookEventsModule', () => { }, }; - const config = new ConfigReader({ - events: { - modules: { - gitlab: { - webhookSecret: 'test-secret', - }, - }, - }, - }); - await startTestBackend({ extensionPoints: [[eventsExtensionPoint, extensionPoint]], - services: [[coreServices.rootConfig, config]], - features: [eventsModuleGitlabWebhook()], + features: [ + eventsModuleGitlabWebhook(), + mockServices.rootConfig.factory({ + data: { + events: { + modules: { + gitlab: { + webhookSecret: 'test-secret', + }, + }, + }, + }, + }), + ], }); expect(addedIngress).not.toBeUndefined(); diff --git a/plugins/events-backend/src/service/EventsPlugin.test.ts b/plugins/events-backend/src/service/EventsPlugin.test.ts index bce45c9ef3..e65147ebbb 100644 --- a/plugins/events-backend/src/service/EventsPlugin.test.ts +++ b/plugins/events-backend/src/service/EventsPlugin.test.ts @@ -14,13 +14,13 @@ * limitations under the License. */ -import { errorHandler, getVoidLogger } from '@backstage/backend-common'; -import { ConfigReader } from '@backstage/config'; +import { errorHandler } from '@backstage/backend-common'; import { coreServices, createBackendModule, + createServiceFactory, } from '@backstage/backend-plugin-api'; -import { startTestBackend } from '@backstage/backend-test-utils'; +import { mockServices, startTestBackend } from '@backstage/backend-test-utils'; import { eventsExtensionPoint } from '@backstage/plugin-events-node/alpha'; import { TestEventBroker, @@ -38,14 +38,6 @@ describe('eventPlugin', () => { const publisher = new TestEventPublisher(); const subscriber = new TestEventSubscriber('sub', ['fake']); - const config = new ConfigReader({ - events: { - http: { - topics: ['fake'], - }, - }, - }); - const httpRouter = Router(); httpRouter.use(express.json()); httpRouter.use(errorHandler()); @@ -70,12 +62,25 @@ describe('eventPlugin', () => { await startTestBackend({ extensionPoints: [], - services: [ - [coreServices.rootConfig, config], - [coreServices.httpRouter, httpRouter], - [coreServices.logger, getVoidLogger()], + features: [ + eventsPlugin(), + testModule(), + mockServices.logger.factory(), + mockServices.rootConfig.factory({ + data: { + events: { + http: { + topics: ['fake'], + }, + }, + }, + }), + createServiceFactory({ + service: coreServices.httpRouter, + deps: {}, + factory: async () => httpRouter, + }), ], - features: [eventsPlugin(), testModule()], }); expect(publisher.eventBroker).toBe(eventBroker); diff --git a/plugins/search-backend-module-catalog/src/alpha.test.ts b/plugins/search-backend-module-catalog/src/alpha.test.ts index edd922b7fb..33ac978d41 100644 --- a/plugins/search-backend-module-catalog/src/alpha.test.ts +++ b/plugins/search-backend-module-catalog/src/alpha.test.ts @@ -49,8 +49,8 @@ describe('searchModuleCatalogCollator', () => { }, ], ], - features: [searchModuleCatalogCollator()], - services: [ + features: [ + searchModuleCatalogCollator(), mockServices.rootConfig.factory({ data: { search: { diff --git a/plugins/search-backend-module-explore/src/alpha.test.ts b/plugins/search-backend-module-explore/src/alpha.test.ts index b7a44e4898..4505f86c5e 100644 --- a/plugins/search-backend-module-explore/src/alpha.test.ts +++ b/plugins/search-backend-module-explore/src/alpha.test.ts @@ -34,8 +34,8 @@ describe('searchModuleExploreCollator', () => { extensionPoints: [ [searchIndexRegistryExtensionPoint, extensionPointMock], ], - features: [searchModuleExploreCollator()], - services: [ + features: [ + searchModuleExploreCollator(), mockServices.rootConfig.factory({ data: { search: { diff --git a/plugins/search-backend-module-techdocs/src/alpha.test.ts b/plugins/search-backend-module-techdocs/src/alpha.test.ts index 1e7ef494bb..d65a77a765 100644 --- a/plugins/search-backend-module-techdocs/src/alpha.test.ts +++ b/plugins/search-backend-module-techdocs/src/alpha.test.ts @@ -34,8 +34,8 @@ describe('searchModuleTechDocsCollator', () => { extensionPoints: [ [searchIndexRegistryExtensionPoint, extensionPointMock], ], - features: [searchModuleTechDocsCollator()], - services: [ + features: [ + searchModuleTechDocsCollator(), mockServices.rootConfig.factory({ data: { search: {