@backstage/backend-test-utils 1.11.3-next.0 → 1.11.3-next.2

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 CHANGED
@@ -1,5 +1,24 @@
1
1
  # @backstage/backend-test-utils
2
2
 
3
+ ## 1.11.3-next.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 7fb12b8: Added a new tracing service mock to be leveraged in tests
8
+ - Updated dependencies
9
+ - @backstage/backend-plugin-api@1.9.1-next.1
10
+ - @backstage/backend-defaults@0.17.1-next.2
11
+
12
+ ## 1.11.3-next.1
13
+
14
+ ### Patch Changes
15
+
16
+ - e9b78e9: Removed the `uuid` dependency and replaced usage with the built-in `crypto.randomUUID()`.
17
+ - Updated dependencies
18
+ - @backstage/backend-defaults@0.17.1-next.1
19
+ - @backstage/plugin-auth-node@0.7.1-next.1
20
+ - @backstage/plugin-permission-common@0.9.9-next.1
21
+
3
22
  ## 1.11.3-next.0
4
23
 
5
24
  ### Patch Changes
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ var backendPluginApi = require('@backstage/backend-plugin-api');
4
+ var alpha$1 = require('@backstage/backend-plugin-api/alpha');
5
+ var alpha = require('@backstage/backend-defaults/alpha');
6
+
7
+ exports.tracingServiceMock = void 0;
8
+ ((tracingServiceMock2) => {
9
+ tracingServiceMock2.factory = () => alpha.tracingServiceFactory;
10
+ tracingServiceMock2.mock = () => {
11
+ const spans = [];
12
+ const startActiveSpan = jest.fn(async (_name, fn, _options) => {
13
+ const span = {
14
+ setAttribute: jest.fn(),
15
+ setStatus: jest.fn()
16
+ };
17
+ spans.push(span);
18
+ return await fn(span);
19
+ });
20
+ const service = { startActiveSpan };
21
+ return Object.assign(service, {
22
+ spans,
23
+ factory: backendPluginApi.createServiceFactory({
24
+ service: alpha$1.tracingServiceRef,
25
+ deps: {},
26
+ factory: () => service
27
+ })
28
+ });
29
+ };
30
+ })(exports.tracingServiceMock || (exports.tracingServiceMock = {}));
31
+ //# sourceMappingURL=TracingServiceMock.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"TracingServiceMock.cjs.js","sources":["../../../src/alpha/services/TracingServiceMock.ts"],"sourcesContent":["/*\n * Copyright 2026 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 {\n createServiceFactory,\n ServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport {\n TracingService,\n TracingServiceAttributeValue,\n TracingServiceSpan,\n TracingServiceSpanStatus,\n tracingServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\nimport { tracingServiceFactory } from '@backstage/backend-defaults/alpha';\n\n/**\n * A jest-mocked span captured by {@link TracingServiceMock}.\n *\n * @alpha\n */\nexport interface MockedTracingServiceSpan extends TracingServiceSpan {\n setAttribute: jest.Mock<void, [string, TracingServiceAttributeValue]>;\n setStatus: jest.Mock<void, [TracingServiceSpanStatus]>;\n}\n\n/**\n * Mock for the `TracingService`. Captures every span created via\n * `startActiveSpan` so tests can assert on the options passed in and the\n * methods called on the span inside the callback.\n *\n * @alpha\n */\nexport interface TracingServiceMock extends TracingService {\n startActiveSpan: jest.MockedFunction<TracingService['startActiveSpan']>;\n /** Spans created by `startActiveSpan` calls, in order. */\n spans: MockedTracingServiceSpan[];\n factory: ServiceFactory<TracingService>;\n}\n\n/**\n * @alpha\n */\nexport namespace tracingServiceMock {\n /**\n * Returns the real `tracingServiceFactory` from `@backstage/backend-defaults`,\n * for tests that want the full default implementation.\n */\n export const factory = () => tracingServiceFactory;\n\n /**\n * Builds a mock `TracingService` backed by jest mocks.\n */\n export const mock = (): TracingServiceMock => {\n const spans: MockedTracingServiceSpan[] = [];\n const startActiveSpan = jest.fn(async (_name, fn, _options) => {\n const span: MockedTracingServiceSpan = {\n setAttribute: jest.fn(),\n setStatus: jest.fn(),\n };\n spans.push(span);\n return await fn(span);\n }) as TracingServiceMock['startActiveSpan'];\n\n const service: TracingService = { startActiveSpan };\n\n return Object.assign(service as TracingServiceMock, {\n spans,\n factory: createServiceFactory({\n service: tracingServiceRef,\n deps: {},\n factory: () => service,\n }),\n });\n };\n}\n"],"names":["tracingServiceMock","tracingServiceFactory","createServiceFactory","tracingServiceRef"],"mappings":";;;;;;AAwDiBA;AAAA,CAAV,CAAUA,mBAAAA,KAAV;AAKE,EAAMA,mBAAAA,CAAA,UAAU,MAAMC,2BAAA;AAKtB,EAAMD,mBAAAA,CAAA,OAAO,MAA0B;AAC5C,IAAA,MAAM,QAAoC,EAAC;AAC3C,IAAA,MAAM,kBAAkB,IAAA,CAAK,EAAA,CAAG,OAAO,KAAA,EAAO,IAAI,QAAA,KAAa;AAC7D,MAAA,MAAM,IAAA,GAAiC;AAAA,QACrC,YAAA,EAAc,KAAK,EAAA,EAAG;AAAA,QACtB,SAAA,EAAW,KAAK,EAAA;AAAG,OACrB;AACA,MAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AACf,MAAA,OAAO,MAAM,GAAG,IAAI,CAAA;AAAA,IACtB,CAAC,CAAA;AAED,IAAA,MAAM,OAAA,GAA0B,EAAE,eAAA,EAAgB;AAElD,IAAA,OAAO,MAAA,CAAO,OAAO,OAAA,EAA+B;AAAA,MAClD,KAAA;AAAA,MACA,SAASE,qCAAA,CAAqB;AAAA,QAC5B,OAAA,EAASC,yBAAA;AAAA,QACT,MAAM,EAAC;AAAA,QACP,SAAS,MAAM;AAAA,OAChB;AAAA,KACF,CAAA;AAAA,EACH,CAAA;AAAA,CAAA,EA/BeH,0BAAA,KAAAA,0BAAA,GAAA,EAAA,CAAA,CAAA;;"}
package/dist/alpha.cjs.js CHANGED
@@ -4,6 +4,7 @@ var ActionsRegistryServiceMock = require('./alpha/services/ActionsRegistryServic
4
4
  var MockActionsRegistry = require('./alpha/services/MockActionsRegistry.cjs.js');
5
5
  var ActionsServiceMock = require('./alpha/services/ActionsServiceMock.cjs.js');
6
6
  var MetricsServiceMock = require('./alpha/services/MetricsServiceMock.cjs.js');
7
+ var TracingServiceMock = require('./alpha/services/TracingServiceMock.cjs.js');
7
8
 
8
9
 
9
10
 
@@ -20,4 +21,8 @@ Object.defineProperty(exports, "metricsServiceMock", {
20
21
  enumerable: true,
21
22
  get: function () { return MetricsServiceMock.metricsServiceMock; }
22
23
  });
24
+ Object.defineProperty(exports, "tracingServiceMock", {
25
+ enumerable: true,
26
+ get: function () { return TracingServiceMock.tracingServiceMock; }
27
+ });
23
28
  //# sourceMappingURL=alpha.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"alpha.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/alpha.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { S as ServiceMock } from './types/createServiceMock.d-CeKvILsY.js';
2
2
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
3
- import { LoggerService, BackstageCredentials } from '@backstage/backend-plugin-api';
3
+ import { LoggerService, BackstageCredentials, ServiceFactory } from '@backstage/backend-plugin-api';
4
4
  import * as _backstage_backend_plugin_api_alpha from '@backstage/backend-plugin-api/alpha';
5
- import { ActionsRegistryService, ActionsService, ActionsRegistryActionOptions, ActionsServiceAction, MetricsService } from '@backstage/backend-plugin-api/alpha';
5
+ import { ActionsRegistryService, ActionsService, ActionsRegistryActionOptions, ActionsServiceAction, MetricsService, TracingServiceSpan, TracingServiceAttributeValue, TracingServiceSpanStatus, TracingService } from '@backstage/backend-plugin-api/alpha';
6
6
  import { JsonObject, JsonValue } from '@backstage/types';
7
7
  import { AnyZodObject } from 'zod/v3';
8
8
 
@@ -89,4 +89,42 @@ declare namespace metricsServiceMock {
89
89
  const mock: (partialImpl?: Partial<MetricsService> | undefined) => ServiceMock<MetricsService>;
90
90
  }
91
91
 
92
- export { MockActionsRegistry, ServiceMock, actionsRegistryServiceMock, actionsServiceMock, metricsServiceMock };
92
+ /**
93
+ * A jest-mocked span captured by {@link TracingServiceMock}.
94
+ *
95
+ * @alpha
96
+ */
97
+ interface MockedTracingServiceSpan extends TracingServiceSpan {
98
+ setAttribute: jest.Mock<void, [string, TracingServiceAttributeValue]>;
99
+ setStatus: jest.Mock<void, [TracingServiceSpanStatus]>;
100
+ }
101
+ /**
102
+ * Mock for the `TracingService`. Captures every span created via
103
+ * `startActiveSpan` so tests can assert on the options passed in and the
104
+ * methods called on the span inside the callback.
105
+ *
106
+ * @alpha
107
+ */
108
+ interface TracingServiceMock extends TracingService {
109
+ startActiveSpan: jest.MockedFunction<TracingService['startActiveSpan']>;
110
+ /** Spans created by `startActiveSpan` calls, in order. */
111
+ spans: MockedTracingServiceSpan[];
112
+ factory: ServiceFactory<TracingService>;
113
+ }
114
+ /**
115
+ * @alpha
116
+ */
117
+ declare namespace tracingServiceMock {
118
+ /**
119
+ * Returns the real `tracingServiceFactory` from `@backstage/backend-defaults`,
120
+ * for tests that want the full default implementation.
121
+ */
122
+ const factory: () => ServiceFactory<TracingService, "plugin", "singleton">;
123
+ /**
124
+ * Builds a mock `TracingService` backed by jest mocks.
125
+ */
126
+ const mock: () => TracingServiceMock;
127
+ }
128
+
129
+ export { MockActionsRegistry, ServiceMock, actionsRegistryServiceMock, actionsServiceMock, metricsServiceMock, tracingServiceMock };
130
+ export type { MockedTracingServiceSpan, TracingServiceMock };
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var Keyv = require('keyv');
4
- var uuid = require('uuid');
4
+ var node_crypto = require('node:crypto');
5
5
  var waitForReady = require('../util/waitForReady.cjs.js');
6
6
 
7
7
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
@@ -15,7 +15,7 @@ async function attemptKeyvConnection(createStore, connection, label) {
15
15
  const attemptKeyv = new Keyv__default.default({ store });
16
16
  let succeeded = false;
17
17
  try {
18
- const value = uuid.v4();
18
+ const value = node_crypto.randomUUID();
19
19
  await attemptKeyv.set("test", value);
20
20
  succeeded = await attemptKeyv.get("test") === value;
21
21
  if (succeeded) {
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.cjs.js","sources":["../../src/cache/helpers.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, { type KeyvStoreAdapter } from 'keyv';\nimport { v4 as uuid } from 'uuid';\nimport { waitForReady } from '../util/waitForReady';\nimport { Instance } from './types';\n\n/**\n * Polls a Keyv store until a set/get round-trip succeeds.\n */\nexport async function attemptKeyvConnection(\n createStore: (connection: string) => KeyvStoreAdapter,\n connection: string,\n label: string,\n): Promise<Keyv> {\n let keyv: Keyv | undefined;\n\n await waitForReady(async () => {\n const store = createStore(connection);\n const attemptKeyv = new Keyv({ store });\n let succeeded = false;\n\n try {\n const value = uuid();\n await attemptKeyv.set('test', value);\n succeeded = (await attemptKeyv.get('test')) === value;\n if (succeeded) {\n keyv = attemptKeyv;\n }\n return succeeded;\n } finally {\n if (!succeeded) {\n await attemptKeyv.disconnect();\n }\n }\n }, label);\n\n return keyv!;\n}\n\n/**\n * Starts a Redis-protocol-compatible container (Redis, Valkey, etc.) on port\n * 6379 and waits until a Keyv round-trip succeeds.\n */\nexport async function startRedisLikeContainer(\n image: string,\n store: string,\n createStore: (connection: string) => KeyvStoreAdapter,\n): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof 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 attemptKeyvConnection(createStore, connection, store);\n\n return {\n store,\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["waitForReady","Keyv","uuid"],"mappings":";;;;;;;;;;AAwBA,eAAsB,qBAAA,CACpB,WAAA,EACA,UAAA,EACA,KAAA,EACe;AACf,EAAA,IAAI,IAAA;AAEJ,EAAA,MAAMA,0BAAa,YAAY;AAC7B,IAAA,MAAM,KAAA,GAAQ,YAAY,UAAU,CAAA;AACpC,IAAA,MAAM,WAAA,GAAc,IAAIC,qBAAA,CAAK,EAAE,OAAO,CAAA;AACtC,IAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,IAAA,IAAI;AACF,MAAA,MAAM,QAAQC,OAAA,EAAK;AACnB,MAAA,MAAM,WAAA,CAAY,GAAA,CAAI,MAAA,EAAQ,KAAK,CAAA;AACnC,MAAA,SAAA,GAAa,MAAM,WAAA,CAAY,GAAA,CAAI,MAAM,CAAA,KAAO,KAAA;AAChD,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,IAAA,GAAO,WAAA;AAAA,MACT;AACA,MAAA,OAAO,SAAA;AAAA,IACT,CAAA,SAAE;AACA,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,MAAM,YAAY,UAAA,EAAW;AAAA,MAC/B;AAAA,IACF;AAAA,EACF,GAAG,KAAK,CAAA;AAER,EAAA,OAAO,IAAA;AACT;AAMA,eAAsB,uBAAA,CACpB,KAAA,EACA,KAAA,EACA,WAAA,EACmB;AAEnB,EAAA,MAAM,EAAE,gBAAA,EAAiB,GACvB,OAAA,CAAQ,gBAAgB,CAAA;AAE1B,EAAA,MAAM,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAAA,CAC/C,gBAAA,CAAiB,IAAI,CAAA,CACrB,KAAA,EAAM;AAET,EAAA,MAAM,IAAA,GAAO,UAAU,OAAA,EAAQ;AAC/B,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,aAAA,CAAc,IAAI,CAAA;AACzC,EAAA,MAAM,UAAA,GAAa,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAE1C,EAAA,MAAM,IAAA,GAAO,MAAM,qBAAA,CAAsB,WAAA,EAAa,YAAY,KAAK,CAAA;AAEvE,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAA,EAAW;AACtB,MAAA,MAAM,SAAA,CAAU,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA;AAAA,IAC1C;AAAA,GACF;AACF;;;;;"}
1
+ {"version":3,"file":"helpers.cjs.js","sources":["../../src/cache/helpers.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, { type KeyvStoreAdapter } from 'keyv';\nimport { randomUUID as uuid } from 'node:crypto';\nimport { waitForReady } from '../util/waitForReady';\nimport { Instance } from './types';\n\n/**\n * Polls a Keyv store until a set/get round-trip succeeds.\n */\nexport async function attemptKeyvConnection(\n createStore: (connection: string) => KeyvStoreAdapter,\n connection: string,\n label: string,\n): Promise<Keyv> {\n let keyv: Keyv | undefined;\n\n await waitForReady(async () => {\n const store = createStore(connection);\n const attemptKeyv = new Keyv({ store });\n let succeeded = false;\n\n try {\n const value = uuid();\n await attemptKeyv.set('test', value);\n succeeded = (await attemptKeyv.get('test')) === value;\n if (succeeded) {\n keyv = attemptKeyv;\n }\n return succeeded;\n } finally {\n if (!succeeded) {\n await attemptKeyv.disconnect();\n }\n }\n }, label);\n\n return keyv!;\n}\n\n/**\n * Starts a Redis-protocol-compatible container (Redis, Valkey, etc.) on port\n * 6379 and waits until a Keyv round-trip succeeds.\n */\nexport async function startRedisLikeContainer(\n image: string,\n store: string,\n createStore: (connection: string) => KeyvStoreAdapter,\n): Promise<Instance> {\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof 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 attemptKeyvConnection(createStore, connection, store);\n\n return {\n store,\n connection,\n keyv,\n stop: async () => {\n await keyv.disconnect();\n await container.stop({ timeout: 10_000 });\n },\n };\n}\n"],"names":["waitForReady","Keyv","uuid"],"mappings":";;;;;;;;;;AAwBA,eAAsB,qBAAA,CACpB,WAAA,EACA,UAAA,EACA,KAAA,EACe;AACf,EAAA,IAAI,IAAA;AAEJ,EAAA,MAAMA,0BAAa,YAAY;AAC7B,IAAA,MAAM,KAAA,GAAQ,YAAY,UAAU,CAAA;AACpC,IAAA,MAAM,WAAA,GAAc,IAAIC,qBAAA,CAAK,EAAE,OAAO,CAAA;AACtC,IAAA,IAAI,SAAA,GAAY,KAAA;AAEhB,IAAA,IAAI;AACF,MAAA,MAAM,QAAQC,sBAAA,EAAK;AACnB,MAAA,MAAM,WAAA,CAAY,GAAA,CAAI,MAAA,EAAQ,KAAK,CAAA;AACnC,MAAA,SAAA,GAAa,MAAM,WAAA,CAAY,GAAA,CAAI,MAAM,CAAA,KAAO,KAAA;AAChD,MAAA,IAAI,SAAA,EAAW;AACb,QAAA,IAAA,GAAO,WAAA;AAAA,MACT;AACA,MAAA,OAAO,SAAA;AAAA,IACT,CAAA,SAAE;AACA,MAAA,IAAI,CAAC,SAAA,EAAW;AACd,QAAA,MAAM,YAAY,UAAA,EAAW;AAAA,MAC/B;AAAA,IACF;AAAA,EACF,GAAG,KAAK,CAAA;AAER,EAAA,OAAO,IAAA;AACT;AAMA,eAAsB,uBAAA,CACpB,KAAA,EACA,KAAA,EACA,WAAA,EACmB;AAEnB,EAAA,MAAM,EAAE,gBAAA,EAAiB,GACvB,OAAA,CAAQ,gBAAgB,CAAA;AAE1B,EAAA,MAAM,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAAA,CAC/C,gBAAA,CAAiB,IAAI,CAAA,CACrB,KAAA,EAAM;AAET,EAAA,MAAM,IAAA,GAAO,UAAU,OAAA,EAAQ;AAC/B,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,aAAA,CAAc,IAAI,CAAA;AACzC,EAAA,MAAM,UAAA,GAAa,CAAA,QAAA,EAAW,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAA;AAE1C,EAAA,MAAM,IAAA,GAAO,MAAM,qBAAA,CAAsB,WAAA,EAAa,YAAY,KAAK,CAAA;AAEvE,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,UAAA;AAAA,IACA,IAAA;AAAA,IACA,MAAM,YAAY;AAChB,MAAA,MAAM,KAAK,UAAA,EAAW;AACtB,MAAA,MAAM,SAAA,CAAU,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA;AAAA,IAC1C;AAAA,GACF;AACF;;;;;"}
@@ -2,7 +2,6 @@
2
2
 
3
3
  var node_crypto = require('node:crypto');
4
4
  var knexFactory = require('knex');
5
- var uuid = require('uuid');
6
5
  var yn = require('yn');
7
6
  var waitForReady = require('../util/waitForReady.cjs.js');
8
7
  var types = require('./types.cjs.js');
@@ -31,7 +30,7 @@ async function waitForMysqlReady(connection) {
31
30
  }
32
31
  async function startMysqlContainer(image) {
33
32
  const user = "root";
34
- const password = uuid.v4();
33
+ const password = node_crypto.randomUUID();
35
34
  const { GenericContainer } = require("testcontainers");
36
35
  const container = await new GenericContainer(image).withExposedPorts(3306).withEnvironment({ MYSQL_ROOT_PASSWORD: password }).withTmpFs({ "/var/lib/mysql": "rw" }).start();
37
36
  const host = container.getHost();
@@ -1 +1 @@
1
- {"version":3,"file":"mysql.cjs.js","sources":["../../src/database/mysql.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 { randomBytes } from 'node:crypto';\nimport knexFactory, { Knex } from 'knex';\nimport { v4 as uuid } from 'uuid';\nimport yn from 'yn';\nimport { waitForReady } from '../util/waitForReady';\nimport { Engine, LARGER_POOL_CONFIG, TestDatabaseProperties } from './types';\n\nasync function waitForMysqlReady(\n connection: Knex.MySqlConnectionConfig,\n): Promise<void> {\n await waitForReady(async () => {\n const knex = knexFactory({\n client: 'mysql2',\n connection: {\n // make a copy because the driver mutates this\n ...connection,\n },\n });\n try {\n const result = await knex.select(knex.raw('version() AS version'));\n return Array.isArray(result) && Boolean(result[0]?.version);\n } finally {\n await knex.destroy();\n }\n }, 'the database');\n}\n\nexport async function startMysqlContainer(image: string): Promise<{\n connection: Knex.MySqlConnectionConfig;\n stopContainer: () => Promise<void>;\n}> {\n const user = 'root';\n const password = uuid();\n\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(3306)\n .withEnvironment({ MYSQL_ROOT_PASSWORD: password })\n .withTmpFs({ '/var/lib/mysql': 'rw' })\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(3306);\n const connection = { host, port, user, password };\n const stopContainer = async () => {\n await container.stop({ timeout: 10_000 });\n };\n\n await waitForMysqlReady(connection);\n\n return { connection, stopContainer };\n}\n\nexport function parseMysqlConnectionString(\n connectionString: string,\n): Knex.MySqlConnectionConfig {\n try {\n const {\n protocol,\n username,\n password,\n port,\n hostname,\n pathname,\n searchParams,\n } = new URL(connectionString);\n\n if (protocol !== 'mysql:') {\n throw new Error(`Unknown protocol ${protocol}`);\n } else if (!username || !password) {\n throw new Error(`Missing username/password`);\n } else if (!pathname.match(/^\\/[^/]+$/)) {\n throw new Error(`Expected single path segment`);\n }\n\n const result: Knex.MySqlConnectionConfig = {\n user: username,\n password,\n host: hostname,\n port: Number(port || 3306),\n database: decodeURIComponent(pathname.substring(1)),\n };\n\n const ssl = searchParams.get('ssl');\n if (ssl) {\n result.ssl = ssl;\n }\n\n const debug = searchParams.get('debug');\n if (debug) {\n result.debug = yn(debug);\n }\n\n return result;\n } catch (e) {\n throw new Error(`Error while parsing MySQL connection string, ${e}`, e);\n }\n}\n\nexport class MysqlEngine implements Engine {\n static async create(\n properties: TestDatabaseProperties,\n ): Promise<MysqlEngine> {\n const { connectionStringEnvironmentVariableName, dockerImageName } =\n properties;\n\n if (connectionStringEnvironmentVariableName) {\n const connectionString =\n process.env[connectionStringEnvironmentVariableName];\n if (connectionString) {\n const connection = parseMysqlConnectionString(connectionString);\n return new MysqlEngine(\n properties,\n connection as Knex.MySqlConnectionConfig,\n );\n }\n }\n\n if (dockerImageName) {\n const { connection, stopContainer } = await startMysqlContainer(\n dockerImageName,\n );\n return new MysqlEngine(properties, connection, stopContainer);\n }\n\n throw new Error(`Test databasee for ${properties.name} not configured`);\n }\n\n readonly #properties: TestDatabaseProperties;\n readonly #connection: Knex.MySqlConnectionConfig;\n readonly #knexInstances: Knex[];\n readonly #databaseNames: string[];\n readonly #stopContainer?: () => Promise<void>;\n\n constructor(\n properties: TestDatabaseProperties,\n connection: Knex.MySqlConnectionConfig,\n stopContainer?: () => Promise<void>,\n ) {\n this.#properties = properties;\n this.#connection = connection;\n this.#knexInstances = [];\n this.#databaseNames = [];\n this.#stopContainer = stopContainer;\n }\n\n async createDatabaseInstance(): Promise<Knex> {\n const adminConnection = this.#connectAdmin();\n try {\n const databaseName = `db${randomBytes(16).toString('hex')}`;\n\n await adminConnection.raw('CREATE DATABASE ??', [databaseName]);\n this.#databaseNames.push(databaseName);\n\n const knexInstance = knexFactory({\n client: this.#properties.driver,\n connection: {\n ...this.#connection,\n database: databaseName,\n },\n ...LARGER_POOL_CONFIG,\n });\n this.#knexInstances.push(knexInstance);\n\n return knexInstance;\n } finally {\n await adminConnection.destroy();\n }\n }\n\n async shutdown(): Promise<void> {\n for (const instance of this.#knexInstances) {\n await instance.destroy();\n }\n\n const adminConnection = this.#connectAdmin();\n try {\n for (const databaseName of this.#databaseNames) {\n await adminConnection.raw('DROP DATABASE ??', [databaseName]);\n }\n } finally {\n await adminConnection.destroy();\n }\n\n await this.#stopContainer?.();\n }\n\n #connectAdmin(): Knex {\n const connection = {\n ...this.#connection,\n database: null as unknown as string,\n };\n return knexFactory({\n client: this.#properties.driver,\n connection,\n pool: {\n min: 0,\n max: 1,\n acquireTimeoutMillis: 20_000,\n createTimeoutMillis: 20_000,\n createRetryIntervalMillis: 1_000,\n },\n });\n }\n}\n"],"names":["waitForReady","knexFactory","uuid","yn","randomBytes","LARGER_POOL_CONFIG"],"mappings":";;;;;;;;;;;;;;AAuBA,eAAe,kBACb,UAAA,EACe;AACf,EAAA,MAAMA,0BAAa,YAAY;AAC7B,IAAA,MAAM,OAAOC,4BAAA,CAAY;AAAA,MACvB,MAAA,EAAQ,QAAA;AAAA,MACR,UAAA,EAAY;AAAA;AAAA,QAEV,GAAG;AAAA;AACL,KACD,CAAA;AACD,IAAA,IAAI;AACF,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,OAAO,IAAA,CAAK,GAAA,CAAI,sBAAsB,CAAC,CAAA;AACjE,MAAA,OAAO,KAAA,CAAM,QAAQ,MAAM,CAAA,IAAK,QAAQ,MAAA,CAAO,CAAC,GAAG,OAAO,CAAA;AAAA,IAC5D,CAAA,SAAE;AACA,MAAA,MAAM,KAAK,OAAA,EAAQ;AAAA,IACrB;AAAA,EACF,GAAG,cAAc,CAAA;AACnB;AAEA,eAAsB,oBAAoB,KAAA,EAGvC;AACD,EAAA,MAAM,IAAA,GAAO,MAAA;AACb,EAAA,MAAM,WAAWC,OAAA,EAAK;AAGtB,EAAA,MAAM,EAAE,gBAAA,EAAiB,GACvB,OAAA,CAAQ,gBAAgB,CAAA;AAE1B,EAAA,MAAM,SAAA,GAAY,MAAM,IAAI,gBAAA,CAAiB,KAAK,CAAA,CAC/C,gBAAA,CAAiB,IAAI,CAAA,CACrB,eAAA,CAAgB,EAAE,mBAAA,EAAqB,QAAA,EAAU,CAAA,CACjD,SAAA,CAAU,EAAE,gBAAA,EAAkB,IAAA,EAAM,CAAA,CACpC,KAAA,EAAM;AAET,EAAA,MAAM,IAAA,GAAO,UAAU,OAAA,EAAQ;AAC/B,EAAA,MAAM,IAAA,GAAO,SAAA,CAAU,aAAA,CAAc,IAAI,CAAA;AACzC,EAAA,MAAM,UAAA,GAAa,EAAE,IAAA,EAAM,IAAA,EAAM,MAAM,QAAA,EAAS;AAChD,EAAA,MAAM,gBAAgB,YAAY;AAChC,IAAA,MAAM,SAAA,CAAU,IAAA,CAAK,EAAE,OAAA,EAAS,KAAQ,CAAA;AAAA,EAC1C,CAAA;AAEA,EAAA,MAAM,kBAAkB,UAAU,CAAA;AAElC,EAAA,OAAO,EAAE,YAAY,aAAA,EAAc;AACrC;AAEO,SAAS,2BACd,gBAAA,EAC4B;AAC5B,EAAA,IAAI;AACF,IAAA,MAAM;AAAA,MACJ,QAAA;AAAA,MACA,QAAA;AAAA,MACA,QAAA;AAAA,MACA,IAAA;AAAA,MACA,QAAA;AAAA,MACA,QAAA;AAAA,MACA;AAAA,KACF,GAAI,IAAI,GAAA,CAAI,gBAAgB,CAAA;AAE5B,IAAA,IAAI,aAAa,QAAA,EAAU;AACzB,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,iBAAA,EAAoB,QAAQ,CAAA,CAAE,CAAA;AAAA,IAChD,CAAA,MAAA,IAAW,CAAC,QAAA,IAAY,CAAC,QAAA,EAAU;AACjC,MAAA,MAAM,IAAI,MAAM,CAAA,yBAAA,CAA2B,CAAA;AAAA,IAC7C,CAAA,MAAA,IAAW,CAAC,QAAA,CAAS,KAAA,CAAM,WAAW,CAAA,EAAG;AACvC,MAAA,MAAM,IAAI,MAAM,CAAA,4BAAA,CAA8B,CAAA;AAAA,IAChD;AAEA,IAAA,MAAM,MAAA,GAAqC;AAAA,MACzC,IAAA,EAAM,QAAA;AAAA,MACN,QAAA;AAAA,MACA,IAAA,EAAM,QAAA;AAAA,MACN,IAAA,EAAM,MAAA,CAAO,IAAA,IAAQ,IAAI,CAAA;AAAA,MACzB,QAAA,EAAU,kBAAA,CAAmB,QAAA,CAAS,SAAA,CAAU,CAAC,CAAC;AAAA,KACpD;AAEA,IAAA,MAAM,GAAA,GAAM,YAAA,CAAa,GAAA,CAAI,KAAK,CAAA;AAClC,IAAA,IAAI,GAAA,EAAK;AACP,MAAA,MAAA,CAAO,GAAA,GAAM,GAAA;AAAA,IACf;AAEA,IAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,GAAA,CAAI,OAAO,CAAA;AACtC,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,MAAA,CAAO,KAAA,GAAQC,oBAAG,KAAK,CAAA;AAAA,IACzB;AAEA,IAAA,OAAO,MAAA;AAAA,EACT,SAAS,CAAA,EAAG;AACV,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,6CAAA,EAAgD,CAAC,IAAI,CAAC,CAAA;AAAA,EACxE;AACF;AAEO,MAAM,WAAA,CAA8B;AAAA,EACzC,aAAa,OACX,UAAA,EACsB;AACtB,IAAA,MAAM,EAAE,uCAAA,EAAyC,eAAA,EAAgB,GAC/D,UAAA;AAEF,IAAA,IAAI,uCAAA,EAAyC;AAC3C,MAAA,MAAM,gBAAA,GACJ,OAAA,CAAQ,GAAA,CAAI,uCAAuC,CAAA;AACrD,MAAA,IAAI,gBAAA,EAAkB;AACpB,QAAA,MAAM,UAAA,GAAa,2BAA2B,gBAAgB,CAAA;AAC9D,QAAA,OAAO,IAAI,WAAA;AAAA,UACT,UAAA;AAAA,UACA;AAAA,SACF;AAAA,MACF;AAAA,IACF;AAEA,IAAA,IAAI,eAAA,EAAiB;AACnB,MAAA,MAAM,EAAE,UAAA,EAAY,aAAA,EAAc,GAAI,MAAM,mBAAA;AAAA,QAC1C;AAAA,OACF;AACA,MAAA,OAAO,IAAI,WAAA,CAAY,UAAA,EAAY,UAAA,EAAY,aAAa,CAAA;AAAA,IAC9D;AAEA,IAAA,MAAM,IAAI,KAAA,CAAM,CAAA,mBAAA,EAAsB,UAAA,CAAW,IAAI,CAAA,eAAA,CAAiB,CAAA;AAAA,EACxE;AAAA,EAES,WAAA;AAAA,EACA,WAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EAET,WAAA,CACE,UAAA,EACA,UAAA,EACA,aAAA,EACA;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,UAAA;AACnB,IAAA,IAAA,CAAK,WAAA,GAAc,UAAA;AACnB,IAAA,IAAA,CAAK,iBAAiB,EAAC;AACvB,IAAA,IAAA,CAAK,iBAAiB,EAAC;AACvB,IAAA,IAAA,CAAK,cAAA,GAAiB,aAAA;AAAA,EACxB;AAAA,EAEA,MAAM,sBAAA,GAAwC;AAC5C,IAAA,MAAM,eAAA,GAAkB,KAAK,aAAA,EAAc;AAC3C,IAAA,IAAI;AACF,MAAA,MAAM,eAAe,CAAA,EAAA,EAAKC,uBAAA,CAAY,EAAE,CAAA,CAAE,QAAA,CAAS,KAAK,CAAC,CAAA,CAAA;AAEzD,MAAA,MAAM,eAAA,CAAgB,GAAA,CAAI,oBAAA,EAAsB,CAAC,YAAY,CAAC,CAAA;AAC9D,MAAA,IAAA,CAAK,cAAA,CAAe,KAAK,YAAY,CAAA;AAErC,MAAA,MAAM,eAAeH,4BAAA,CAAY;AAAA,QAC/B,MAAA,EAAQ,KAAK,WAAA,CAAY,MAAA;AAAA,QACzB,UAAA,EAAY;AAAA,UACV,GAAG,IAAA,CAAK,WAAA;AAAA,UACR,QAAA,EAAU;AAAA,SACZ;AAAA,QACA,GAAGI;AAAA,OACJ,CAAA;AACD,MAAA,IAAA,CAAK,cAAA,CAAe,KAAK,YAAY,CAAA;AAErC,MAAA,OAAO,YAAA;AAAA,IACT,CAAA,SAAE;AACA,MAAA,MAAM,gBAAgB,OAAA,EAAQ;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,MAAM,QAAA,GAA0B;AAC9B,IAAA,KAAA,MAAW,QAAA,IAAY,KAAK,cAAA,EAAgB;AAC1C,MAAA,MAAM,SAAS,OAAA,EAAQ;AAAA,IACzB;AAEA,IAAA,MAAM,eAAA,GAAkB,KAAK,aAAA,EAAc;AAC3C,IAAA,IAAI;AACF,MAAA,KAAA,MAAW,YAAA,IAAgB,KAAK,cAAA,EAAgB;AAC9C,QAAA,MAAM,eAAA,CAAgB,GAAA,CAAI,kBAAA,EAAoB,CAAC,YAAY,CAAC,CAAA;AAAA,MAC9D;AAAA,IACF,CAAA,SAAE;AACA,MAAA,MAAM,gBAAgB,OAAA,EAAQ;AAAA,IAChC;AAEA,IAAA,MAAM,KAAK,cAAA,IAAiB;AAAA,EAC9B;AAAA,EAEA,aAAA,GAAsB;AACpB,IAAA,MAAM,UAAA,GAAa;AAAA,MACjB,GAAG,IAAA,CAAK,WAAA;AAAA,MACR,QAAA,EAAU;AAAA,KACZ;AACA,IAAA,OAAOJ,4BAAA,CAAY;AAAA,MACjB,MAAA,EAAQ,KAAK,WAAA,CAAY,MAAA;AAAA,MACzB,UAAA;AAAA,MACA,IAAA,EAAM;AAAA,QACJ,GAAA,EAAK,CAAA;AAAA,QACL,GAAA,EAAK,CAAA;AAAA,QACL,oBAAA,EAAsB,GAAA;AAAA,QACtB,mBAAA,EAAqB,GAAA;AAAA,QACrB,yBAAA,EAA2B;AAAA;AAC7B,KACD,CAAA;AAAA,EACH;AACF;;;;;;"}
1
+ {"version":3,"file":"mysql.cjs.js","sources":["../../src/database/mysql.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 { randomBytes } from 'node:crypto';\nimport knexFactory, { Knex } from 'knex';\nimport { randomUUID as uuid } from 'node:crypto';\nimport yn from 'yn';\nimport { waitForReady } from '../util/waitForReady';\nimport { Engine, LARGER_POOL_CONFIG, TestDatabaseProperties } from './types';\n\nasync function waitForMysqlReady(\n connection: Knex.MySqlConnectionConfig,\n): Promise<void> {\n await waitForReady(async () => {\n const knex = knexFactory({\n client: 'mysql2',\n connection: {\n // make a copy because the driver mutates this\n ...connection,\n },\n });\n try {\n const result = await knex.select(knex.raw('version() AS version'));\n return Array.isArray(result) && Boolean(result[0]?.version);\n } finally {\n await knex.destroy();\n }\n }, 'the database');\n}\n\nexport async function startMysqlContainer(image: string): Promise<{\n connection: Knex.MySqlConnectionConfig;\n stopContainer: () => Promise<void>;\n}> {\n const user = 'root';\n const password = uuid();\n\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(3306)\n .withEnvironment({ MYSQL_ROOT_PASSWORD: password })\n .withTmpFs({ '/var/lib/mysql': 'rw' })\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(3306);\n const connection = { host, port, user, password };\n const stopContainer = async () => {\n await container.stop({ timeout: 10_000 });\n };\n\n await waitForMysqlReady(connection);\n\n return { connection, stopContainer };\n}\n\nexport function parseMysqlConnectionString(\n connectionString: string,\n): Knex.MySqlConnectionConfig {\n try {\n const {\n protocol,\n username,\n password,\n port,\n hostname,\n pathname,\n searchParams,\n } = new URL(connectionString);\n\n if (protocol !== 'mysql:') {\n throw new Error(`Unknown protocol ${protocol}`);\n } else if (!username || !password) {\n throw new Error(`Missing username/password`);\n } else if (!pathname.match(/^\\/[^/]+$/)) {\n throw new Error(`Expected single path segment`);\n }\n\n const result: Knex.MySqlConnectionConfig = {\n user: username,\n password,\n host: hostname,\n port: Number(port || 3306),\n database: decodeURIComponent(pathname.substring(1)),\n };\n\n const ssl = searchParams.get('ssl');\n if (ssl) {\n result.ssl = ssl;\n }\n\n const debug = searchParams.get('debug');\n if (debug) {\n result.debug = yn(debug);\n }\n\n return result;\n } catch (e) {\n throw new Error(`Error while parsing MySQL connection string, ${e}`, e);\n }\n}\n\nexport class MysqlEngine implements Engine {\n static async create(\n properties: TestDatabaseProperties,\n ): Promise<MysqlEngine> {\n const { connectionStringEnvironmentVariableName, dockerImageName } =\n properties;\n\n if (connectionStringEnvironmentVariableName) {\n const connectionString =\n process.env[connectionStringEnvironmentVariableName];\n if (connectionString) {\n const connection = parseMysqlConnectionString(connectionString);\n return new MysqlEngine(\n properties,\n connection as Knex.MySqlConnectionConfig,\n );\n }\n }\n\n if (dockerImageName) {\n const { connection, stopContainer } = await startMysqlContainer(\n dockerImageName,\n );\n return new MysqlEngine(properties, connection, stopContainer);\n }\n\n throw new Error(`Test databasee for ${properties.name} not configured`);\n }\n\n readonly #properties: TestDatabaseProperties;\n readonly #connection: Knex.MySqlConnectionConfig;\n readonly #knexInstances: Knex[];\n readonly #databaseNames: string[];\n readonly #stopContainer?: () => Promise<void>;\n\n constructor(\n properties: TestDatabaseProperties,\n connection: Knex.MySqlConnectionConfig,\n stopContainer?: () => Promise<void>,\n ) {\n this.#properties = properties;\n this.#connection = connection;\n this.#knexInstances = [];\n this.#databaseNames = [];\n this.#stopContainer = stopContainer;\n }\n\n async createDatabaseInstance(): Promise<Knex> {\n const adminConnection = this.#connectAdmin();\n try {\n const databaseName = `db${randomBytes(16).toString('hex')}`;\n\n await adminConnection.raw('CREATE DATABASE ??', [databaseName]);\n this.#databaseNames.push(databaseName);\n\n const knexInstance = knexFactory({\n client: this.#properties.driver,\n connection: {\n ...this.#connection,\n database: databaseName,\n },\n ...LARGER_POOL_CONFIG,\n });\n this.#knexInstances.push(knexInstance);\n\n return knexInstance;\n } finally {\n await adminConnection.destroy();\n }\n }\n\n async shutdown(): Promise<void> {\n for (const instance of this.#knexInstances) {\n await instance.destroy();\n }\n\n const adminConnection = this.#connectAdmin();\n try {\n for (const databaseName of this.#databaseNames) {\n await adminConnection.raw('DROP DATABASE ??', [databaseName]);\n }\n } finally {\n await adminConnection.destroy();\n }\n\n await this.#stopContainer?.();\n }\n\n #connectAdmin(): Knex {\n const connection = {\n ...this.#connection,\n database: null as unknown as string,\n };\n return knexFactory({\n client: this.#properties.driver,\n connection,\n pool: {\n min: 0,\n max: 1,\n acquireTimeoutMillis: 20_000,\n createTimeoutMillis: 20_000,\n createRetryIntervalMillis: 1_000,\n },\n });\n }\n}\n"],"names":["waitForReady","knexFactory","uuid","yn","randomBytes","LARGER_POOL_CONFIG"],"mappings":"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"}
@@ -3,7 +3,6 @@
3
3
  var node_crypto = require('node:crypto');
4
4
  var knexFactory = require('knex');
5
5
  var pgConnectionString = require('pg-connection-string');
6
- var uuid = require('uuid');
7
6
  var waitForReady = require('../util/waitForReady.cjs.js');
8
7
  var types = require('./types.cjs.js');
9
8
 
@@ -30,7 +29,7 @@ async function waitForPostgresReady(connection) {
30
29
  }
31
30
  async function startPostgresContainer(image) {
32
31
  const user = "postgres";
33
- const password = uuid.v4();
32
+ const password = node_crypto.randomUUID();
34
33
  const { GenericContainer } = require("testcontainers");
35
34
  const container = await new GenericContainer(image).withExposedPorts(5432).withEnvironment({
36
35
  // Since postgres 18, the default directory changed - so we pin it here
@@ -1 +1 @@
1
- {"version":3,"file":"postgres.cjs.js","sources":["../../src/database/postgres.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 { randomBytes } from 'node:crypto';\nimport knexFactory, { Knex } from 'knex';\nimport { parse as parsePgConnectionString } from 'pg-connection-string';\nimport { v4 as uuid } from 'uuid';\nimport { waitForReady } from '../util/waitForReady';\nimport { Engine, LARGER_POOL_CONFIG, TestDatabaseProperties } from './types';\n\nasync function waitForPostgresReady(\n connection: Knex.PgConnectionConfig,\n): Promise<void> {\n await waitForReady(async () => {\n const knex = knexFactory({\n client: 'pg',\n connection: {\n // make a copy because the driver mutates this\n ...connection,\n },\n });\n try {\n const result = await knex.select(knex.raw('version()'));\n return Array.isArray(result) && Boolean(result[0]?.version);\n } finally {\n await knex.destroy();\n }\n }, 'the database');\n}\n\nexport async function startPostgresContainer(image: string): Promise<{\n connection: Knex.PgConnectionConfig;\n stopContainer: () => Promise<void>;\n}> {\n const user = 'postgres';\n const password = uuid();\n\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(5432)\n .withEnvironment({\n // Since postgres 18, the default directory changed - so we pin it here\n PGDATA: '/var/lib/postgresql/data',\n POSTGRES_PASSWORD: password,\n })\n .withTmpFs({ '/var/lib/postgresql/data': 'rw' })\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(5432);\n const connection = { host, port, user, password };\n const stopContainer = async () => {\n await container.stop({ timeout: 10_000 });\n };\n\n await waitForPostgresReady(connection);\n\n return { connection, stopContainer };\n}\n\nexport class PostgresEngine implements Engine {\n static async create(\n properties: TestDatabaseProperties,\n ): Promise<PostgresEngine> {\n const { connectionStringEnvironmentVariableName, dockerImageName } =\n properties;\n\n if (connectionStringEnvironmentVariableName) {\n const connectionString =\n process.env[connectionStringEnvironmentVariableName];\n if (connectionString) {\n const connection = parsePgConnectionString(connectionString);\n return new PostgresEngine(\n properties,\n connection as Knex.PgConnectionConfig,\n );\n }\n }\n\n if (dockerImageName) {\n const { connection, stopContainer } = await startPostgresContainer(\n dockerImageName,\n );\n return new PostgresEngine(properties, connection, stopContainer);\n }\n\n throw new Error(`Test databasee for ${properties.name} not configured`);\n }\n\n readonly #properties: TestDatabaseProperties;\n readonly #connection: Knex.PgConnectionConfig;\n readonly #knexInstances: Knex[];\n readonly #databaseNames: string[];\n readonly #stopContainer?: () => Promise<void>;\n\n constructor(\n properties: TestDatabaseProperties,\n connection: Knex.PgConnectionConfig,\n stopContainer?: () => Promise<void>,\n ) {\n this.#properties = properties;\n this.#connection = connection;\n this.#knexInstances = [];\n this.#databaseNames = [];\n this.#stopContainer = stopContainer;\n }\n\n async createDatabaseInstance(): Promise<Knex> {\n const adminConnection = this.#connectAdmin();\n try {\n const databaseName = `db${randomBytes(16).toString('hex')}`;\n\n await adminConnection.raw('CREATE DATABASE ??', [databaseName]);\n this.#databaseNames.push(databaseName);\n\n const knexInstance = knexFactory({\n client: this.#properties.driver,\n connection: {\n ...this.#connection,\n database: databaseName,\n },\n ...LARGER_POOL_CONFIG,\n });\n this.#knexInstances.push(knexInstance);\n\n return knexInstance;\n } finally {\n await adminConnection.destroy();\n }\n }\n\n async shutdown(): Promise<void> {\n for (const instance of this.#knexInstances) {\n await instance.destroy();\n }\n\n const adminConnection = this.#connectAdmin();\n try {\n for (const databaseName of this.#databaseNames) {\n await adminConnection.raw('DROP DATABASE ??', [databaseName]);\n }\n } finally {\n await adminConnection.destroy();\n }\n\n await this.#stopContainer?.();\n }\n\n #connectAdmin(): Knex {\n return knexFactory({\n client: this.#properties.driver,\n connection: {\n ...this.#connection,\n database: 'postgres',\n },\n pool: {\n acquireTimeoutMillis: 10000,\n },\n });\n }\n}\n"],"names":["waitForReady","knexFactory","uuid","parsePgConnectionString","randomBytes","LARGER_POOL_CONFIG"],"mappings":"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"}
1
+ {"version":3,"file":"postgres.cjs.js","sources":["../../src/database/postgres.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 { randomBytes } from 'node:crypto';\nimport knexFactory, { Knex } from 'knex';\nimport { parse as parsePgConnectionString } from 'pg-connection-string';\nimport { randomUUID as uuid } from 'node:crypto';\nimport { waitForReady } from '../util/waitForReady';\nimport { Engine, LARGER_POOL_CONFIG, TestDatabaseProperties } from './types';\n\nasync function waitForPostgresReady(\n connection: Knex.PgConnectionConfig,\n): Promise<void> {\n await waitForReady(async () => {\n const knex = knexFactory({\n client: 'pg',\n connection: {\n // make a copy because the driver mutates this\n ...connection,\n },\n });\n try {\n const result = await knex.select(knex.raw('version()'));\n return Array.isArray(result) && Boolean(result[0]?.version);\n } finally {\n await knex.destroy();\n }\n }, 'the database');\n}\n\nexport async function startPostgresContainer(image: string): Promise<{\n connection: Knex.PgConnectionConfig;\n stopContainer: () => Promise<void>;\n}> {\n const user = 'postgres';\n const password = uuid();\n\n // Lazy-load to avoid side-effect of importing testcontainers\n const { GenericContainer } =\n require('testcontainers') as typeof import('testcontainers');\n\n const container = await new GenericContainer(image)\n .withExposedPorts(5432)\n .withEnvironment({\n // Since postgres 18, the default directory changed - so we pin it here\n PGDATA: '/var/lib/postgresql/data',\n POSTGRES_PASSWORD: password,\n })\n .withTmpFs({ '/var/lib/postgresql/data': 'rw' })\n .start();\n\n const host = container.getHost();\n const port = container.getMappedPort(5432);\n const connection = { host, port, user, password };\n const stopContainer = async () => {\n await container.stop({ timeout: 10_000 });\n };\n\n await waitForPostgresReady(connection);\n\n return { connection, stopContainer };\n}\n\nexport class PostgresEngine implements Engine {\n static async create(\n properties: TestDatabaseProperties,\n ): Promise<PostgresEngine> {\n const { connectionStringEnvironmentVariableName, dockerImageName } =\n properties;\n\n if (connectionStringEnvironmentVariableName) {\n const connectionString =\n process.env[connectionStringEnvironmentVariableName];\n if (connectionString) {\n const connection = parsePgConnectionString(connectionString);\n return new PostgresEngine(\n properties,\n connection as Knex.PgConnectionConfig,\n );\n }\n }\n\n if (dockerImageName) {\n const { connection, stopContainer } = await startPostgresContainer(\n dockerImageName,\n );\n return new PostgresEngine(properties, connection, stopContainer);\n }\n\n throw new Error(`Test databasee for ${properties.name} not configured`);\n }\n\n readonly #properties: TestDatabaseProperties;\n readonly #connection: Knex.PgConnectionConfig;\n readonly #knexInstances: Knex[];\n readonly #databaseNames: string[];\n readonly #stopContainer?: () => Promise<void>;\n\n constructor(\n properties: TestDatabaseProperties,\n connection: Knex.PgConnectionConfig,\n stopContainer?: () => Promise<void>,\n ) {\n this.#properties = properties;\n this.#connection = connection;\n this.#knexInstances = [];\n this.#databaseNames = [];\n this.#stopContainer = stopContainer;\n }\n\n async createDatabaseInstance(): Promise<Knex> {\n const adminConnection = this.#connectAdmin();\n try {\n const databaseName = `db${randomBytes(16).toString('hex')}`;\n\n await adminConnection.raw('CREATE DATABASE ??', [databaseName]);\n this.#databaseNames.push(databaseName);\n\n const knexInstance = knexFactory({\n client: this.#properties.driver,\n connection: {\n ...this.#connection,\n database: databaseName,\n },\n ...LARGER_POOL_CONFIG,\n });\n this.#knexInstances.push(knexInstance);\n\n return knexInstance;\n } finally {\n await adminConnection.destroy();\n }\n }\n\n async shutdown(): Promise<void> {\n for (const instance of this.#knexInstances) {\n await instance.destroy();\n }\n\n const adminConnection = this.#connectAdmin();\n try {\n for (const databaseName of this.#databaseNames) {\n await adminConnection.raw('DROP DATABASE ??', [databaseName]);\n }\n } finally {\n await adminConnection.destroy();\n }\n\n await this.#stopContainer?.();\n }\n\n #connectAdmin(): Knex {\n return knexFactory({\n client: this.#properties.driver,\n connection: {\n ...this.#connection,\n database: 'postgres',\n },\n pool: {\n acquireTimeoutMillis: 10000,\n },\n });\n }\n}\n"],"names":["waitForReady","knexFactory","uuid","parsePgConnectionString","randomBytes","LARGER_POOL_CONFIG"],"mappings":"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"}
@@ -14,6 +14,7 @@ require('zod/v3');
14
14
  require('zod-to-json-schema');
15
15
  var ActionsServiceMock = require('../alpha/services/ActionsServiceMock.cjs.js');
16
16
  var MetricsServiceMock = require('../alpha/services/MetricsServiceMock.cjs.js');
17
+ var TracingServiceMock = require('../alpha/services/TracingServiceMock.cjs.js');
17
18
 
18
19
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
19
20
 
@@ -41,7 +42,8 @@ const defaultServiceFactories = [
41
42
  // Alpha services
42
43
  ActionsRegistryServiceMock.actionsRegistryServiceMock.factory(),
43
44
  ActionsServiceMock.actionsServiceMock.factory(),
44
- MetricsServiceMock.metricsServiceMock.factory()
45
+ MetricsServiceMock.metricsServiceMock.factory(),
46
+ TracingServiceMock.tracingServiceMock.factory()
45
47
  ];
46
48
  function createPluginsForOrphanModules(features) {
47
49
  const pluginIds = /* @__PURE__ */ new Set();
@@ -1 +1 @@
1
- {"version":3,"file":"TestBackend.cjs.js","sources":["../../src/wiring/TestBackend.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { Backend, createSpecializedBackend } from '@backstage/backend-app-api';\nimport {\n createServiceFactory,\n BackendFeature,\n ExtensionPoint,\n coreServices,\n createBackendModule,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { mockServices } from '../services';\nimport { ConfigReader } from '@backstage/config';\nimport express from 'express';\n// Direct internal import to avoid duplication\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n InternalBackendFeature,\n InternalBackendRegistrations,\n} from '../../../backend-plugin-api/src/wiring/types';\nimport {\n DefaultRootHttpRouter,\n ExtendedHttpServer,\n MiddlewareFactory,\n createHealthRouter,\n createHttpServer,\n} from '@backstage/backend-defaults/rootHttpRouter';\nimport { HostDiscovery } from '@backstage/backend-defaults/discovery';\nimport {\n actionsRegistryServiceMock,\n actionsServiceMock,\n metricsServiceMock,\n} from '../alpha/services';\n\n/** @public */\nexport interface TestBackendOptions<TExtensionPoints extends any[]> {\n extensionPoints?: readonly [\n ...{\n [index in keyof TExtensionPoints]: [\n ExtensionPoint<TExtensionPoints[index]>,\n Partial<TExtensionPoints[index]>,\n ];\n },\n ];\n features?: Array<BackendFeature | Promise<{ default: BackendFeature }>>;\n}\n\n/** @public */\nexport interface TestBackend extends Backend {\n /**\n * Provides access to the underling HTTP server for use with utilities\n * such as `supertest`.\n *\n * If the root http router service has been replaced, this will throw an error.\n */\n readonly server: ExtendedHttpServer;\n}\n\nexport const defaultServiceFactories = [\n mockServices.auth.factory(),\n mockServices.auditor.factory(),\n mockServices.cache.factory(),\n mockServices.rootConfig.factory(),\n mockServices.database.factory(),\n mockServices.httpAuth.factory(),\n mockServices.httpRouter.factory(),\n mockServices.lifecycle.factory(),\n mockServices.logger.factory(),\n mockServices.permissions.factory(),\n mockServices.permissionsRegistry.factory(),\n mockServices.rootHealth.factory(),\n mockServices.rootLifecycle.factory(),\n mockServices.rootLogger.factory(),\n mockServices.scheduler.factory(),\n mockServices.userInfo.factory(),\n mockServices.urlReader.factory(),\n mockServices.events.factory(),\n\n // Alpha services\n actionsRegistryServiceMock.factory(),\n actionsServiceMock.factory(),\n metricsServiceMock.factory(),\n];\n\n/**\n * Given a set of features, return an array of plugins that ensures that each\n * module in the provided set of features has a corresponding plugin.\n * @internal\n */\nfunction createPluginsForOrphanModules(features: Array<BackendFeature>) {\n const pluginIds = new Set<string>();\n const modulePluginIds = new Set<string>();\n\n for (const feature of features) {\n if (isInternalBackendRegistrations(feature)) {\n const registrations = feature.getRegistrations();\n for (const registration of registrations) {\n if (\n registration.type === 'plugin' ||\n registration.type === 'plugin-v1.1'\n ) {\n pluginIds.add(registration.pluginId);\n } else if (\n registration.type === 'module' ||\n registration.type === 'module-v1.1'\n ) {\n modulePluginIds.add(registration.pluginId);\n }\n }\n }\n }\n\n for (const pluginId of pluginIds) {\n modulePluginIds.delete(pluginId);\n }\n\n return Array.from(modulePluginIds).map(pluginId =>\n createBackendPlugin({\n pluginId,\n register(reg) {\n reg.registerInit({ deps: {}, async init() {} });\n },\n }),\n );\n}\n\n/**\n * Given a set of extension points and features, find the extension\n * points that we mock and tie them to the correct plugin ID.\n * @returns\n */\nfunction createExtensionPointTestModules(\n features: Array<BackendFeature>,\n extensionPointTuples?: readonly [\n ref: ExtensionPoint<unknown>,\n impl: unknown,\n ][],\n): Array<BackendFeature> {\n if (!extensionPointTuples) {\n return [];\n }\n\n const registrations = features.flatMap(feature => {\n if (isInternalBackendRegistrations(feature)) {\n return feature.getRegistrations();\n }\n return [];\n });\n\n const extensionPointMap = new Map(\n extensionPointTuples.map(ep => [ep[0].id, ep]),\n );\n const extensionPointsToSort = new Set(extensionPointMap.keys());\n const extensionPointsByPlugin = new Map<string, string[]>();\n\n for (const registration of registrations) {\n if (registration.type === 'module' || registration.type === 'module-v1.1') {\n const testDep = Object.values(registration.init.deps).filter(dep =>\n extensionPointsToSort.has(dep.id),\n );\n if (testDep.length > 0) {\n let points = extensionPointsByPlugin.get(registration.pluginId);\n if (!points) {\n points = [];\n extensionPointsByPlugin.set(registration.pluginId, points);\n }\n for (const { id } of testDep) {\n points.push(id);\n extensionPointsToSort.delete(id);\n }\n }\n }\n }\n\n if (extensionPointsToSort.size > 0) {\n const list = Array.from(extensionPointsToSort)\n .map(id => `'${id}'`)\n .join(', ');\n throw new Error(\n `Unable to determine the plugin ID of extension point(s) ${list}. ` +\n 'Tested extension points must be depended on by one or more tested modules.',\n );\n }\n\n const modules = [];\n\n for (const [pluginId, pluginExtensionPointIds] of extensionPointsByPlugin) {\n modules.push(\n createBackendModule({\n pluginId,\n moduleId: 'test-extension-point-registration',\n register(reg) {\n for (const id of pluginExtensionPointIds) {\n const tuple = extensionPointMap.get(id)!;\n reg.registerExtensionPoint(...tuple);\n }\n\n reg.registerInit({ deps: {}, async init() {} });\n },\n }),\n );\n }\n\n return modules;\n}\n\nfunction isPromise<T>(value: unknown | Promise<T>): value is Promise<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function'\n );\n}\n\n// Same as in the backend-app-api, handles double defaults from dynamic imports\nfunction unwrapFeature(\n feature: BackendFeature | { default: BackendFeature },\n): BackendFeature {\n if ('$$type' in feature) {\n return feature;\n }\n\n if ('default' in feature) {\n return feature.default;\n }\n\n return feature;\n}\n\nconst backendInstancesToCleanUp = new Array<Backend>();\n\n/** @public */\nexport async function startTestBackend<TExtensionPoints extends any[]>(\n options: TestBackendOptions<TExtensionPoints>,\n): Promise<TestBackend> {\n const { extensionPoints, ...otherOptions } = options;\n\n // Unpack input into awaited plain BackendFeatures\n const features: BackendFeature[] = await Promise.all(\n options.features?.map(async val => {\n if (isPromise(val)) {\n const { default: feature } = await val;\n return unwrapFeature(feature);\n }\n return unwrapFeature(val);\n }) ?? [],\n );\n\n let server: ExtendedHttpServer;\n\n const rootHttpRouterFactory = createServiceFactory({\n service: coreServices.rootHttpRouter,\n deps: {\n config: coreServices.rootConfig,\n lifecycle: coreServices.rootLifecycle,\n rootLogger: coreServices.rootLogger,\n health: coreServices.rootHealth,\n },\n async factory({ config, lifecycle, rootLogger, health }) {\n const router = DefaultRootHttpRouter.create();\n const logger = rootLogger.child({ service: 'rootHttpRouter' });\n\n const app = express();\n\n const middleware = MiddlewareFactory.create({ config, logger });\n const healthRouter = createHealthRouter({ config, health });\n\n app.use(healthRouter);\n app.use(router.handler());\n app.use(middleware.notFound());\n app.use(middleware.error());\n\n server = await createHttpServer(\n app,\n { listen: { host: '', port: 0 } },\n { logger },\n );\n\n lifecycle.addShutdownHook(() => server.stop(), { logger });\n\n await server.start();\n\n return router;\n },\n });\n\n const discoveryFactory = createServiceFactory({\n service: coreServices.discovery,\n deps: {\n rootHttpRouter: coreServices.rootHttpRouter,\n },\n async factory() {\n if (!server) {\n throw new Error('Test server not started yet');\n }\n const port = server.port();\n const discovery = HostDiscovery.fromConfig(\n new ConfigReader({\n backend: { baseUrl: `http://localhost:${port}`, listen: { port } },\n }),\n );\n return discovery;\n },\n });\n\n const backend = createSpecializedBackend({\n ...otherOptions,\n defaultServiceFactories: [\n ...defaultServiceFactories,\n rootHttpRouterFactory,\n discoveryFactory,\n ],\n });\n\n backendInstancesToCleanUp.push(backend);\n\n for (const m of createExtensionPointTestModules(features, extensionPoints)) {\n backend.add(m);\n }\n for (const p of createPluginsForOrphanModules(features)) {\n backend.add(p);\n }\n for (const feature of features) {\n backend.add(feature);\n }\n\n await backend.start();\n\n return Object.assign(backend, {\n get server() {\n if (!server) {\n throw new Error('TestBackend server is not available');\n }\n return server;\n },\n });\n}\n\nlet registered = false;\nfunction registerTestHooks() {\n if (typeof afterAll !== 'function') {\n return;\n }\n if (registered) {\n return;\n }\n registered = true;\n\n afterAll(async () => {\n await Promise.all(\n backendInstancesToCleanUp.map(async backend => {\n try {\n await backend.stop();\n } catch (error) {\n console.error(`Failed to stop backend after tests, ${error}`);\n }\n }),\n );\n backendInstancesToCleanUp.length = 0;\n });\n}\n\nregisterTestHooks();\n\nfunction toInternalBackendFeature(\n feature: BackendFeature,\n): InternalBackendFeature {\n if (feature.$$type !== '@backstage/BackendFeature') {\n throw new Error(`Invalid BackendFeature, bad type '${feature.$$type}'`);\n }\n const internal = feature as InternalBackendFeature;\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid BackendFeature, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n\nfunction isInternalBackendRegistrations(\n feature: BackendFeature,\n): feature is InternalBackendRegistrations {\n const internal = toInternalBackendFeature(feature);\n if (internal.featureType === 'registrations') {\n return true;\n }\n // Backwards compatibility for v1 registrations that use duck typing\n return 'getRegistrations' in internal;\n}\n"],"names":["mockServices","actionsRegistryServiceMock","actionsServiceMock","metricsServiceMock","createBackendPlugin","createBackendModule","createServiceFactory","coreServices","DefaultRootHttpRouter","express","MiddlewareFactory","createHealthRouter","createHttpServer","discovery","HostDiscovery","ConfigReader","createSpecializedBackend"],"mappings":"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"}
1
+ {"version":3,"file":"TestBackend.cjs.js","sources":["../../src/wiring/TestBackend.ts"],"sourcesContent":["/*\n * Copyright 2022 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 { Backend, createSpecializedBackend } from '@backstage/backend-app-api';\nimport {\n createServiceFactory,\n BackendFeature,\n ExtensionPoint,\n coreServices,\n createBackendModule,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { mockServices } from '../services';\nimport { ConfigReader } from '@backstage/config';\nimport express from 'express';\n// Direct internal import to avoid duplication\n// eslint-disable-next-line @backstage/no-relative-monorepo-imports\nimport {\n InternalBackendFeature,\n InternalBackendRegistrations,\n} from '../../../backend-plugin-api/src/wiring/types';\nimport {\n DefaultRootHttpRouter,\n ExtendedHttpServer,\n MiddlewareFactory,\n createHealthRouter,\n createHttpServer,\n} from '@backstage/backend-defaults/rootHttpRouter';\nimport { HostDiscovery } from '@backstage/backend-defaults/discovery';\nimport {\n actionsRegistryServiceMock,\n actionsServiceMock,\n metricsServiceMock,\n tracingServiceMock,\n} from '../alpha/services';\n\n/** @public */\nexport interface TestBackendOptions<TExtensionPoints extends any[]> {\n extensionPoints?: readonly [\n ...{\n [index in keyof TExtensionPoints]: [\n ExtensionPoint<TExtensionPoints[index]>,\n Partial<TExtensionPoints[index]>,\n ];\n },\n ];\n features?: Array<BackendFeature | Promise<{ default: BackendFeature }>>;\n}\n\n/** @public */\nexport interface TestBackend extends Backend {\n /**\n * Provides access to the underling HTTP server for use with utilities\n * such as `supertest`.\n *\n * If the root http router service has been replaced, this will throw an error.\n */\n readonly server: ExtendedHttpServer;\n}\n\nexport const defaultServiceFactories = [\n mockServices.auth.factory(),\n mockServices.auditor.factory(),\n mockServices.cache.factory(),\n mockServices.rootConfig.factory(),\n mockServices.database.factory(),\n mockServices.httpAuth.factory(),\n mockServices.httpRouter.factory(),\n mockServices.lifecycle.factory(),\n mockServices.logger.factory(),\n mockServices.permissions.factory(),\n mockServices.permissionsRegistry.factory(),\n mockServices.rootHealth.factory(),\n mockServices.rootLifecycle.factory(),\n mockServices.rootLogger.factory(),\n mockServices.scheduler.factory(),\n mockServices.userInfo.factory(),\n mockServices.urlReader.factory(),\n mockServices.events.factory(),\n\n // Alpha services\n actionsRegistryServiceMock.factory(),\n actionsServiceMock.factory(),\n metricsServiceMock.factory(),\n tracingServiceMock.factory(),\n];\n\n/**\n * Given a set of features, return an array of plugins that ensures that each\n * module in the provided set of features has a corresponding plugin.\n * @internal\n */\nfunction createPluginsForOrphanModules(features: Array<BackendFeature>) {\n const pluginIds = new Set<string>();\n const modulePluginIds = new Set<string>();\n\n for (const feature of features) {\n if (isInternalBackendRegistrations(feature)) {\n const registrations = feature.getRegistrations();\n for (const registration of registrations) {\n if (\n registration.type === 'plugin' ||\n registration.type === 'plugin-v1.1'\n ) {\n pluginIds.add(registration.pluginId);\n } else if (\n registration.type === 'module' ||\n registration.type === 'module-v1.1'\n ) {\n modulePluginIds.add(registration.pluginId);\n }\n }\n }\n }\n\n for (const pluginId of pluginIds) {\n modulePluginIds.delete(pluginId);\n }\n\n return Array.from(modulePluginIds).map(pluginId =>\n createBackendPlugin({\n pluginId,\n register(reg) {\n reg.registerInit({ deps: {}, async init() {} });\n },\n }),\n );\n}\n\n/**\n * Given a set of extension points and features, find the extension\n * points that we mock and tie them to the correct plugin ID.\n * @returns\n */\nfunction createExtensionPointTestModules(\n features: Array<BackendFeature>,\n extensionPointTuples?: readonly [\n ref: ExtensionPoint<unknown>,\n impl: unknown,\n ][],\n): Array<BackendFeature> {\n if (!extensionPointTuples) {\n return [];\n }\n\n const registrations = features.flatMap(feature => {\n if (isInternalBackendRegistrations(feature)) {\n return feature.getRegistrations();\n }\n return [];\n });\n\n const extensionPointMap = new Map(\n extensionPointTuples.map(ep => [ep[0].id, ep]),\n );\n const extensionPointsToSort = new Set(extensionPointMap.keys());\n const extensionPointsByPlugin = new Map<string, string[]>();\n\n for (const registration of registrations) {\n if (registration.type === 'module' || registration.type === 'module-v1.1') {\n const testDep = Object.values(registration.init.deps).filter(dep =>\n extensionPointsToSort.has(dep.id),\n );\n if (testDep.length > 0) {\n let points = extensionPointsByPlugin.get(registration.pluginId);\n if (!points) {\n points = [];\n extensionPointsByPlugin.set(registration.pluginId, points);\n }\n for (const { id } of testDep) {\n points.push(id);\n extensionPointsToSort.delete(id);\n }\n }\n }\n }\n\n if (extensionPointsToSort.size > 0) {\n const list = Array.from(extensionPointsToSort)\n .map(id => `'${id}'`)\n .join(', ');\n throw new Error(\n `Unable to determine the plugin ID of extension point(s) ${list}. ` +\n 'Tested extension points must be depended on by one or more tested modules.',\n );\n }\n\n const modules = [];\n\n for (const [pluginId, pluginExtensionPointIds] of extensionPointsByPlugin) {\n modules.push(\n createBackendModule({\n pluginId,\n moduleId: 'test-extension-point-registration',\n register(reg) {\n for (const id of pluginExtensionPointIds) {\n const tuple = extensionPointMap.get(id)!;\n reg.registerExtensionPoint(...tuple);\n }\n\n reg.registerInit({ deps: {}, async init() {} });\n },\n }),\n );\n }\n\n return modules;\n}\n\nfunction isPromise<T>(value: unknown | Promise<T>): value is Promise<T> {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'then' in value &&\n typeof value.then === 'function'\n );\n}\n\n// Same as in the backend-app-api, handles double defaults from dynamic imports\nfunction unwrapFeature(\n feature: BackendFeature | { default: BackendFeature },\n): BackendFeature {\n if ('$$type' in feature) {\n return feature;\n }\n\n if ('default' in feature) {\n return feature.default;\n }\n\n return feature;\n}\n\nconst backendInstancesToCleanUp = new Array<Backend>();\n\n/** @public */\nexport async function startTestBackend<TExtensionPoints extends any[]>(\n options: TestBackendOptions<TExtensionPoints>,\n): Promise<TestBackend> {\n const { extensionPoints, ...otherOptions } = options;\n\n // Unpack input into awaited plain BackendFeatures\n const features: BackendFeature[] = await Promise.all(\n options.features?.map(async val => {\n if (isPromise(val)) {\n const { default: feature } = await val;\n return unwrapFeature(feature);\n }\n return unwrapFeature(val);\n }) ?? [],\n );\n\n let server: ExtendedHttpServer;\n\n const rootHttpRouterFactory = createServiceFactory({\n service: coreServices.rootHttpRouter,\n deps: {\n config: coreServices.rootConfig,\n lifecycle: coreServices.rootLifecycle,\n rootLogger: coreServices.rootLogger,\n health: coreServices.rootHealth,\n },\n async factory({ config, lifecycle, rootLogger, health }) {\n const router = DefaultRootHttpRouter.create();\n const logger = rootLogger.child({ service: 'rootHttpRouter' });\n\n const app = express();\n\n const middleware = MiddlewareFactory.create({ config, logger });\n const healthRouter = createHealthRouter({ config, health });\n\n app.use(healthRouter);\n app.use(router.handler());\n app.use(middleware.notFound());\n app.use(middleware.error());\n\n server = await createHttpServer(\n app,\n { listen: { host: '', port: 0 } },\n { logger },\n );\n\n lifecycle.addShutdownHook(() => server.stop(), { logger });\n\n await server.start();\n\n return router;\n },\n });\n\n const discoveryFactory = createServiceFactory({\n service: coreServices.discovery,\n deps: {\n rootHttpRouter: coreServices.rootHttpRouter,\n },\n async factory() {\n if (!server) {\n throw new Error('Test server not started yet');\n }\n const port = server.port();\n const discovery = HostDiscovery.fromConfig(\n new ConfigReader({\n backend: { baseUrl: `http://localhost:${port}`, listen: { port } },\n }),\n );\n return discovery;\n },\n });\n\n const backend = createSpecializedBackend({\n ...otherOptions,\n defaultServiceFactories: [\n ...defaultServiceFactories,\n rootHttpRouterFactory,\n discoveryFactory,\n ],\n });\n\n backendInstancesToCleanUp.push(backend);\n\n for (const m of createExtensionPointTestModules(features, extensionPoints)) {\n backend.add(m);\n }\n for (const p of createPluginsForOrphanModules(features)) {\n backend.add(p);\n }\n for (const feature of features) {\n backend.add(feature);\n }\n\n await backend.start();\n\n return Object.assign(backend, {\n get server() {\n if (!server) {\n throw new Error('TestBackend server is not available');\n }\n return server;\n },\n });\n}\n\nlet registered = false;\nfunction registerTestHooks() {\n if (typeof afterAll !== 'function') {\n return;\n }\n if (registered) {\n return;\n }\n registered = true;\n\n afterAll(async () => {\n await Promise.all(\n backendInstancesToCleanUp.map(async backend => {\n try {\n await backend.stop();\n } catch (error) {\n console.error(`Failed to stop backend after tests, ${error}`);\n }\n }),\n );\n backendInstancesToCleanUp.length = 0;\n });\n}\n\nregisterTestHooks();\n\nfunction toInternalBackendFeature(\n feature: BackendFeature,\n): InternalBackendFeature {\n if (feature.$$type !== '@backstage/BackendFeature') {\n throw new Error(`Invalid BackendFeature, bad type '${feature.$$type}'`);\n }\n const internal = feature as InternalBackendFeature;\n if (internal.version !== 'v1') {\n throw new Error(\n `Invalid BackendFeature, bad version '${internal.version}'`,\n );\n }\n return internal;\n}\n\nfunction isInternalBackendRegistrations(\n feature: BackendFeature,\n): feature is InternalBackendRegistrations {\n const internal = toInternalBackendFeature(feature);\n if (internal.featureType === 'registrations') {\n return true;\n }\n // Backwards compatibility for v1 registrations that use duck typing\n return 'getRegistrations' in internal;\n}\n"],"names":["mockServices","actionsRegistryServiceMock","actionsServiceMock","metricsServiceMock","tracingServiceMock","createBackendPlugin","createBackendModule","createServiceFactory","coreServices","DefaultRootHttpRouter","express","MiddlewareFactory","createHealthRouter","createHttpServer","discovery","HostDiscovery","ConfigReader","createSpecializedBackend"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/backend-test-utils",
3
- "version": "1.11.3-next.0",
3
+ "version": "1.11.3-next.2",
4
4
  "description": "Test helpers library for Backstage backends",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -58,13 +58,13 @@
58
58
  },
59
59
  "dependencies": {
60
60
  "@backstage/backend-app-api": "1.7.0-next.0",
61
- "@backstage/backend-defaults": "0.17.1-next.0",
62
- "@backstage/backend-plugin-api": "1.9.1-next.0",
61
+ "@backstage/backend-defaults": "0.17.1-next.2",
62
+ "@backstage/backend-plugin-api": "1.9.1-next.1",
63
63
  "@backstage/config": "1.3.8-next.0",
64
64
  "@backstage/errors": "1.3.1-next.0",
65
- "@backstage/plugin-auth-node": "0.7.1-next.0",
65
+ "@backstage/plugin-auth-node": "0.7.1-next.1",
66
66
  "@backstage/plugin-events-node": "0.4.22-next.0",
67
- "@backstage/plugin-permission-common": "0.9.9-next.0",
67
+ "@backstage/plugin-permission-common": "0.9.9-next.1",
68
68
  "@backstage/types": "1.2.2",
69
69
  "@keyv/memcache": "^2.0.1",
70
70
  "@keyv/redis": "^4.0.1",
@@ -85,13 +85,12 @@
85
85
  "pg-connection-string": "^2.3.0",
86
86
  "testcontainers": "^11.9.0",
87
87
  "text-extensions": "^2.4.0",
88
- "uuid": "^11.0.0",
89
88
  "yn": "^4.0.0",
90
89
  "zod": "^3.25.76 || ^4.0.0",
91
90
  "zod-to-json-schema": "^3.25.1"
92
91
  },
93
92
  "devDependencies": {
94
- "@backstage/cli": "0.36.2-next.0",
93
+ "@backstage/cli": "0.36.2-next.1",
95
94
  "@types/jest": "*",
96
95
  "@types/lodash": "^4.14.151",
97
96
  "@types/supertest": "^2.0.8",