From b4b1bd66433e10a7c8e750d1f5cd2f35e055bcd2 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 10 Jan 2023 15:09:30 +0100 Subject: [PATCH] backend-test-utils: refactor startTestBackend to use new http implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Fredrik Adelöw Co-authored-by: blam Co-authored-by: Johan Haals Signed-off-by: Patrik Oldsberg --- packages/backend-test-utils/api-report.md | 10 ++- .../src/next/wiring/TestBackend.ts | 88 +++++++++++-------- .../src/next/wiring/index.ts | 2 +- 3 files changed, 60 insertions(+), 40 deletions(-) diff --git a/packages/backend-test-utils/api-report.md b/packages/backend-test-utils/api-report.md index 3df3f3cb21..ad7ecc04dd 100644 --- a/packages/backend-test-utils/api-report.md +++ b/packages/backend-test-utils/api-report.md @@ -5,6 +5,7 @@ ```ts import { Backend } from '@backstage/backend-app-api'; import { BackendFeature } from '@backstage/backend-plugin-api'; +import { ExtendedHttpServer } from '@backstage/backend-app-api'; import { ExtensionPoint } from '@backstage/backend-plugin-api'; import { Knex } from 'knex'; import { ServiceFactory } from '@backstage/backend-plugin-api'; @@ -24,7 +25,14 @@ export function setupRequestMockHandlers(worker: { export function startTestBackend< TServices extends any[], TExtensionPoints extends any[], ->(options: TestBackendOptions): Promise; +>( + options: TestBackendOptions, +): Promise; + +// @alpha (undocumented) +export interface TestBackend extends Backend { + readonly server: ExtendedHttpServer; +} // @alpha (undocumented) export interface TestBackendOptions< diff --git a/packages/backend-test-utils/src/next/wiring/TestBackend.ts b/packages/backend-test-utils/src/next/wiring/TestBackend.ts index 933257426e..00c38240a3 100644 --- a/packages/backend-test-utils/src/next/wiring/TestBackend.ts +++ b/packages/backend-test-utils/src/next/wiring/TestBackend.ts @@ -27,14 +27,12 @@ import { urlReaderFactory, databaseFactory, httpRouterFactory, + MiddlewareFactory, + createHttpServer, + ExtendedHttpServer, + DefaultRootHttpRouter, } from '@backstage/backend-app-api'; -import { - createServiceBuilder, - SingleHostDiscovery, -} from '@backstage/backend-common'; -import { Handler } from 'express'; -import * as http from 'http'; -import Router from 'express-promise-router'; +import { SingleHostDiscovery } from '@backstage/backend-common'; import { ServiceFactory, ServiceRef, @@ -45,8 +43,8 @@ import { } from '@backstage/backend-plugin-api'; import { mockConfigFactory, mockTokenManagerFactory } from '../implementations'; -import { AddressInfo } from 'net'; import { ConfigReader } from '@backstage/config'; +import express from 'express'; /** @alpha */ export interface TestBackendOptions< @@ -72,6 +70,17 @@ export interface TestBackendOptions< features?: BackendFeature[]; } +/** @alpha */ +export interface TestBackend extends Backend { + /** + * Provides access to the underling HTTP server for use with utilities + * such as `supertest`. + * + * If the root http router service has been replaced, this will throw an error. + */ + readonly server: ExtendedHttpServer; +} + const defaultServiceFactories = [ cacheFactory(), databaseFactory(), @@ -93,7 +102,9 @@ const backendInstancesToCleanUp = new Array(); export async function startTestBackend< TServices extends any[], TExtensionPoints extends any[], ->(options: TestBackendOptions): Promise { +>( + options: TestBackendOptions, +): Promise { const { services = [], extensionPoints = [], @@ -101,49 +112,43 @@ export async function startTestBackend< ...otherOptions } = options; - let server: http.Server; + let server: ExtendedHttpServer; const rootHttpRouterFactory = createServiceFactory({ service: coreServices.rootHttpRouter, deps: { config: coreServices.config, lifecycle: coreServices.rootLifecycle, + rootLogger: coreServices.rootLogger, }, - async factory({ config, lifecycle }) { - const router = Router(); + async factory({ config, lifecycle, rootLogger }) { + const router = DefaultRootHttpRouter.create(); + const logger = rootLogger.child({ service: 'rootHttpRouter' }); - const service = createServiceBuilder(module) - .loadConfig(config) - .setPort(0); + const app = express(); - service.addRouter('', router); + const middleware = MiddlewareFactory.create({ config, logger }); - server = await service.start(); - // Stop method isn't part of the public API, let's fix that once we move the implementation here. - const stoppableServer = server as typeof server & { - stop: (cb: (error?: Error) => void) => void; - }; + app.use(router.handler()); + app.use(middleware.notFound()); + app.use(middleware.error()); + + server = await createHttpServer( + app, + { listen: { host: '', port: 0 } }, + { logger }, + ); lifecycle.addShutdownHook({ async fn() { - await new Promise((resolve, reject) => { - stoppableServer.stop((error?: Error) => { - if (error) { - reject(error); - } else { - resolve(); - } - }); - }); + await server.stop(); }, - labels: { service: 'rootHttpRouter' }, + logger, }); - return { - use: (path: string, handler: Handler) => { - router.use(path, handler); - }, - }; + await server.start(); + + return router; }, }); @@ -156,7 +161,7 @@ export async function startTestBackend< if (!server) { throw new Error('Test server not started yet'); } - const { port } = server.address() as AddressInfo; + const port = server.port(); const discovery = SingleHostDiscovery.fromConfig( new ConfigReader({ backend: { baseUrl: `http://localhost:${port}`, listen: { port } }, @@ -220,7 +225,14 @@ export async function startTestBackend< await backend.start(); - return Object.assign(backend, { server: server! }) as Backend; + return Object.assign(backend, { + get server() { + if (!server) { + throw new Error('TestBackend server is not available'); + } + return server; + }, + }); } let registered = false; diff --git a/packages/backend-test-utils/src/next/wiring/index.ts b/packages/backend-test-utils/src/next/wiring/index.ts index eb7b773e33..7c39474d4c 100644 --- a/packages/backend-test-utils/src/next/wiring/index.ts +++ b/packages/backend-test-utils/src/next/wiring/index.ts @@ -15,4 +15,4 @@ */ export { startTestBackend } from './TestBackend'; -export type { TestBackendOptions } from './TestBackend'; +export type { TestBackend, TestBackendOptions } from './TestBackend';