diff --git a/.changeset/twenty-parents-relate.md b/.changeset/twenty-parents-relate.md new file mode 100644 index 0000000000..a883873c16 --- /dev/null +++ b/.changeset/twenty-parents-relate.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-test-utils': patch +--- + +All mock service factories and mock service implementations are now available via the new experimental `mockServices` export. diff --git a/packages/backend-defaults/src/CreateBackend.test.ts b/packages/backend-defaults/src/CreateBackend.test.ts index 35b3a7decf..2cfb92c3a6 100644 --- a/packages/backend-defaults/src/CreateBackend.test.ts +++ b/packages/backend-defaults/src/CreateBackend.test.ts @@ -21,7 +21,7 @@ import { createServiceRef, createSharedEnvironment, } from '@backstage/backend-plugin-api'; -import { mockConfigFactory } from '@backstage/backend-test-utils'; +import { mockServices } from '@backstage/backend-test-utils'; import { createBackend } from './CreateBackend'; const fooServiceRef = createServiceRef({ id: 'foo', scope: 'root' }); @@ -112,7 +112,7 @@ describe('createBackend', () => { }; }, }), - mockConfigFactory({ + mockServices.config.factory({ data: { root: 'root-env' }, }), createServiceFactory({ diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 8ff29f8545..232f7e8136 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -5,25 +5,150 @@ ```ts import { Backend } from '@backstage/backend-app-api'; import { BackendFeature } from '@backstage/backend-plugin-api'; +import { CacheService } from '@backstage/backend-plugin-api'; +import { ConfigReader } from '@backstage/config'; import { ConfigService } from '@backstage/backend-plugin-api'; +import { DatabaseService } from '@backstage/backend-plugin-api'; import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; +import { HttpRouterFactoryOptions } from '@backstage/backend-app-api'; +import { HttpRouterService } from '@backstage/backend-plugin-api'; +import { IdentityService } from '@backstage/backend-plugin-api'; import { JsonObject } from '@backstage/types'; import { Knex } from 'knex'; +import { LifecycleService } from '@backstage/backend-plugin-api'; +import { LoggerService } from '@backstage/backend-plugin-api'; +import { PermissionsService } from '@backstage/backend-plugin-api'; +import { RootLifecycleService } from '@backstage/backend-plugin-api'; +import { RootLoggerService } 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'; // @public (undocumented) export function isDockerDisabledForTests(): boolean; // @alpha (undocumented) -export const mockConfigFactory: ( - options?: - | { - data?: JsonObject | undefined; - } - | undefined, -) => ServiceFactory; +export namespace mockServices { + // (undocumented) + export namespace cache { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } + // (undocumented) + export function config(options?: config.Options): ConfigReader; + // (undocumented) + export namespace config { + // (undocumented) + export type Options = { + data?: JsonObject; + }; + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: (options?: Options | undefined) => ServiceFactory; + } + // (undocumented) + export namespace database { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } + // (undocumented) + export namespace httpRouter { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: ( + options?: HttpRouterFactoryOptions | undefined, + ) => ServiceFactory; + } + // (undocumented) + export function identity(): IdentityService; + // (undocumented) + export namespace identity { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } + // (undocumented) + export namespace lifecycle { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } + // (undocumented) + export namespace logger { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } + // (undocumented) + export namespace permissions { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } + // (undocumented) + export namespace rootLifecycle { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } + // (undocumented) + export function rootLogger(options?: rootLogger.Options): LoggerService; + // (undocumented) + export namespace rootLogger { + // (undocumented) + export type Options = { + levels: + | boolean + | { + error: boolean; + warn: boolean; + info: boolean; + debug: boolean; + }; + }; + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: (options?: Options | undefined) => ServiceFactory; + } + // (undocumented) + export namespace scheduler { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } + // (undocumented) + export function tokenManager(): TokenManagerService; + // (undocumented) + export namespace tokenManager { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } + // (undocumented) + export namespace urlReader { + const // (undocumented) + ref: ServiceRef; + const // (undocumented) + factory: () => ServiceFactory; + } +} // @public export function setupRequestMockHandlers(worker: { diff --git a/packages/backend-test-utils/src/next/implementations/mockConfigService.ts b/packages/backend-test-utils/src/next/implementations/mockConfigService.ts deleted file mode 100644 index 1d04faad91..0000000000 --- a/packages/backend-test-utils/src/next/implementations/mockConfigService.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2022 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 { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; -import { ConfigReader } from '@backstage/config'; -import { JsonObject } from '@backstage/types'; - -/** @alpha */ -export const mockConfigFactory = createServiceFactory( - (options?: { data?: JsonObject }) => ({ - service: coreServices.config, - deps: {}, - async factory() { - return new ConfigReader(options?.data, 'mock-config'); - }, - }), -); diff --git a/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts b/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts deleted file mode 100644 index 2cfc15220e..0000000000 --- a/packages/backend-test-utils/src/next/implementations/mockTokenManagerService.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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. - */ -import { TokenManager } from '@backstage/backend-common'; -import { - coreServices, - createServiceFactory, -} from '@backstage/backend-plugin-api'; - -class TokenManagerMock implements TokenManager { - async getToken(): Promise<{ token: string }> { - return { token: 'mock-token' }; - } - async authenticate(token: string): Promise { - if (token !== 'mock-token') { - throw new Error('Invalid token'); - } - } -} - -/** @alpha */ -export const mockTokenManagerFactory = createServiceFactory({ - service: coreServices.tokenManager, - deps: {}, - async factory() { - return new TokenManagerMock(); - }, -}); diff --git a/packages/backend-test-utils/src/next/index.ts b/packages/backend-test-utils/src/next/index.ts index 9f9edfd837..572fb3a9e7 100644 --- a/packages/backend-test-utils/src/next/index.ts +++ b/packages/backend-test-utils/src/next/index.ts @@ -15,4 +15,4 @@ */ export * from './wiring'; -export * from './implementations'; +export * from './services'; diff --git a/packages/backend-test-utils/src/next/implementations/mockIdentityService.ts b/packages/backend-test-utils/src/next/services/MockIdentityService.ts similarity index 75% rename from packages/backend-test-utils/src/next/implementations/mockIdentityService.ts rename to packages/backend-test-utils/src/next/services/MockIdentityService.ts index a838c8c879..ff424f79c2 100644 --- a/packages/backend-test-utils/src/next/implementations/mockIdentityService.ts +++ b/packages/backend-test-utils/src/next/services/MockIdentityService.ts @@ -13,17 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { - coreServices, - createServiceFactory, - IdentityService, -} from '@backstage/backend-plugin-api'; +import { IdentityService } from '@backstage/backend-plugin-api'; import { IdentityApiGetIdentityRequest, BackstageIdentityResponse, } from '@backstage/plugin-auth-node'; -class MockIdentityServiceImpl implements IdentityService { +export class MockIdentityService implements IdentityService { getIdentity( _options: IdentityApiGetIdentityRequest, ): Promise { @@ -37,11 +33,3 @@ class MockIdentityServiceImpl implements IdentityService { }); } } - -export const mockIdentityFactory = createServiceFactory({ - service: coreServices.identity, - deps: {}, - async factory() { - return new MockIdentityServiceImpl(); - }, -}); diff --git a/packages/backend-test-utils/src/next/implementations/mockRootLoggerService.ts b/packages/backend-test-utils/src/next/services/MockRootLoggerService.ts similarity index 74% rename from packages/backend-test-utils/src/next/implementations/mockRootLoggerService.ts rename to packages/backend-test-utils/src/next/services/MockRootLoggerService.ts index bb3af6a9fb..780d330bfb 100644 --- a/packages/backend-test-utils/src/next/implementations/mockRootLoggerService.ts +++ b/packages/backend-test-utils/src/next/services/MockRootLoggerService.ts @@ -15,21 +15,14 @@ */ import { - coreServices, - createServiceFactory, LoggerService, LogMeta, RootLoggerService, } from '@backstage/backend-plugin-api'; +import type { mockServices } from './mockServices'; -interface MockLoggerOptions { - levels: - | boolean - | { error: boolean; warn: boolean; info: boolean; debug: boolean }; -} - -class MockLogger implements RootLoggerService { - #levels: Exclude; +export class MockRootLoggerService implements RootLoggerService { + #levels: Exclude; #meta: LogMeta; error(message: string, meta?: LogMeta | Error | undefined): void { @@ -49,10 +42,13 @@ class MockLogger implements RootLoggerService { } child(meta: LogMeta): LoggerService { - return new MockLogger(this.#levels, { ...this.#meta, ...meta }); + return new MockRootLoggerService(this.#levels, { ...this.#meta, ...meta }); } - constructor(levels: MockLoggerOptions['levels'], meta: LogMeta) { + constructor( + levels: mockServices.rootLogger.Options['levels'], + meta: LogMeta, + ) { if (typeof levels === 'boolean') { this.#levels = { error: levels, @@ -79,12 +75,3 @@ class MockLogger implements RootLoggerService { } } } - -/** @alpha */ -export const mockRootLoggerService = createServiceFactory({ - service: coreServices.rootLogger, - deps: {}, - async factory(_deps) { - return new MockLogger(false, {}); - }, -}); diff --git a/packages/backend-test-utils/src/next/implementations/index.ts b/packages/backend-test-utils/src/next/services/index.ts similarity index 91% rename from packages/backend-test-utils/src/next/implementations/index.ts rename to packages/backend-test-utils/src/next/services/index.ts index 55f417f8df..f562150efa 100644 --- a/packages/backend-test-utils/src/next/implementations/index.ts +++ b/packages/backend-test-utils/src/next/services/index.ts @@ -13,4 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { mockConfigFactory } from './mockConfigService'; +export { mockServices } from './mockServices'; diff --git a/packages/backend-test-utils/src/next/services/mockServices.ts b/packages/backend-test-utils/src/next/services/mockServices.ts new file mode 100644 index 0000000000..f86d8bac55 --- /dev/null +++ b/packages/backend-test-utils/src/next/services/mockServices.ts @@ -0,0 +1,147 @@ +/* + * 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. + */ + +import { + coreServices, + createServiceFactory, + IdentityService, + LoggerService, + ServiceFactory, + ServiceRef, + TokenManagerService, +} from '@backstage/backend-plugin-api'; +import { + cacheFactory, + databaseFactory, + httpRouterFactory, + lifecycleFactory, + loggerFactory, + permissionsFactory, + rootLifecycleFactory, + schedulerFactory, + urlReaderFactory, +} from '@backstage/backend-app-api'; +import { ConfigReader } from '@backstage/config'; +import { JsonObject } from '@backstage/types'; +import { MockIdentityService } from './MockIdentityService'; +import { MockRootLoggerService } from './MockRootLoggerService'; + +function simpleFactory( + ref: ServiceRef, + factory: (...options: TOptions) => TService, +): (...options: TOptions) => ServiceFactory { + return createServiceFactory((options: unknown) => ({ + service: ref as ServiceRef, + deps: {}, + async factory() { + return (factory as any)(options); + }, + })); +} + +/** + * @alpha + */ +export namespace mockServices { + export function config(options?: config.Options) { + return new ConfigReader(options?.data, 'mock-config'); + } + export namespace config { + export type Options = { data?: JsonObject }; + + export const ref = coreServices.config; + export const factory = simpleFactory(ref, config); + } + + export function rootLogger(options?: rootLogger.Options): LoggerService { + return new MockRootLoggerService(options?.levels ?? false, {}); + } + export namespace rootLogger { + export type Options = { + levels: + | boolean + | { error: boolean; warn: boolean; info: boolean; debug: boolean }; + }; + + export const ref = coreServices.rootLogger; + export const factory = simpleFactory(ref, rootLogger); + } + + export function tokenManager(): TokenManagerService { + return { + async getToken(): Promise<{ token: string }> { + return { token: 'mock-token' }; + }, + async authenticate(token: string): Promise { + if (token !== 'mock-token') { + throw new Error('Invalid token'); + } + }, + }; + } + export namespace tokenManager { + export const ref = coreServices.tokenManager; + export const factory = simpleFactory(ref, tokenManager); + } + + export function identity(): IdentityService { + return new MockIdentityService(); + } + export namespace identity { + export const ref = coreServices.identity; + export const factory = simpleFactory(ref, identity); + } + + // TODO(Rugvip): Not all core services have implementations available here yet. + // some may need a bit more refactoring for it to be simpler to + // re-implement functioning mock versions here. + export namespace cache { + export const ref = coreServices.cache; + export const factory = cacheFactory; + } + export namespace database { + export const ref = coreServices.database; + export const factory = databaseFactory; + } + export namespace httpRouter { + export const ref = coreServices.httpRouter; + export const factory = httpRouterFactory; + } + export namespace lifecycle { + export const ref = coreServices.lifecycle; + export const factory = lifecycleFactory; + } + export namespace logger { + export const ref = coreServices.logger; + export const factory = loggerFactory; + } + export namespace permissions { + export const ref = coreServices.permissions; + export const factory = permissionsFactory; + } + export namespace rootLifecycle { + export const ref = coreServices.rootLifecycle; + export const factory = rootLifecycleFactory; + } + export namespace scheduler { + export const ref = coreServices.scheduler; + export const factory = schedulerFactory; + } + export namespace urlReader { + export const ref = coreServices.urlReader; + export const factory = urlReaderFactory; + } +} diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 78c2f78e5e..db1016fcb6 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -17,15 +17,6 @@ import { Backend, createSpecializedBackend, - lifecycleFactory, - rootLifecycleFactory, - loggerFactory, - cacheFactory, - permissionsFactory, - schedulerFactory, - urlReaderFactory, - databaseFactory, - httpRouterFactory, MiddlewareFactory, createHttpServer, ExtendedHttpServer, @@ -40,13 +31,9 @@ import { ExtensionPoint, coreServices, } from '@backstage/backend-plugin-api'; - -import { mockConfigFactory } from '../implementations/mockConfigService'; -import { mockRootLoggerService } from '../implementations/mockRootLoggerService'; -import { mockTokenManagerFactory } from '../implementations/mockTokenManagerService'; +import { mockServices } from '../services'; import { ConfigReader } from '@backstage/config'; import express from 'express'; -import { mockIdentityFactory } from '../implementations/mockIdentityService'; /** @alpha */ export interface TestBackendOptions< @@ -84,19 +71,19 @@ export interface TestBackend extends Backend { } const defaultServiceFactories = [ - cacheFactory(), - databaseFactory(), - httpRouterFactory(), - lifecycleFactory(), - loggerFactory(), - mockConfigFactory(), - mockRootLoggerService(), - mockIdentityFactory(), - mockTokenManagerFactory(), - permissionsFactory(), - rootLifecycleFactory(), - schedulerFactory(), - urlReaderFactory(), + mockServices.cache.factory(), + mockServices.config.factory(), + mockServices.database.factory(), + mockServices.httpRouter.factory(), + mockServices.identity.factory(), + mockServices.lifecycle.factory(), + mockServices.logger.factory(), + mockServices.permissions.factory(), + mockServices.rootLifecycle.factory(), + mockServices.rootLogger.factory(), + mockServices.scheduler.factory(), + mockServices.tokenManager.factory(), + mockServices.urlReader.factory(), ]; const backendInstancesToCleanUp = new Array(); diff --git a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts index d44281600c..1b18ab0ed9 100644 --- a/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts +++ b/plugins/catalog-backend-module-bitbucket-cloud/src/service/BitbucketCloudEntityProviderCatalogModule.test.ts @@ -19,10 +19,7 @@ import { PluginTaskScheduler, TaskScheduleDefinition, } from '@backstage/backend-tasks'; -import { - startTestBackend, - mockConfigFactory, -} from '@backstage/backend-test-utils'; +import { startTestBackend, mockServices } from '@backstage/backend-test-utils'; import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node'; import { eventsExtensionPoint } from '@backstage/plugin-events-node'; import { Duration } from 'luxon'; @@ -59,7 +56,7 @@ describe('bitbucketCloudEntityProviderCatalogModule', () => { [eventsExtensionPoint, eventsExtensionPointImpl], ], services: [ - mockConfigFactory({ + mockServices.config.factory({ data: { catalog: { providers: {