Merge pull request #19654 from backstage/rugvip/service-tester
backend-test-utils: add ServiceFactoryTester utility
This commit is contained in:
+23
-46
@@ -14,39 +14,29 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
ServiceFactoryTester,
|
||||
mockServices,
|
||||
} from '@backstage/backend-test-utils';
|
||||
import { httpRouterServiceFactory } from './httpRouterServiceFactory';
|
||||
|
||||
describe('httpRouterFactory', () => {
|
||||
it('should register plugin paths', async () => {
|
||||
const rootHttpRouter = { use: jest.fn() };
|
||||
const factory = httpRouterServiceFactory() as any;
|
||||
const rootHttpRouter = mockServices.rootHttpRouter.mock();
|
||||
const tester = ServiceFactoryTester.from(httpRouterServiceFactory, {
|
||||
dependencies: [rootHttpRouter.factory],
|
||||
});
|
||||
|
||||
const handler1 = () => {};
|
||||
const router1 = await factory.factory(
|
||||
{
|
||||
rootHttpRouter,
|
||||
plugin: { getId: () => 'test1' },
|
||||
lifecycle: { addStartupHook() {}, addShutdownHook() {} },
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
router1.use(handler1);
|
||||
const router1 = await tester.get('test1');
|
||||
router1.use(() => {});
|
||||
expect(rootHttpRouter.use).toHaveBeenCalledTimes(1);
|
||||
expect(rootHttpRouter.use).toHaveBeenCalledWith(
|
||||
'/api/test1',
|
||||
expect.any(Function),
|
||||
);
|
||||
|
||||
const handler2 = () => {};
|
||||
const router2 = await factory.factory(
|
||||
{
|
||||
rootHttpRouter,
|
||||
plugin: { getId: () => 'test2' },
|
||||
lifecycle: { addStartupHook() {}, addShutdownHook() {} },
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
router2.use(handler2);
|
||||
const router2 = await tester.get('test2');
|
||||
router2.use(() => {});
|
||||
expect(rootHttpRouter.use).toHaveBeenCalledTimes(2);
|
||||
expect(rootHttpRouter.use).toHaveBeenCalledWith(
|
||||
'/api/test2',
|
||||
@@ -55,37 +45,24 @@ describe('httpRouterFactory', () => {
|
||||
});
|
||||
|
||||
it('should use custom path generator', async () => {
|
||||
const rootHttpRouter = { use: jest.fn() };
|
||||
const factory = httpRouterServiceFactory({
|
||||
getPath: id => `/some/${id}/path`,
|
||||
}) as any;
|
||||
|
||||
const handler1 = () => {};
|
||||
const router1 = await factory.factory(
|
||||
{
|
||||
rootHttpRouter,
|
||||
plugin: { getId: () => 'test1' },
|
||||
lifecycle: { addStartupHook() {}, addShutdownHook() {} },
|
||||
},
|
||||
undefined,
|
||||
const rootHttpRouter = mockServices.rootHttpRouter.mock();
|
||||
const tester = ServiceFactoryTester.from(
|
||||
httpRouterServiceFactory({
|
||||
getPath: id => `/some/${id}/path`,
|
||||
}),
|
||||
{ dependencies: [rootHttpRouter.factory] },
|
||||
);
|
||||
router1.use(handler1);
|
||||
|
||||
const router1 = await tester.get('test1');
|
||||
router1.use(() => {});
|
||||
expect(rootHttpRouter.use).toHaveBeenCalledTimes(1);
|
||||
expect(rootHttpRouter.use).toHaveBeenCalledWith(
|
||||
'/some/test1/path',
|
||||
expect.any(Function),
|
||||
);
|
||||
|
||||
const handler2 = () => {};
|
||||
const router2 = await factory.factory(
|
||||
{
|
||||
rootHttpRouter,
|
||||
plugin: { getId: () => 'test2' },
|
||||
lifecycle: { addStartupHook() {}, addShutdownHook() {} },
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
router2.use(handler2);
|
||||
const router2 = await tester.get('test2');
|
||||
router2.use(() => {});
|
||||
expect(rootHttpRouter.use).toHaveBeenCalledTimes(2);
|
||||
expect(rootHttpRouter.use).toHaveBeenCalledWith(
|
||||
'/some/test2/path',
|
||||
|
||||
+21
-42
@@ -14,54 +14,33 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
coreServices,
|
||||
createBackendPlugin,
|
||||
} from '@backstage/backend-plugin-api';
|
||||
import { startTestBackend } from '@backstage/backend-test-utils';
|
||||
import { coreServices } from '@backstage/backend-plugin-api';
|
||||
import { ServiceFactoryTester } from '@backstage/backend-test-utils';
|
||||
import { schedulerServiceFactory } from './schedulerServiceFactory';
|
||||
|
||||
describe('schedulerFactory', () => {
|
||||
it('creates sidecar database features', async () => {
|
||||
expect.assertions(3);
|
||||
const tester = ServiceFactoryTester.from(schedulerServiceFactory());
|
||||
|
||||
const subject = schedulerServiceFactory();
|
||||
|
||||
const plugin = createBackendPlugin({
|
||||
pluginId: 'example',
|
||||
register(reg) {
|
||||
reg.registerInit({
|
||||
deps: {
|
||||
scheduler: subject.service,
|
||||
database: coreServices.database,
|
||||
},
|
||||
init: async ({ scheduler, database }) => {
|
||||
await scheduler.scheduleTask({
|
||||
id: 'task1',
|
||||
timeout: { seconds: 1 },
|
||||
frequency: { seconds: 1 },
|
||||
fn: async () => {},
|
||||
});
|
||||
|
||||
const client = await database.getClient();
|
||||
await expect(
|
||||
client.from('backstage_backend_tasks__tasks').count(),
|
||||
).resolves.toEqual([{ 'count(*)': 1 }]);
|
||||
await expect(
|
||||
client.from('backstage_backend_tasks__knex_migrations').count(),
|
||||
).resolves.toEqual([{ 'count(*)': expect.any(Number) }]);
|
||||
await expect(
|
||||
client
|
||||
.from('backstage_backend_tasks__knex_migrations_lock')
|
||||
.count(),
|
||||
).resolves.toEqual([{ 'count(*)': expect.any(Number) }]);
|
||||
},
|
||||
});
|
||||
},
|
||||
const scheduler = await tester.get();
|
||||
await scheduler.scheduleTask({
|
||||
id: 'task1',
|
||||
timeout: { seconds: 1 },
|
||||
frequency: { seconds: 1 },
|
||||
fn: async () => {},
|
||||
});
|
||||
|
||||
await startTestBackend({
|
||||
features: [plugin(), subject],
|
||||
});
|
||||
const database = await tester.getService(coreServices.database);
|
||||
|
||||
const client = await database.getClient();
|
||||
await expect(
|
||||
client.from('backstage_backend_tasks__tasks').count(),
|
||||
).resolves.toEqual([{ 'count(*)': 1 }]);
|
||||
await expect(
|
||||
client.from('backstage_backend_tasks__knex_migrations').count(),
|
||||
).resolves.toEqual([{ 'count(*)': expect.any(Number) }]);
|
||||
await expect(
|
||||
client.from('backstage_backend_tasks__knex_migrations_lock').count(),
|
||||
).resolves.toEqual([{ 'count(*)': expect.any(Number) }]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,9 +58,9 @@ const pluginMetadataServiceFactory = createServiceFactory(
|
||||
);
|
||||
|
||||
export class ServiceRegistry implements EnumerableServiceHolder {
|
||||
static create(factories: Array<ServiceFactory>): EnumerableServiceHolder {
|
||||
static create(factories: Array<ServiceFactory>): ServiceRegistry {
|
||||
const registry = new ServiceRegistry(factories);
|
||||
registry.checkForCircularDeps();
|
||||
registry.#checkForCircularDeps();
|
||||
return registry;
|
||||
}
|
||||
|
||||
@@ -80,7 +80,6 @@ export class ServiceRegistry implements EnumerableServiceHolder {
|
||||
InternalServiceFactory,
|
||||
Promise<unknown>
|
||||
>();
|
||||
readonly #dependencyGraph: DependencyGraph<string>;
|
||||
|
||||
private constructor(factories: Array<ServiceFactory>) {
|
||||
this.#providedFactories = new Map(
|
||||
@@ -88,15 +87,6 @@ export class ServiceRegistry implements EnumerableServiceHolder {
|
||||
);
|
||||
this.#loadedDefaultFactories = new Map();
|
||||
this.#implementations = new Map();
|
||||
this.#dependencyGraph = DependencyGraph.fromIterable(
|
||||
Array.from(this.#providedFactories).map(
|
||||
([serviceId, serviceFactory]) => ({
|
||||
value: serviceId,
|
||||
provides: [serviceId],
|
||||
consumes: Object.values(serviceFactory.deps).map(d => d.id),
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#resolveFactory(
|
||||
@@ -163,10 +153,17 @@ export class ServiceRegistry implements EnumerableServiceHolder {
|
||||
}
|
||||
}
|
||||
|
||||
checkForCircularDeps(): void {
|
||||
const circularDependencies = Array.from(
|
||||
this.#dependencyGraph.detectCircularDependencies(),
|
||||
#checkForCircularDeps(): void {
|
||||
const graph = DependencyGraph.fromIterable(
|
||||
Array.from(this.#providedFactories).map(
|
||||
([serviceId, serviceFactory]) => ({
|
||||
value: serviceId,
|
||||
provides: [serviceId],
|
||||
consumes: Object.values(serviceFactory.deps).map(d => d.id),
|
||||
}),
|
||||
),
|
||||
);
|
||||
const circularDependencies = Array.from(graph.detectCircularDependencies());
|
||||
|
||||
if (circularDependencies.length) {
|
||||
const cycles = circularDependencies
|
||||
|
||||
Reference in New Issue
Block a user