Made it possible to construct mockServices.database with a given knex instance

Signed-off-by: Fredrik Adelöw <freben@gmail.com>
This commit is contained in:
Fredrik Adelöw
2024-11-05 11:35:31 +01:00
parent e115f24e81
commit 50648277ef
13 changed files with 119 additions and 124 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/backend-test-utils': minor
---
Made it possible to construct `mockServices.database` with a given knex instance
@@ -224,10 +224,7 @@ your test database.
```ts
const { knex, subject } = await createSubject(databaseId);
const { server } = await startTestBackend({
features: [
myPlugin(),
mockServices.database.mock({ getClient: async () => knex }),
],
features: [myPlugin(), mockServices.database.factory({ knex })],
});
```
@@ -46,7 +46,7 @@ describe('DatabaseKeyStore', () => {
knex,
logger,
keyStore: await DatabaseKeyStore.create({
database: { getClient: async () => knex },
database: mockServices.database({ knex }),
logger,
}),
};
@@ -14,16 +14,11 @@
* limitations under the License.
*/
import {
TestDatabaseId,
TestDatabases,
mockServices,
} from '@backstage/backend-test-utils';
import { TestDatabases, mockServices } from '@backstage/backend-test-utils';
import { Duration } from 'luxon';
import waitForExpect from 'wait-for-expect';
import { DefaultSchedulerService } from './DefaultSchedulerService';
import { createTestScopedSignal } from './__testUtils__/createTestScopedSignal';
import { DatabaseService } from '@backstage/backend-plugin-api';
jest.setTimeout(60_000);
@@ -32,19 +27,12 @@ describe('TaskScheduler', () => {
const databases = TestDatabases.create();
const testScopedSignal = createTestScopedSignal();
async function createDatabase(
databaseId: TestDatabaseId,
): Promise<DatabaseService> {
const knex = await databases.init(databaseId);
return {
getClient: async () => knex,
};
}
it.each(databases.eachSupportedId())(
'can return a working v1 plugin impl, %p',
async databaseId => {
const database = await createDatabase(databaseId);
const knex = await databases.init(databaseId);
const database = mockServices.database({ knex });
const manager = DefaultSchedulerService.create({ database, logger });
const fn = jest.fn();
@@ -65,7 +53,9 @@ describe('TaskScheduler', () => {
it.each(databases.eachSupportedId())(
'can return a working v2 plugin impl, %p',
async databaseId => {
const database = await createDatabase(databaseId);
const knex = await databases.init(databaseId);
const database = mockServices.database({ knex });
const manager = DefaultSchedulerService.create({ database, logger });
const fn = jest.fn();
+15 -6
View File
@@ -175,14 +175,23 @@ export namespace mockServices {
partialImpl?: Partial<CacheService> | undefined,
) => ServiceMock<CacheService>;
}
export function database(options: {
knex: Knex;
migrations?: {
skip?: boolean;
};
}): DatabaseService;
// (undocumented)
export namespace database {
const // (undocumented)
factory: () => ServiceFactory<DatabaseService, 'plugin', 'singleton'>;
const // (undocumented)
mock: (
partialImpl?: Partial<DatabaseService> | undefined,
) => ServiceMock<DatabaseService>;
const factory: (options?: {
knex: Knex;
migrations?: {
skip?: boolean;
};
}) => ServiceFactory<DatabaseService, 'plugin', 'singleton'>;
const mock: (
partialImpl?: Partial<DatabaseService> | undefined,
) => ServiceMock<DatabaseService>;
}
// (undocumented)
export function discovery(): DiscoveryService;
@@ -30,6 +30,7 @@ import {
AuthService,
BackstageCredentials,
BackstageUserInfo,
DatabaseService,
DiscoveryService,
HttpAuthService,
LoggerService,
@@ -51,6 +52,7 @@ import { MockHttpAuthService } from './MockHttpAuthService';
import { MockRootLoggerService } from './MockRootLoggerService';
import { MockUserInfoService } from './MockUserInfoService';
import { mockCredentials } from './mockCredentials';
import { Knex } from 'knex';
/** @internal */
function createLoggerMock() {
@@ -376,8 +378,45 @@ export namespace mockServices {
}));
}
/**
* Creates a mock implementation of the
* {@link @backstage/backend-plugin-api#coreServices.database}. Just returns
* the given `knex` instance, which is useful in combination with the
* {@link TestDatabases} facility.
*/
export function database(options: {
knex: Knex;
migrations?: { skip?: boolean };
}): DatabaseService {
return {
getClient: async () => options.knex,
migrations: options.migrations,
};
}
export namespace database {
export const factory = () => databaseServiceFactory;
/**
* Creates a mock factory for the
* {@link @backstage/backend-plugin-api#coreServices.database}. Just returns
* the given `knex` instance if you supply one, which is useful in
* combination with the {@link TestDatabases} facility. Otherwise, it
* returns the regular default database factory which reads config settings.
*/
export const factory = (options?: {
knex: Knex;
migrations?: { skip?: boolean };
}) =>
options
? createServiceFactory({
service: coreServices.database,
deps: {},
factory: () => database(options),
})
: databaseServiceFactory;
/**
* Creates a mock of the
* {@link @backstage/backend-plugin-api#coreServices.database}, optionally
* with some given method implementations.
*/
export const mock = simpleMock(coreServices.database, () => ({
getClient: jest.fn(),
}));
@@ -14,24 +14,9 @@
* limitations under the License.
*/
import { Knex as KnexType } from 'knex';
import { TestDatabases, mockServices } from '@backstage/backend-test-utils';
import { StaticAssetsStore } from './StaticAssetsStore';
const logger = mockServices.logger.mock();
function createDatabaseManager(
client: KnexType,
skipMigrations: boolean = false,
) {
return {
getClient: async () => client,
migrations: {
skip: skipMigrations,
},
};
}
jest.setTimeout(60_000);
describe('StaticAssetsStore', () => {
@@ -40,11 +25,11 @@ describe('StaticAssetsStore', () => {
it.each(databases.eachSupportedId())(
'should store and retrieve assets, %p',
async databaseId => {
const client = await databases.init(databaseId);
const database = createDatabaseManager(client);
const knex = await databases.init(databaseId);
const store = await StaticAssetsStore.create({
logger,
database,
logger: mockServices.logger.mock(),
database: mockServices.database({ knex }),
});
await store.storeAssets([
@@ -82,11 +67,11 @@ describe('StaticAssetsStore', () => {
it.each(databases.eachSupportedId())(
'should update assets timestamps, but not contents, %p',
async databaseId => {
const client = await databases.init(databaseId);
const database = createDatabaseManager(client);
const knex = await databases.init(databaseId);
const store = await StaticAssetsStore.create({
logger,
database,
logger: mockServices.logger.mock(),
database: mockServices.database({ knex }),
});
await store.storeAssets([
@@ -134,10 +119,10 @@ describe('StaticAssetsStore', () => {
'should trim old assets, %p',
async databaseId => {
const knex = await databases.init(databaseId);
const database = createDatabaseManager(knex);
const store = await StaticAssetsStore.create({
logger,
database,
logger: mockServices.logger.mock(),
database: mockServices.database({ knex }),
});
await store.storeAssets([
@@ -179,10 +164,10 @@ describe('StaticAssetsStore', () => {
'should isolate assets in namespace, %p',
async databaseId => {
const knex = await databases.init(databaseId);
const database = createDatabaseManager(knex);
const store = await StaticAssetsStore.create({
logger,
database,
logger: mockServices.logger.mock(),
database: mockServices.database({ knex }),
});
const otherStore = store.withNamespace('other');
@@ -14,22 +14,22 @@
* limitations under the License.
*/
import { describePerformanceTest, performanceTraceEnabled } from './lib/env';
import { startTestBackend, TestDatabases } from '@backstage/backend-test-utils';
import { createBackendModule } from '@backstage/backend-plugin-api';
import {
TestDatabases,
mockServices,
startTestBackend,
} from '@backstage/backend-test-utils';
import { CatalogClient } from '@backstage/catalog-client';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { Knex } from 'knex';
import { applyDatabaseMigrations } from '../../database/migrations';
import {
SyntheticLoadEntitiesProcessor,
SyntheticLoadEntitiesProvider,
SyntheticLoadOptions,
} from './lib/catalogModuleSyntheticLoadEntities';
import { CatalogClient } from '@backstage/catalog-client';
import {
coreServices,
createBackendModule,
createServiceFactory,
} from '@backstage/backend-plugin-api';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { Knex } from 'knex';
import { describePerformanceTest, performanceTraceEnabled } from './lib/env';
jest.setTimeout(600_000);
@@ -85,11 +85,7 @@ describePerformanceTest('getEntitiesPerformanceTest', () => {
const backend = await startTestBackend({
features: [
import('@backstage/plugin-catalog-backend/alpha'),
createServiceFactory({
service: coreServices.database,
deps: {},
factory: () => ({ getClient: async () => knex }),
}),
mockServices.database.factory({ knex }),
createBackendModule({
pluginId: 'catalog',
moduleId: 'synthetic-load-entities',
@@ -14,15 +14,11 @@
* limitations under the License.
*/
import { createBackendModule } from '@backstage/backend-plugin-api';
import {
coreServices,
createBackendModule,
createServiceFactory,
} from '@backstage/backend-plugin-api';
import {
TestDatabases,
mockServices,
startTestBackend,
TestDatabases,
} from '@backstage/backend-test-utils';
import { catalogProcessingExtensionPoint } from '@backstage/plugin-catalog-node/alpha';
import { Knex } from 'knex';
@@ -182,11 +178,7 @@ describePerformanceTest('stitchingPerformance', () => {
features: [
import('@backstage/plugin-catalog-backend/alpha'),
mockServices.rootConfig.factory({ data: config }),
createServiceFactory({
service: coreServices.database,
deps: {},
factory: () => ({ getClient: async () => knex }),
}),
mockServices.database.factory({ knex }),
createBackendModule({
pluginId: 'catalog',
moduleId: 'synthetic-load-entities',
@@ -239,11 +231,7 @@ describePerformanceTest('stitchingPerformance', () => {
features: [
import('@backstage/plugin-catalog-backend/alpha'),
mockServices.rootConfig.factory({ data: config }),
createServiceFactory({
service: coreServices.database,
deps: {},
factory: () => ({ getClient: async () => knex }),
}),
mockServices.database.factory({ knex }),
createBackendModule({
pluginId: 'catalog',
moduleId: 'synthetic-load-entities',
@@ -144,9 +144,7 @@ describe('eventsPlugin', () => {
async function mockKnexFactory(databaseId: TestDatabaseId) {
const knex = await databases.init(databaseId);
return mockServices.database.mock({
getClient: async () => knex,
}).factory;
return mockServices.database.factory({ knex });
}
let backend: TestBackend | undefined = undefined;
@@ -13,7 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
import {
TestDatabaseId,
TestDatabases,
mockServices,
} from '@backstage/backend-test-utils';
import { DatabaseNotificationsStore } from './DatabaseNotificationsStore';
import { Knex } from 'knex';
import {
@@ -28,15 +32,10 @@ const databases = TestDatabases.create();
async function createStore(databaseId: TestDatabaseId) {
const knex = await databases.init(databaseId);
const mgr = {
getClient: async () => knex,
migrations: {
skip: false,
},
};
const database = mockServices.database({ knex, migrations: { skip: false } });
return {
knex,
storage: await DatabaseNotificationsStore.create({ database: mgr }),
storage: await DatabaseNotificationsStore.create({ database }),
};
}
@@ -14,8 +14,11 @@
* limitations under the License.
*/
import { Knex as KnexType } from 'knex';
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
import {
TestDatabaseId,
TestDatabases,
mockServices,
} from '@backstage/backend-test-utils';
import { IndexableDocument } from '@backstage/plugin-search-common';
import { PgSearchHighlightOptions } from '../PgSearchEngine';
import { DatabaseDocumentStore } from './DatabaseDocumentStore';
@@ -32,18 +35,6 @@ const highlightOptions: PgSearchHighlightOptions = {
fragmentDelimiter: ' ... ',
};
function createDatabaseManager(
client: KnexType,
skipMigrations: boolean = false,
) {
return {
getClient: async () => client,
migrations: {
skip: skipMigrations,
},
};
}
jest.setTimeout(60_000);
describe('DatabaseDocumentStore', () => {
@@ -66,8 +57,7 @@ describe('DatabaseDocumentStore', () => {
'should fail to create, %p',
async databaseId => {
const knex = await databases.init(databaseId);
const databaseManager = createDatabaseManager(knex);
const databaseManager = mockServices.database({ knex });
await expect(
async () => await DatabaseDocumentStore.create(databaseManager),
).rejects.toThrow();
@@ -82,7 +72,7 @@ describe('DatabaseDocumentStore', () => {
async function createStore(databaseId: TestDatabaseId) {
const knex = await databases.init(databaseId);
const databaseManager = createDatabaseManager(knex);
const databaseManager = mockServices.database({ knex });
const store = await DatabaseDocumentStore.create(databaseManager);
return { store, knex };
@@ -14,7 +14,11 @@
* limitations under the License.
*/
import { TestDatabaseId, TestDatabases } from '@backstage/backend-test-utils';
import {
TestDatabaseId,
TestDatabases,
mockServices,
} from '@backstage/backend-test-utils';
import { Knex } from 'knex';
import {
DatabaseUserSettingsStore,
@@ -29,12 +33,7 @@ const databases = TestDatabases.create({
async function createStore(databaseId: TestDatabaseId) {
const knex = await databases.init(databaseId);
const databaseManager = {
getClient: async () => knex,
migrations: {
skip: false,
},
};
const databaseManager = mockServices.database({ knex });
return {
knex,