@backstage/backend-test-utils 1.0.1-next.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/dist/backend-app-api/src/lib/DependencyGraph.cjs.js +182 -0
- package/dist/backend-app-api/src/lib/DependencyGraph.cjs.js.map +1 -0
- package/dist/backend-app-api/src/wiring/ServiceRegistry.cjs.js +240 -0
- package/dist/backend-app-api/src/wiring/ServiceRegistry.cjs.js.map +1 -0
- package/dist/cache/TestCaches.cjs.js +159 -0
- package/dist/cache/TestCaches.cjs.js.map +1 -0
- package/dist/cache/memcache.cjs.js +62 -0
- package/dist/cache/memcache.cjs.js.map +1 -0
- package/dist/cache/redis.cjs.js +62 -0
- package/dist/cache/redis.cjs.js.map +1 -0
- package/dist/cache/types.cjs.js +25 -0
- package/dist/cache/types.cjs.js.map +1 -0
- package/dist/database/TestDatabases.cjs.js +128 -0
- package/dist/database/TestDatabases.cjs.js.map +1 -0
- package/dist/database/mysql.cjs.js +188 -0
- package/dist/database/mysql.cjs.js.map +1 -0
- package/dist/database/postgres.cjs.js +143 -0
- package/dist/database/postgres.cjs.js.map +1 -0
- package/dist/database/sqlite.cjs.js +40 -0
- package/dist/database/sqlite.cjs.js.map +1 -0
- package/dist/database/types.cjs.js +68 -0
- package/dist/database/types.cjs.js.map +1 -0
- package/dist/filesystem/MockDirectory.cjs.js +173 -0
- package/dist/filesystem/MockDirectory.cjs.js.map +1 -0
- package/dist/index.cjs.js +25 -2327
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +44 -2
- package/dist/msw/registerMswTestHooks.cjs.js +10 -0
- package/dist/msw/registerMswTestHooks.cjs.js.map +1 -0
- package/dist/next/services/MockAuthService.cjs.js +111 -0
- package/dist/next/services/MockAuthService.cjs.js.map +1 -0
- package/dist/next/services/MockHttpAuthService.cjs.js +87 -0
- package/dist/next/services/MockHttpAuthService.cjs.js.map +1 -0
- package/dist/next/services/MockRootLoggerService.cjs.js +49 -0
- package/dist/next/services/MockRootLoggerService.cjs.js.map +1 -0
- package/dist/next/services/MockUserInfoService.cjs.js +26 -0
- package/dist/next/services/MockUserInfoService.cjs.js.map +1 -0
- package/dist/next/services/mockCredentials.cjs.js +148 -0
- package/dist/next/services/mockCredentials.cjs.js.map +1 -0
- package/dist/next/services/mockServices.cjs.js +294 -0
- package/dist/next/services/mockServices.cjs.js.map +1 -0
- package/dist/next/wiring/ServiceFactoryTester.cjs.js +61 -0
- package/dist/next/wiring/ServiceFactoryTester.cjs.js.map +1 -0
- package/dist/next/wiring/TestBackend.cjs.js +258 -0
- package/dist/next/wiring/TestBackend.cjs.js.map +1 -0
- package/dist/util/errorHandler.cjs.js +18 -0
- package/dist/util/errorHandler.cjs.js.map +1 -0
- package/dist/util/getDockerImageForName.cjs.js +8 -0
- package/dist/util/getDockerImageForName.cjs.js.map +1 -0
- package/dist/util/isDockerDisabledForTests.cjs.js +8 -0
- package/dist/util/isDockerDisabledForTests.cjs.js.map +1 -0
- package/package.json +11 -11
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Keyv = require('keyv');
|
|
4
|
+
var isDockerDisabledForTests = require('../util/isDockerDisabledForTests.cjs.js');
|
|
5
|
+
var memcache = require('./memcache.cjs.js');
|
|
6
|
+
var redis = require('./redis.cjs.js');
|
|
7
|
+
var types = require('./types.cjs.js');
|
|
8
|
+
|
|
9
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var Keyv__default = /*#__PURE__*/_interopDefaultCompat(Keyv);
|
|
12
|
+
|
|
13
|
+
class TestCaches {
|
|
14
|
+
instanceById;
|
|
15
|
+
supportedIds;
|
|
16
|
+
static defaultIds;
|
|
17
|
+
/**
|
|
18
|
+
* Creates an empty `TestCaches` instance, and sets up Jest to clean up all of
|
|
19
|
+
* its acquired resources after all tests finish.
|
|
20
|
+
*
|
|
21
|
+
* You typically want to create just a single instance like this at the top of
|
|
22
|
+
* your test file or `describe` block, and then call `init` many times on that
|
|
23
|
+
* instance inside the individual tests. Spinning up a "physical" cache
|
|
24
|
+
* instance takes a considerable amount of time, slowing down tests. But
|
|
25
|
+
* wiping the contents of an instance using `init` is very fast.
|
|
26
|
+
*/
|
|
27
|
+
static create(options) {
|
|
28
|
+
const ids = options?.ids;
|
|
29
|
+
const disableDocker = options?.disableDocker ?? isDockerDisabledForTests.isDockerDisabledForTests();
|
|
30
|
+
let testCacheIds;
|
|
31
|
+
if (ids) {
|
|
32
|
+
testCacheIds = ids;
|
|
33
|
+
} else if (TestCaches.defaultIds) {
|
|
34
|
+
testCacheIds = TestCaches.defaultIds;
|
|
35
|
+
} else {
|
|
36
|
+
testCacheIds = Object.keys(types.allCaches);
|
|
37
|
+
}
|
|
38
|
+
const supportedIds = testCacheIds.filter((id) => {
|
|
39
|
+
const properties = types.allCaches[id];
|
|
40
|
+
if (!properties) {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
if (properties.connectionStringEnvironmentVariableName && process.env[properties.connectionStringEnvironmentVariableName]) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (!properties.dockerImageName) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
if (disableDocker) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
});
|
|
54
|
+
const caches = new TestCaches(supportedIds);
|
|
55
|
+
if (supportedIds.length > 0) {
|
|
56
|
+
afterAll(async () => {
|
|
57
|
+
await caches.shutdown();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return caches;
|
|
61
|
+
}
|
|
62
|
+
static setDefaults(options) {
|
|
63
|
+
TestCaches.defaultIds = options.ids;
|
|
64
|
+
}
|
|
65
|
+
constructor(supportedIds) {
|
|
66
|
+
this.instanceById = /* @__PURE__ */ new Map();
|
|
67
|
+
this.supportedIds = supportedIds;
|
|
68
|
+
}
|
|
69
|
+
supports(id) {
|
|
70
|
+
return this.supportedIds.includes(id);
|
|
71
|
+
}
|
|
72
|
+
eachSupportedId() {
|
|
73
|
+
return this.supportedIds.map((id) => [id]);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Returns a fresh, empty cache for the given driver.
|
|
77
|
+
*
|
|
78
|
+
* @param id - The ID of the cache to use, e.g. 'REDIS_7'
|
|
79
|
+
* @returns Cache connection properties
|
|
80
|
+
*/
|
|
81
|
+
async init(id) {
|
|
82
|
+
const properties = types.allCaches[id];
|
|
83
|
+
if (!properties) {
|
|
84
|
+
const candidates = Object.keys(types.allCaches).join(", ");
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Unknown test cache ${id}, possible values are ${candidates}`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
if (!this.supportedIds.includes(id)) {
|
|
90
|
+
const candidates = this.supportedIds.join(", ");
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Unsupported test cache ${id} for this environment, possible values are ${candidates}`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
let instance = this.instanceById.get(id);
|
|
96
|
+
if (!instance) {
|
|
97
|
+
instance = await this.initAny(properties);
|
|
98
|
+
this.instanceById.set(id, instance);
|
|
99
|
+
}
|
|
100
|
+
await instance.keyv.clear();
|
|
101
|
+
return {
|
|
102
|
+
store: instance.store,
|
|
103
|
+
connection: instance.connection,
|
|
104
|
+
keyv: instance.keyv
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
async initAny(properties) {
|
|
108
|
+
switch (properties.store) {
|
|
109
|
+
case "memcache":
|
|
110
|
+
return this.initMemcached(properties);
|
|
111
|
+
case "redis":
|
|
112
|
+
return this.initRedis(properties);
|
|
113
|
+
case "memory":
|
|
114
|
+
return {
|
|
115
|
+
store: "memory",
|
|
116
|
+
connection: "memory",
|
|
117
|
+
keyv: new Keyv__default.default(),
|
|
118
|
+
stop: async () => {
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
default:
|
|
122
|
+
throw new Error(`Unknown cache store '${properties.store}'`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
async initMemcached(properties) {
|
|
126
|
+
const envVarName = properties.connectionStringEnvironmentVariableName;
|
|
127
|
+
if (envVarName) {
|
|
128
|
+
const connectionString = process.env[envVarName];
|
|
129
|
+
if (connectionString) {
|
|
130
|
+
return memcache.connectToExternalMemcache(connectionString);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return await memcache.startMemcachedContainer(properties.dockerImageName);
|
|
134
|
+
}
|
|
135
|
+
async initRedis(properties) {
|
|
136
|
+
const envVarName = properties.connectionStringEnvironmentVariableName;
|
|
137
|
+
if (envVarName) {
|
|
138
|
+
const connectionString = process.env[envVarName];
|
|
139
|
+
if (connectionString) {
|
|
140
|
+
return redis.connectToExternalRedis(connectionString);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return await redis.startRedisContainer(properties.dockerImageName);
|
|
144
|
+
}
|
|
145
|
+
async shutdown() {
|
|
146
|
+
const instances = [...this.instanceById.values()];
|
|
147
|
+
this.instanceById.clear();
|
|
148
|
+
await Promise.all(
|
|
149
|
+
instances.map(
|
|
150
|
+
({ stop }) => stop().catch((error) => {
|
|
151
|
+
console.warn(`TestCaches: Failed to stop container`, { error });
|
|
152
|
+
})
|
|
153
|
+
)
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
exports.TestCaches = TestCaches;
|
|
159
|
+
//# sourceMappingURL=TestCaches.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestCaches.cjs.js","sources":["../../src/cache/TestCaches.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Keyv from 'keyv';\nimport { isDockerDisabledForTests } from '../util/isDockerDisabledForTests';\nimport { connectToExternalMemcache, startMemcachedContainer } from './memcache';\nimport { connectToExternalRedis, startRedisContainer } from './redis';\nimport { Instance, TestCacheId, TestCacheProperties, allCaches } from './types';\n\n/**\n * Encapsulates the creation of ephemeral test cache instances for use inside\n * unit or integration tests.\n *\n * @public\n */\nexport class TestCaches {\n private readonly instanceById: Map<string, Instance>;\n private readonly supportedIds: TestCacheId[];\n private static defaultIds?: TestCacheId[];\n\n /**\n * Creates an empty `TestCaches` instance, and sets up Jest to clean up all of\n * its acquired resources after all tests finish.\n *\n * You typically want to create just a single instance like this at the top of\n * your test file or `describe` block, and then call `init` many times on that\n * instance inside the individual tests. Spinning up a \"physical\" cache\n * instance takes a considerable amount of time, slowing down tests. But\n * wiping the contents of an instance using `init` is very fast.\n */\n static create(options?: {\n ids?: TestCacheId[];\n disableDocker?: boolean;\n }): TestCaches {\n const ids = options?.ids;\n const disableDocker = options?.disableDocker ?? isDockerDisabledForTests();\n\n let testCacheIds: TestCacheId[];\n if (ids) {\n testCacheIds = ids;\n } else if (TestCaches.defaultIds) {\n testCacheIds = TestCaches.defaultIds;\n } else {\n testCacheIds = Object.keys(allCaches) as TestCacheId[];\n }\n\n const supportedIds = testCacheIds.filter(id => {\n const properties = allCaches[id];\n if (!properties) {\n return false;\n }\n // If the caller has set up the env with an explicit connection string,\n // we'll assume that this target will work\n if (\n properties.connectionStringEnvironmentVariableName &&\n process.env[properties.connectionStringEnvironmentVariableName]\n ) {\n return true;\n }\n // If the cache doesn't require docker at all, there's nothing to worry\n // about\n if (!properties.dockerImageName) {\n return true;\n }\n // If the cache requires docker, but docker is disabled, we will fail.\n if (disableDocker) {\n return false;\n }\n return true;\n });\n\n const caches = new TestCaches(supportedIds);\n\n if (supportedIds.length > 0) {\n afterAll(async () => {\n await caches.shutdown();\n });\n }\n\n return caches;\n }\n\n static setDefaults(options: { ids?: TestCacheId[] }) {\n TestCaches.defaultIds = options.ids;\n }\n\n private constructor(supportedIds: TestCacheId[]) {\n this.instanceById = new Map();\n this.supportedIds = supportedIds;\n }\n\n supports(id: TestCacheId): boolean {\n return this.supportedIds.includes(id);\n }\n\n eachSupportedId(): [TestCacheId][] {\n return this.supportedIds.map(id => [id]);\n }\n\n /**\n * Returns a fresh, empty cache for the given driver.\n *\n * @param id - The ID of the cache to use, e.g. 'REDIS_7'\n * @returns Cache connection properties\n */\n async init(\n id: TestCacheId,\n ): Promise<{ store: string; connection: string; keyv: Keyv }> {\n const properties = allCaches[id];\n if (!properties) {\n const candidates = Object.keys(allCaches).join(', ');\n throw new Error(\n `Unknown test cache ${id}, possible values are ${candidates}`,\n );\n }\n if (!this.supportedIds.includes(id)) {\n const candidates = this.supportedIds.join(', ');\n throw new Error(\n `Unsupported test cache ${id} for this environment, possible values are ${candidates}`,\n );\n }\n\n // Ensure that a testcontainers instance is up for this ID\n let instance: Instance | undefined = this.instanceById.get(id);\n if (!instance) {\n instance = await this.initAny(properties);\n this.instanceById.set(id, instance);\n }\n\n // Ensure that it's cleared of data from previous tests\n await instance.keyv.clear();\n\n return {\n store: instance.store,\n connection: instance.connection,\n keyv: instance.keyv,\n };\n }\n\n private async initAny(properties: TestCacheProperties): Promise<Instance> {\n switch (properties.store) {\n case 'memcache':\n return this.initMemcached(properties);\n case 'redis':\n return this.initRedis(properties);\n case 'memory':\n return {\n store: 'memory',\n connection: 'memory',\n keyv: new Keyv(),\n stop: async () => {},\n };\n default:\n throw new Error(`Unknown cache store '${properties.store}'`);\n }\n }\n\n private async initMemcached(\n properties: TestCacheProperties,\n ): Promise<Instance> {\n // Use the connection string if provided\n const envVarName = properties.connectionStringEnvironmentVariableName;\n if (envVarName) {\n const connectionString = process.env[envVarName];\n if (connectionString) {\n return connectToExternalMemcache(connectionString);\n }\n }\n\n return await startMemcachedContainer(properties.dockerImageName!);\n }\n\n private async initRedis(properties: TestCacheProperties): Promise<Instance> {\n // Use the connection string if provided\n const envVarName = properties.connectionStringEnvironmentVariableName;\n if (envVarName) {\n const connectionString = process.env[envVarName];\n if (connectionString) {\n return connectToExternalRedis(connectionString);\n }\n }\n\n return await startRedisContainer(properties.dockerImageName!);\n }\n\n private async shutdown() {\n const instances = [...this.instanceById.values()];\n this.instanceById.clear();\n await Promise.all(\n instances.map(({ stop }) =>\n stop().catch(error => {\n console.warn(`TestCaches: Failed to stop container`, { error });\n }),\n ),\n );\n }\n}\n"],"names":["isDockerDisabledForTests","allCaches","Keyv","connectToExternalMemcache","startMemcachedContainer","connectToExternalRedis","startRedisContainer"],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Keyv = require('keyv');
|
|
4
|
+
var KeyvMemcache = require('@keyv/memcache');
|
|
5
|
+
var uuid = require('uuid');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var Keyv__default = /*#__PURE__*/_interopDefaultCompat(Keyv);
|
|
10
|
+
var KeyvMemcache__default = /*#__PURE__*/_interopDefaultCompat(KeyvMemcache);
|
|
11
|
+
|
|
12
|
+
async function attemptMemcachedConnection(connection) {
|
|
13
|
+
const startTime = Date.now();
|
|
14
|
+
for (; ; ) {
|
|
15
|
+
try {
|
|
16
|
+
const store = new KeyvMemcache__default.default(connection);
|
|
17
|
+
const keyv = new Keyv__default.default({ store });
|
|
18
|
+
const value = uuid.v4();
|
|
19
|
+
await keyv.set("test", value);
|
|
20
|
+
if (await keyv.get("test") === value) {
|
|
21
|
+
return keyv;
|
|
22
|
+
}
|
|
23
|
+
} catch (e) {
|
|
24
|
+
if (Date.now() - startTime > 3e4) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Timed out waiting for memcached to be ready for connections, ${e}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function connectToExternalMemcache(connection) {
|
|
34
|
+
const keyv = await attemptMemcachedConnection(connection);
|
|
35
|
+
return {
|
|
36
|
+
store: "memcache",
|
|
37
|
+
connection,
|
|
38
|
+
keyv,
|
|
39
|
+
stop: async () => await keyv.disconnect()
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function startMemcachedContainer(image) {
|
|
43
|
+
const { GenericContainer } = await import('testcontainers');
|
|
44
|
+
const container = await new GenericContainer(image).withExposedPorts(11211).start();
|
|
45
|
+
const host = container.getHost();
|
|
46
|
+
const port = container.getMappedPort(11211);
|
|
47
|
+
const connection = `${host}:${port}`;
|
|
48
|
+
const keyv = await attemptMemcachedConnection(connection);
|
|
49
|
+
return {
|
|
50
|
+
store: "memcache",
|
|
51
|
+
connection,
|
|
52
|
+
keyv,
|
|
53
|
+
stop: async () => {
|
|
54
|
+
await keyv.disconnect();
|
|
55
|
+
await container.stop({ timeout: 1e4 });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
exports.connectToExternalMemcache = connectToExternalMemcache;
|
|
61
|
+
exports.startMemcachedContainer = startMemcachedContainer;
|
|
62
|
+
//# sourceMappingURL=memcache.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memcache.cjs.js","sources":["../../src/cache/memcache.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Keyv from 'keyv';\nimport KeyvMemcache from '@keyv/memcache';\nimport { v4 as uuid } from 'uuid';\nimport { Instance } from './types';\n\nasync function attemptMemcachedConnection(connection: string): Promise<Keyv> {\n const startTime = Date.now();\n\n for (;;) {\n try {\n const store = new KeyvMemcache(connection);\n const keyv = new Keyv({ store });\n const value = uuid();\n await keyv.set('test', value);\n if ((await keyv.get('test')) === value) {\n return keyv;\n }\n } catch (e) {\n if (Date.now() - startTime > 30_000) {\n throw new Error(\n `Timed out waiting for memcached to be ready for connections, ${e}`,\n );\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n\nexport async function connectToExternalMemcache(\n connection: string,\n): Promise<Instance> {\n const keyv = await attemptMemcachedConnection(connection);\n return {\n store: 'memcache',\n connection,\n keyv,\n stop: async () => await keyv.disconnect(),\n };\n}\n\nexport async function startMemcachedContainer(\n image: string,\n): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } = await import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(11211)\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(11211);\n const connection = `${host}:${port}`;\n\n const keyv = await attemptMemcachedConnection(connection);\n\n return {\n store: 'memcache',\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["KeyvMemcache","Keyv","uuid"],"mappings":";;;;;;;;;;;AAqBA,eAAe,2BAA2B,UAAmC,EAAA;AAC3E,EAAM,MAAA,SAAA,GAAY,KAAK,GAAI,EAAA,CAAA;AAE3B,EAAS,WAAA;AACP,IAAI,IAAA;AACF,MAAM,MAAA,KAAA,GAAQ,IAAIA,6BAAA,CAAa,UAAU,CAAA,CAAA;AACzC,MAAA,MAAM,IAAO,GAAA,IAAIC,qBAAK,CAAA,EAAE,OAAO,CAAA,CAAA;AAC/B,MAAA,MAAM,QAAQC,OAAK,EAAA,CAAA;AACnB,MAAM,MAAA,IAAA,CAAK,GAAI,CAAA,MAAA,EAAQ,KAAK,CAAA,CAAA;AAC5B,MAAA,IAAK,MAAM,IAAA,CAAK,GAAI,CAAA,MAAM,MAAO,KAAO,EAAA;AACtC,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,aACO,CAAG,EAAA;AACV,MAAA,IAAI,IAAK,CAAA,GAAA,EAAQ,GAAA,SAAA,GAAY,GAAQ,EAAA;AACnC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,gEAAgE,CAAC,CAAA,CAAA;AAAA,SACnE,CAAA;AAAA,OACF;AAAA,KACF;AAEA,IAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAG,CAAC,CAAA,CAAA;AAAA,GACvD;AACF,CAAA;AAEA,eAAsB,0BACpB,UACmB,EAAA;AACnB,EAAM,MAAA,IAAA,GAAO,MAAM,0BAAA,CAA2B,UAAU,CAAA,CAAA;AACxD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,UAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAM,EAAA,YAAY,MAAM,IAAA,CAAK,UAAW,EAAA;AAAA,GAC1C,CAAA;AACF,CAAA;AAEA,eAAsB,wBACpB,KACmB,EAAA;AAEnB,EAAA,MAAM,EAAE,gBAAA,EAAqB,GAAA,MAAM,OAAO,gBAAgB,CAAA,CAAA;AAE1D,EAAM,MAAA,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAC/C,CAAA,gBAAA,CAAiB,KAAK,CAAA,CACtB,KAAM,EAAA,CAAA;AAET,EAAM,MAAA,IAAA,GAAO,UAAU,OAAQ,EAAA,CAAA;AAC/B,EAAM,MAAA,IAAA,GAAO,SAAU,CAAA,aAAA,CAAc,KAAK,CAAA,CAAA;AAC1C,EAAA,MAAM,UAAa,GAAA,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,CAAA;AAElC,EAAM,MAAA,IAAA,GAAO,MAAM,0BAAA,CAA2B,UAAU,CAAA,CAAA;AAExD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,UAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAW,EAAA,CAAA;AACtB,MAAA,MAAM,SAAU,CAAA,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA,CAAA;AAAA,KAC1C;AAAA,GACF,CAAA;AACF;;;;;"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var Keyv = require('keyv');
|
|
4
|
+
var KeyvRedis = require('@keyv/redis');
|
|
5
|
+
var uuid = require('uuid');
|
|
6
|
+
|
|
7
|
+
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
8
|
+
|
|
9
|
+
var Keyv__default = /*#__PURE__*/_interopDefaultCompat(Keyv);
|
|
10
|
+
var KeyvRedis__default = /*#__PURE__*/_interopDefaultCompat(KeyvRedis);
|
|
11
|
+
|
|
12
|
+
async function attemptRedisConnection(connection) {
|
|
13
|
+
const startTime = Date.now();
|
|
14
|
+
for (; ; ) {
|
|
15
|
+
try {
|
|
16
|
+
const store = new KeyvRedis__default.default(connection);
|
|
17
|
+
const keyv = new Keyv__default.default({ store });
|
|
18
|
+
const value = uuid.v4();
|
|
19
|
+
await keyv.set("test", value);
|
|
20
|
+
if (await keyv.get("test") === value) {
|
|
21
|
+
return keyv;
|
|
22
|
+
}
|
|
23
|
+
} catch (e) {
|
|
24
|
+
if (Date.now() - startTime > 3e4) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Timed out waiting for redis to be ready for connections, ${e}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function connectToExternalRedis(connection) {
|
|
34
|
+
const keyv = await attemptRedisConnection(connection);
|
|
35
|
+
return {
|
|
36
|
+
store: "redis",
|
|
37
|
+
connection,
|
|
38
|
+
keyv,
|
|
39
|
+
stop: async () => await keyv.disconnect()
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function startRedisContainer(image) {
|
|
43
|
+
const { GenericContainer } = await import('testcontainers');
|
|
44
|
+
const container = await new GenericContainer(image).withExposedPorts(6379).start();
|
|
45
|
+
const host = container.getHost();
|
|
46
|
+
const port = container.getMappedPort(6379);
|
|
47
|
+
const connection = `redis://${host}:${port}`;
|
|
48
|
+
const keyv = await attemptRedisConnection(connection);
|
|
49
|
+
return {
|
|
50
|
+
store: "redis",
|
|
51
|
+
connection,
|
|
52
|
+
keyv,
|
|
53
|
+
stop: async () => {
|
|
54
|
+
await keyv.disconnect();
|
|
55
|
+
await container.stop({ timeout: 1e4 });
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
exports.connectToExternalRedis = connectToExternalRedis;
|
|
61
|
+
exports.startRedisContainer = startRedisContainer;
|
|
62
|
+
//# sourceMappingURL=redis.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis.cjs.js","sources":["../../src/cache/redis.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Keyv from 'keyv';\nimport KeyvRedis from '@keyv/redis';\nimport { v4 as uuid } from 'uuid';\nimport { Instance } from './types';\n\nasync function attemptRedisConnection(connection: string): Promise<Keyv> {\n const startTime = Date.now();\n\n for (;;) {\n try {\n const store = new KeyvRedis(connection);\n const keyv = new Keyv({ store });\n const value = uuid();\n await keyv.set('test', value);\n if ((await keyv.get('test')) === value) {\n return keyv;\n }\n } catch (e) {\n if (Date.now() - startTime > 30_000) {\n throw new Error(\n `Timed out waiting for redis to be ready for connections, ${e}`,\n );\n }\n }\n\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n}\n\nexport async function connectToExternalRedis(\n connection: string,\n): Promise<Instance> {\n const keyv = await attemptRedisConnection(connection);\n return {\n store: 'redis',\n connection,\n keyv,\n stop: async () => await keyv.disconnect(),\n };\n}\n\nexport async function startRedisContainer(image: string): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } = await import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(6379)\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(6379);\n const connection = `redis://${host}:${port}`;\n\n const keyv = await attemptRedisConnection(connection);\n\n return {\n store: 'redis',\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["KeyvRedis","Keyv","uuid"],"mappings":";;;;;;;;;;;AAqBA,eAAe,uBAAuB,UAAmC,EAAA;AACvE,EAAM,MAAA,SAAA,GAAY,KAAK,GAAI,EAAA,CAAA;AAE3B,EAAS,WAAA;AACP,IAAI,IAAA;AACF,MAAM,MAAA,KAAA,GAAQ,IAAIA,0BAAA,CAAU,UAAU,CAAA,CAAA;AACtC,MAAA,MAAM,IAAO,GAAA,IAAIC,qBAAK,CAAA,EAAE,OAAO,CAAA,CAAA;AAC/B,MAAA,MAAM,QAAQC,OAAK,EAAA,CAAA;AACnB,MAAM,MAAA,IAAA,CAAK,GAAI,CAAA,MAAA,EAAQ,KAAK,CAAA,CAAA;AAC5B,MAAA,IAAK,MAAM,IAAA,CAAK,GAAI,CAAA,MAAM,MAAO,KAAO,EAAA;AACtC,QAAO,OAAA,IAAA,CAAA;AAAA,OACT;AAAA,aACO,CAAG,EAAA;AACV,MAAA,IAAI,IAAK,CAAA,GAAA,EAAQ,GAAA,SAAA,GAAY,GAAQ,EAAA;AACnC,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,4DAA4D,CAAC,CAAA,CAAA;AAAA,SAC/D,CAAA;AAAA,OACF;AAAA,KACF;AAEA,IAAA,MAAM,IAAI,OAAQ,CAAA,CAAA,OAAA,KAAW,UAAW,CAAA,OAAA,EAAS,GAAG,CAAC,CAAA,CAAA;AAAA,GACvD;AACF,CAAA;AAEA,eAAsB,uBACpB,UACmB,EAAA;AACnB,EAAM,MAAA,IAAA,GAAO,MAAM,sBAAA,CAAuB,UAAU,CAAA,CAAA;AACpD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,OAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,IAAM,EAAA,YAAY,MAAM,IAAA,CAAK,UAAW,EAAA;AAAA,GAC1C,CAAA;AACF,CAAA;AAEA,eAAsB,oBAAoB,KAAkC,EAAA;AAE1E,EAAA,MAAM,EAAE,gBAAA,EAAqB,GAAA,MAAM,OAAO,gBAAgB,CAAA,CAAA;AAE1D,EAAM,MAAA,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAC/C,CAAA,gBAAA,CAAiB,IAAI,CAAA,CACrB,KAAM,EAAA,CAAA;AAET,EAAM,MAAA,IAAA,GAAO,UAAU,OAAQ,EAAA,CAAA;AAC/B,EAAM,MAAA,IAAA,GAAO,SAAU,CAAA,aAAA,CAAc,IAAI,CAAA,CAAA;AACzC,EAAA,MAAM,UAAa,GAAA,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA,CAAA;AAE1C,EAAM,MAAA,IAAA,GAAO,MAAM,sBAAA,CAAuB,UAAU,CAAA,CAAA;AAEpD,EAAO,OAAA;AAAA,IACL,KAAO,EAAA,OAAA;AAAA,IACP,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAW,EAAA,CAAA;AACtB,MAAA,MAAM,SAAU,CAAA,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA,CAAA;AAAA,KAC1C;AAAA,GACF,CAAA;AACF;;;;;"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var getDockerImageForName = require('../util/getDockerImageForName.cjs.js');
|
|
4
|
+
|
|
5
|
+
const allCaches = Object.freeze({
|
|
6
|
+
REDIS_7: {
|
|
7
|
+
name: "Redis 7.x",
|
|
8
|
+
store: "redis",
|
|
9
|
+
dockerImageName: getDockerImageForName.getDockerImageForName("redis:7"),
|
|
10
|
+
connectionStringEnvironmentVariableName: "BACKSTAGE_TEST_CACHE_REDIS7_CONNECTION_STRING"
|
|
11
|
+
},
|
|
12
|
+
MEMCACHED_1: {
|
|
13
|
+
name: "Memcached 1.x",
|
|
14
|
+
store: "memcache",
|
|
15
|
+
dockerImageName: getDockerImageForName.getDockerImageForName("memcached:1"),
|
|
16
|
+
connectionStringEnvironmentVariableName: "BACKSTAGE_TEST_CACHE_MEMCACHED1_CONNECTION_STRING"
|
|
17
|
+
},
|
|
18
|
+
MEMORY: {
|
|
19
|
+
name: "In-memory",
|
|
20
|
+
store: "memory"
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
exports.allCaches = allCaches;
|
|
25
|
+
//# sourceMappingURL=types.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.cjs.js","sources":["../../src/cache/types.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport Keyv from 'keyv';\nimport { getDockerImageForName } from '../util/getDockerImageForName';\n\n/**\n * The possible caches to test against.\n *\n * @public\n */\nexport type TestCacheId = 'MEMORY' | 'REDIS_7' | 'MEMCACHED_1';\n\nexport type TestCacheProperties = {\n name: string;\n store: string;\n dockerImageName?: string;\n connectionStringEnvironmentVariableName?: string;\n};\n\nexport type Instance = {\n store: string;\n connection: string;\n keyv: Keyv;\n stop: () => Promise<void>;\n};\n\nexport const allCaches: Record<TestCacheId, TestCacheProperties> =\n Object.freeze({\n REDIS_7: {\n name: 'Redis 7.x',\n store: 'redis',\n dockerImageName: getDockerImageForName('redis:7'),\n connectionStringEnvironmentVariableName:\n 'BACKSTAGE_TEST_CACHE_REDIS7_CONNECTION_STRING',\n },\n MEMCACHED_1: {\n name: 'Memcached 1.x',\n store: 'memcache',\n dockerImageName: getDockerImageForName('memcached:1'),\n connectionStringEnvironmentVariableName:\n 'BACKSTAGE_TEST_CACHE_MEMCACHED1_CONNECTION_STRING',\n },\n MEMORY: {\n name: 'In-memory',\n store: 'memory',\n },\n });\n"],"names":["getDockerImageForName"],"mappings":";;;;AAwCa,MAAA,SAAA,GACX,OAAO,MAAO,CAAA;AAAA,EACZ,OAAS,EAAA;AAAA,IACP,IAAM,EAAA,WAAA;AAAA,IACN,KAAO,EAAA,OAAA;AAAA,IACP,eAAA,EAAiBA,4CAAsB,SAAS,CAAA;AAAA,IAChD,uCACE,EAAA,+CAAA;AAAA,GACJ;AAAA,EACA,WAAa,EAAA;AAAA,IACX,IAAM,EAAA,eAAA;AAAA,IACN,KAAO,EAAA,UAAA;AAAA,IACP,eAAA,EAAiBA,4CAAsB,aAAa,CAAA;AAAA,IACpD,uCACE,EAAA,mDAAA;AAAA,GACJ;AAAA,EACA,MAAQ,EAAA;AAAA,IACN,IAAM,EAAA,WAAA;AAAA,IACN,KAAO,EAAA,QAAA;AAAA,GACT;AACF,CAAC;;;;"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var isDockerDisabledForTests = require('../util/isDockerDisabledForTests.cjs.js');
|
|
4
|
+
var mysql = require('./mysql.cjs.js');
|
|
5
|
+
var postgres = require('./postgres.cjs.js');
|
|
6
|
+
var sqlite = require('./sqlite.cjs.js');
|
|
7
|
+
var types = require('./types.cjs.js');
|
|
8
|
+
|
|
9
|
+
class TestDatabases {
|
|
10
|
+
engineFactoryByDriver = {
|
|
11
|
+
pg: postgres.PostgresEngine.create,
|
|
12
|
+
mysql: mysql.MysqlEngine.create,
|
|
13
|
+
mysql2: mysql.MysqlEngine.create,
|
|
14
|
+
"better-sqlite3": sqlite.SqliteEngine.create,
|
|
15
|
+
sqlite3: sqlite.SqliteEngine.create
|
|
16
|
+
};
|
|
17
|
+
engineByTestDatabaseId;
|
|
18
|
+
supportedIds;
|
|
19
|
+
static defaultIds;
|
|
20
|
+
/**
|
|
21
|
+
* Creates an empty `TestDatabases` instance, and sets up Jest to clean up
|
|
22
|
+
* all of its acquired resources after all tests finish.
|
|
23
|
+
*
|
|
24
|
+
* You typically want to create just a single instance like this at the top
|
|
25
|
+
* of your test file or `describe` block, and then call `init` many times on
|
|
26
|
+
* that instance inside the individual tests. Spinning up a "physical"
|
|
27
|
+
* database instance takes a considerable amount of time, slowing down tests.
|
|
28
|
+
* But initializing a new logical database inside that instance using `init`
|
|
29
|
+
* is very fast.
|
|
30
|
+
*/
|
|
31
|
+
static create(options) {
|
|
32
|
+
const ids = options?.ids;
|
|
33
|
+
const disableDocker = options?.disableDocker ?? isDockerDisabledForTests.isDockerDisabledForTests();
|
|
34
|
+
let testDatabaseIds;
|
|
35
|
+
if (ids) {
|
|
36
|
+
testDatabaseIds = ids;
|
|
37
|
+
} else if (TestDatabases.defaultIds) {
|
|
38
|
+
testDatabaseIds = TestDatabases.defaultIds;
|
|
39
|
+
} else {
|
|
40
|
+
testDatabaseIds = Object.keys(types.allDatabases);
|
|
41
|
+
}
|
|
42
|
+
const supportedIds = testDatabaseIds.filter((id) => {
|
|
43
|
+
const properties = types.allDatabases[id];
|
|
44
|
+
if (!properties) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
if (properties.connectionStringEnvironmentVariableName && process.env[properties.connectionStringEnvironmentVariableName]) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
if (!properties.dockerImageName) {
|
|
51
|
+
return true;
|
|
52
|
+
}
|
|
53
|
+
if (disableDocker) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
57
|
+
});
|
|
58
|
+
const databases = new TestDatabases(supportedIds);
|
|
59
|
+
if (supportedIds.length > 0) {
|
|
60
|
+
afterAll(async () => {
|
|
61
|
+
await databases.shutdown();
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return databases;
|
|
65
|
+
}
|
|
66
|
+
static setDefaults(options) {
|
|
67
|
+
TestDatabases.defaultIds = options.ids;
|
|
68
|
+
}
|
|
69
|
+
constructor(supportedIds) {
|
|
70
|
+
this.engineByTestDatabaseId = /* @__PURE__ */ new Map();
|
|
71
|
+
this.supportedIds = supportedIds;
|
|
72
|
+
}
|
|
73
|
+
supports(id) {
|
|
74
|
+
return this.supportedIds.includes(id);
|
|
75
|
+
}
|
|
76
|
+
eachSupportedId() {
|
|
77
|
+
return this.supportedIds.map((id) => [id]);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Returns a fresh, unique, empty logical database on an instance of the
|
|
81
|
+
* given database ID platform.
|
|
82
|
+
*
|
|
83
|
+
* @param id - The ID of the database platform to use, e.g. 'POSTGRES_13'
|
|
84
|
+
* @returns A `Knex` connection object
|
|
85
|
+
*/
|
|
86
|
+
async init(id) {
|
|
87
|
+
const properties = types.allDatabases[id];
|
|
88
|
+
if (!properties) {
|
|
89
|
+
const candidates = Object.keys(types.allDatabases).join(", ");
|
|
90
|
+
throw new Error(
|
|
91
|
+
`Unknown test database ${id}, possible values are ${candidates}`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
if (!this.supportedIds.includes(id)) {
|
|
95
|
+
const candidates = this.supportedIds.join(", ");
|
|
96
|
+
throw new Error(
|
|
97
|
+
`Unsupported test database ${id} for this environment, possible values are ${candidates}`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
let engine = this.engineByTestDatabaseId.get(id);
|
|
101
|
+
if (!engine) {
|
|
102
|
+
const factory = this.engineFactoryByDriver[properties.driver];
|
|
103
|
+
if (!factory) {
|
|
104
|
+
throw new Error(`Unknown database driver ${properties.driver}`);
|
|
105
|
+
}
|
|
106
|
+
engine = await factory(properties);
|
|
107
|
+
this.engineByTestDatabaseId.set(id, engine);
|
|
108
|
+
}
|
|
109
|
+
return await engine.createDatabaseInstance();
|
|
110
|
+
}
|
|
111
|
+
async shutdown() {
|
|
112
|
+
const engines = [...this.engineByTestDatabaseId.values()];
|
|
113
|
+
this.engineByTestDatabaseId.clear();
|
|
114
|
+
for (const engine of engines) {
|
|
115
|
+
try {
|
|
116
|
+
await engine.shutdown();
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.warn(`TestDatabases: Failed to shutdown engine`, {
|
|
119
|
+
engine,
|
|
120
|
+
error
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
exports.TestDatabases = TestDatabases;
|
|
128
|
+
//# sourceMappingURL=TestDatabases.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TestDatabases.cjs.js","sources":["../../src/database/TestDatabases.ts"],"sourcesContent":["/*\n * Copyright 2021 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Knex } from 'knex';\nimport { isDockerDisabledForTests } from '../util/isDockerDisabledForTests';\nimport { MysqlEngine } from './mysql';\nimport { PostgresEngine } from './postgres';\nimport { SqliteEngine } from './sqlite';\nimport {\n Engine,\n TestDatabaseId,\n TestDatabaseProperties,\n allDatabases,\n} from './types';\n\n/**\n * Encapsulates the creation of ephemeral test database instances for use\n * inside unit or integration tests.\n *\n * @public\n */\nexport class TestDatabases {\n private readonly engineFactoryByDriver: Record<\n string,\n (properties: TestDatabaseProperties) => Promise<Engine>\n > = {\n pg: PostgresEngine.create,\n mysql: MysqlEngine.create,\n mysql2: MysqlEngine.create,\n 'better-sqlite3': SqliteEngine.create,\n sqlite3: SqliteEngine.create,\n };\n private readonly engineByTestDatabaseId: Map<string, Engine>;\n private readonly supportedIds: TestDatabaseId[];\n private static defaultIds?: TestDatabaseId[];\n\n /**\n * Creates an empty `TestDatabases` instance, and sets up Jest to clean up\n * all of its acquired resources after all tests finish.\n *\n * You typically want to create just a single instance like this at the top\n * of your test file or `describe` block, and then call `init` many times on\n * that instance inside the individual tests. Spinning up a \"physical\"\n * database instance takes a considerable amount of time, slowing down tests.\n * But initializing a new logical database inside that instance using `init`\n * is very fast.\n */\n static create(options?: {\n ids?: TestDatabaseId[];\n disableDocker?: boolean;\n }): TestDatabases {\n const ids = options?.ids;\n const disableDocker = options?.disableDocker ?? isDockerDisabledForTests();\n\n let testDatabaseIds: TestDatabaseId[];\n if (ids) {\n testDatabaseIds = ids;\n } else if (TestDatabases.defaultIds) {\n testDatabaseIds = TestDatabases.defaultIds;\n } else {\n testDatabaseIds = Object.keys(allDatabases) as TestDatabaseId[];\n }\n\n const supportedIds = testDatabaseIds.filter(id => {\n const properties = allDatabases[id];\n if (!properties) {\n return false;\n }\n // If the caller has set up the env with an explicit connection string,\n // we'll assume that this database will work\n if (\n properties.connectionStringEnvironmentVariableName &&\n process.env[properties.connectionStringEnvironmentVariableName]\n ) {\n return true;\n }\n // If the database doesn't require docker at all, there's nothing to worry\n // about\n if (!properties.dockerImageName) {\n return true;\n }\n // If the database requires docker, but docker is disabled, we will fail.\n if (disableDocker) {\n return false;\n }\n return true;\n });\n\n const databases = new TestDatabases(supportedIds);\n\n if (supportedIds.length > 0) {\n afterAll(async () => {\n await databases.shutdown();\n });\n }\n\n return databases;\n }\n\n static setDefaults(options: { ids?: TestDatabaseId[] }) {\n TestDatabases.defaultIds = options.ids;\n }\n\n private constructor(supportedIds: TestDatabaseId[]) {\n this.engineByTestDatabaseId = new Map();\n this.supportedIds = supportedIds;\n }\n\n supports(id: TestDatabaseId): boolean {\n return this.supportedIds.includes(id);\n }\n\n eachSupportedId(): [TestDatabaseId][] {\n return this.supportedIds.map(id => [id]);\n }\n\n /**\n * Returns a fresh, unique, empty logical database on an instance of the\n * given database ID platform.\n *\n * @param id - The ID of the database platform to use, e.g. 'POSTGRES_13'\n * @returns A `Knex` connection object\n */\n async init(id: TestDatabaseId): Promise<Knex> {\n const properties = allDatabases[id];\n if (!properties) {\n const candidates = Object.keys(allDatabases).join(', ');\n throw new Error(\n `Unknown test database ${id}, possible values are ${candidates}`,\n );\n }\n if (!this.supportedIds.includes(id)) {\n const candidates = this.supportedIds.join(', ');\n throw new Error(\n `Unsupported test database ${id} for this environment, possible values are ${candidates}`,\n );\n }\n\n let engine = this.engineByTestDatabaseId.get(id);\n if (!engine) {\n const factory = this.engineFactoryByDriver[properties.driver];\n if (!factory) {\n throw new Error(`Unknown database driver ${properties.driver}`);\n }\n engine = await factory(properties);\n this.engineByTestDatabaseId.set(id, engine);\n }\n\n return await engine.createDatabaseInstance();\n }\n\n private async shutdown() {\n const engines = [...this.engineByTestDatabaseId.values()];\n this.engineByTestDatabaseId.clear();\n\n for (const engine of engines) {\n try {\n await engine.shutdown();\n } catch (error) {\n console.warn(`TestDatabases: Failed to shutdown engine`, {\n engine,\n error,\n });\n }\n }\n }\n}\n"],"names":["PostgresEngine","MysqlEngine","SqliteEngine","isDockerDisabledForTests","allDatabases"],"mappings":"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"}
|