@backstage/backend-test-utils 1.11.3-next.1 → 1.11.3

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,32 @@
1
1
  # @backstage/backend-test-utils
2
2
 
3
+ ## 1.11.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 7fb12b8: Added a new tracing service mock to be leveraged in tests
8
+ - ada7df7: Fixed `mockCredentials` to include the internal `version: 'v1'` field on all credential objects (`none()`, `user()`, `limitedUser()`, `service()`), and fixed `user()` to encode the user entity ref into the token (matching `user.token(ref)` behavior). This makes mock credentials compatible with `toInternalBackstageCredentials()`, which validates the version field, and ensures that credentials for different users produce different tokens.
9
+ - e9b78e9: Removed the `uuid` dependency and replaced usage with the built-in `crypto.randomUUID()`.
10
+ - 6209065: Added `context` and `propagation` to the alpha `TracingService`. Plugins can bridge OpenTelemetry context across async boundaries via `tracing.propagation.extract(tracing.context.active(), carrier)` followed by `tracing.context.with(ctx, fn)`, and read propagated baggage via `tracing.propagation.getActiveBaggage()` or `tracing.propagation.getBaggage(ctx)`.
11
+ - Updated dependencies
12
+ - @backstage/errors@1.3.1
13
+ - @backstage/backend-plugin-api@1.9.1
14
+ - @backstage/backend-defaults@0.17.1
15
+ - @backstage/backend-app-api@1.7.0
16
+ - @backstage/plugin-auth-node@0.7.1
17
+ - @backstage/plugin-permission-common@0.9.9
18
+ - @backstage/config@1.3.8
19
+ - @backstage/plugin-events-node@0.4.22
20
+
21
+ ## 1.11.3-next.2
22
+
23
+ ### Patch Changes
24
+
25
+ - 7fb12b8: Added a new tracing service mock to be leveraged in tests
26
+ - Updated dependencies
27
+ - @backstage/backend-plugin-api@1.9.1-next.1
28
+ - @backstage/backend-defaults@0.17.1-next.2
29
+
3
30
  ## 1.11.3-next.1
4
31
 
5
32
  ### Patch Changes
@@ -0,0 +1,101 @@
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
+ function toMockContext(ctx) {
8
+ return ctx;
9
+ }
10
+ function fromMockContext(ctx) {
11
+ return ctx;
12
+ }
13
+ function parseBaggageHeader(carrier) {
14
+ let raw;
15
+ for (const [name, value] of Object.entries(carrier)) {
16
+ if (name.toLowerCase() !== "baggage") continue;
17
+ raw = Array.isArray(value) ? value[0] : value;
18
+ break;
19
+ }
20
+ if (!raw) return void 0;
21
+ const entries = /* @__PURE__ */ new Map();
22
+ for (const segment of raw.split(",")) {
23
+ const [pair] = segment.split(";");
24
+ const eqIdx = pair.indexOf("=");
25
+ if (eqIdx === -1) continue;
26
+ const key = decodeURIComponent(pair.slice(0, eqIdx).trim());
27
+ const value = decodeURIComponent(pair.slice(eqIdx + 1).trim());
28
+ if (!key) continue;
29
+ entries.set(key, { value });
30
+ }
31
+ if (entries.size === 0) return void 0;
32
+ return {
33
+ getAllEntries: () => Array.from(entries.entries())
34
+ };
35
+ }
36
+ exports.tracingServiceMock = void 0;
37
+ ((tracingServiceMock2) => {
38
+ tracingServiceMock2.factory = () => alpha.tracingServiceFactory;
39
+ tracingServiceMock2.mock = () => {
40
+ const spans = [];
41
+ const startActiveSpan = jest.fn(
42
+ async (_name, optionsOrFn, maybeFn) => {
43
+ const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
44
+ const span = {
45
+ setAttribute: jest.fn(),
46
+ setStatus: jest.fn()
47
+ };
48
+ spans.push(span);
49
+ return await fn(span);
50
+ }
51
+ );
52
+ const contextStack = [{}];
53
+ const active = jest.fn(
54
+ () => fromMockContext(contextStack[contextStack.length - 1])
55
+ );
56
+ const withFn = jest.fn(async (ctx, fn) => {
57
+ contextStack.push(toMockContext(ctx));
58
+ try {
59
+ return await fn();
60
+ } finally {
61
+ contextStack.pop();
62
+ }
63
+ });
64
+ const extract = jest.fn((ctx, carrier) => {
65
+ const baggage = parseBaggageHeader(carrier);
66
+ const base = toMockContext(ctx);
67
+ return fromMockContext({ baggage: baggage ?? base.baggage });
68
+ });
69
+ const getBaggage = jest.fn(
70
+ (ctx) => toMockContext(ctx).baggage
71
+ );
72
+ const getActiveBaggage = jest.fn(
73
+ () => contextStack[contextStack.length - 1].baggage
74
+ );
75
+ const context = {
76
+ active,
77
+ with: withFn
78
+ };
79
+ const propagation = {
80
+ extract,
81
+ getBaggage,
82
+ getActiveBaggage
83
+ };
84
+ const service = {
85
+ startActiveSpan,
86
+ context,
87
+ propagation
88
+ };
89
+ return Object.assign(service, {
90
+ context,
91
+ propagation,
92
+ spans,
93
+ factory: backendPluginApi.createServiceFactory({
94
+ service: alpha$1.tracingServiceRef,
95
+ deps: {},
96
+ factory: () => service
97
+ })
98
+ });
99
+ };
100
+ })(exports.tracingServiceMock || (exports.tracingServiceMock = {}));
101
+ //# 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 TracingServiceBaggage,\n TracingServiceContext,\n TracingServiceContextAPI,\n TracingServicePropagationAPI,\n TracingServiceSpan,\n TracingServiceSpanStatus,\n tracingServiceRef,\n} from '@backstage/backend-plugin-api/alpha';\nimport { tracingServiceFactory } from '@backstage/backend-defaults/alpha';\n\n// Internal context shape used by the mock. The opaque `TracingServiceContext`\n// is just this object cast to the public type.\ninterface MockContext {\n baggage?: TracingServiceBaggage;\n}\n\nfunction toMockContext(ctx: TracingServiceContext): MockContext {\n return ctx as unknown as MockContext;\n}\nfunction fromMockContext(ctx: MockContext): TracingServiceContext {\n return ctx as unknown as TracingServiceContext;\n}\n\n// Parses the `baggage` header per the W3C Baggage member syntax,\n// dropping value properties (`;property=value`). This mirrors what\n// `propagation.extract` does in the real tracing service, just enough\n// for tests to assert end-to-end behaviour between propagated headers\n// and `getActiveBaggage()`.\nfunction parseBaggageHeader(\n carrier: Record<string, string | string[] | undefined>,\n): TracingServiceBaggage | undefined {\n let raw: string | undefined;\n for (const [name, value] of Object.entries(carrier)) {\n if (name.toLowerCase() !== 'baggage') continue;\n raw = Array.isArray(value) ? value[0] : value;\n break;\n }\n if (!raw) return undefined;\n\n const entries = new Map<string, { value: string }>();\n for (const segment of raw.split(',')) {\n const [pair] = segment.split(';');\n const eqIdx = pair.indexOf('=');\n if (eqIdx === -1) continue;\n const key = decodeURIComponent(pair.slice(0, eqIdx).trim());\n const value = decodeURIComponent(pair.slice(eqIdx + 1).trim());\n if (!key) continue;\n entries.set(key, { value });\n }\n if (entries.size === 0) return undefined;\n\n return {\n getAllEntries: () => Array.from(entries.entries()),\n };\n}\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 * Jest-mocked counterpart of the `context` member on the\n * `TracingService`.\n *\n * @alpha\n */\nexport interface MockedTracingServiceContextAPI\n extends TracingServiceContextAPI {\n active: jest.MockedFunction<TracingServiceContextAPI['active']>;\n with: jest.MockedFunction<TracingServiceContextAPI['with']>;\n}\n\n/**\n * Jest-mocked counterpart of the `propagation` member on the\n * `TracingService`.\n *\n * @alpha\n */\nexport interface MockedTracingServicePropagationAPI\n extends TracingServicePropagationAPI {\n extract: jest.MockedFunction<TracingServicePropagationAPI['extract']>;\n getBaggage: jest.MockedFunction<TracingServicePropagationAPI['getBaggage']>;\n getActiveBaggage: jest.MockedFunction<\n TracingServicePropagationAPI['getActiveBaggage']\n >;\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 * By default, `propagation.extract` parses the `baggage` header (W3C\n * Baggage syntax) out of the supplied carrier and stashes the entries\n * on the returned context handle. `context.with` activates that handle\n * for the duration of the wrapped callback so\n * `propagation.getActiveBaggage` (and `propagation.getBaggage` on the\n * supplied handle) returns those entries. Other propagation fields\n * (e.g. `traceparent`) are ignored. Tests that need fully custom\n * baggage can still override `propagation.getActiveBaggage` via\n * `mockReturnValue` / `mockImplementation`, which takes precedence over\n * the default behaviour.\n *\n * Unlike the real `DefaultTracingService`, the mock's `startActiveSpan`\n * does **not** resolve `options.credentials` from `options.request` via\n * `httpAuth`. Tests that need principal-derived span attributes should\n * supply `options.credentials` directly on the span options, or assert\n * on the raw `options` captured by `startActiveSpan.mock.calls`.\n *\n * @alpha\n */\nexport interface TracingServiceMock extends TracingService {\n startActiveSpan: jest.MockedFunction<TracingService['startActiveSpan']>;\n context: MockedTracingServiceContextAPI;\n propagation: MockedTracingServicePropagationAPI;\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(\n async (\n _name: string,\n optionsOrFn: unknown,\n maybeFn?: (span: MockedTracingServiceSpan) => unknown,\n ) => {\n const fn = (\n typeof optionsOrFn === 'function' ? optionsOrFn : maybeFn\n ) as (span: MockedTracingServiceSpan) => unknown;\n const span: MockedTracingServiceSpan = {\n setAttribute: jest.fn(),\n setStatus: jest.fn(),\n };\n spans.push(span);\n return await fn(span);\n },\n ) as unknown as TracingServiceMock['startActiveSpan'];\n\n const contextStack: MockContext[] = [{}];\n\n const active = jest.fn(() =>\n fromMockContext(contextStack[contextStack.length - 1]),\n ) as MockedTracingServiceContextAPI['active'];\n\n const withFn = jest.fn(async (ctx, fn) => {\n contextStack.push(toMockContext(ctx));\n try {\n return await fn();\n } finally {\n contextStack.pop();\n }\n }) as MockedTracingServiceContextAPI['with'];\n\n const extract = jest.fn((ctx, carrier) => {\n const baggage = parseBaggageHeader(carrier);\n // Carry forward the parsed baggage; preserve any baggage already on the\n // supplied handle if the carrier doesn't include one.\n const base = toMockContext(ctx);\n return fromMockContext({ baggage: baggage ?? base.baggage });\n }) as MockedTracingServicePropagationAPI['extract'];\n\n const getBaggage = jest.fn(\n ctx => toMockContext(ctx).baggage,\n ) as MockedTracingServicePropagationAPI['getBaggage'];\n\n const getActiveBaggage = jest.fn(\n () => contextStack[contextStack.length - 1].baggage,\n ) as MockedTracingServicePropagationAPI['getActiveBaggage'];\n\n const context: MockedTracingServiceContextAPI = {\n active,\n with: withFn,\n };\n const propagation: MockedTracingServicePropagationAPI = {\n extract,\n getBaggage,\n getActiveBaggage,\n };\n\n const service: TracingService = {\n startActiveSpan,\n context,\n propagation,\n };\n\n return Object.assign(service as TracingServiceMock, {\n context,\n propagation,\n spans,\n factory: createServiceFactory({\n service: tracingServiceRef,\n deps: {},\n factory: () => service,\n }),\n });\n };\n}\n"],"names":["tracingServiceMock","tracingServiceFactory","createServiceFactory","tracingServiceRef"],"mappings":"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"}
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, TracingServiceContextAPI, TracingServicePropagationAPI, 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,82 @@ 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
+ * Jest-mocked counterpart of the `context` member on the
103
+ * `TracingService`.
104
+ *
105
+ * @alpha
106
+ */
107
+ interface MockedTracingServiceContextAPI extends TracingServiceContextAPI {
108
+ active: jest.MockedFunction<TracingServiceContextAPI['active']>;
109
+ with: jest.MockedFunction<TracingServiceContextAPI['with']>;
110
+ }
111
+ /**
112
+ * Jest-mocked counterpart of the `propagation` member on the
113
+ * `TracingService`.
114
+ *
115
+ * @alpha
116
+ */
117
+ interface MockedTracingServicePropagationAPI extends TracingServicePropagationAPI {
118
+ extract: jest.MockedFunction<TracingServicePropagationAPI['extract']>;
119
+ getBaggage: jest.MockedFunction<TracingServicePropagationAPI['getBaggage']>;
120
+ getActiveBaggage: jest.MockedFunction<TracingServicePropagationAPI['getActiveBaggage']>;
121
+ }
122
+ /**
123
+ * Mock for the `TracingService`. Captures every span created via
124
+ * `startActiveSpan` so tests can assert on the options passed in and the
125
+ * methods called on the span inside the callback.
126
+ *
127
+ * By default, `propagation.extract` parses the `baggage` header (W3C
128
+ * Baggage syntax) out of the supplied carrier and stashes the entries
129
+ * on the returned context handle. `context.with` activates that handle
130
+ * for the duration of the wrapped callback so
131
+ * `propagation.getActiveBaggage` (and `propagation.getBaggage` on the
132
+ * supplied handle) returns those entries. Other propagation fields
133
+ * (e.g. `traceparent`) are ignored. Tests that need fully custom
134
+ * baggage can still override `propagation.getActiveBaggage` via
135
+ * `mockReturnValue` / `mockImplementation`, which takes precedence over
136
+ * the default behaviour.
137
+ *
138
+ * Unlike the real `DefaultTracingService`, the mock's `startActiveSpan`
139
+ * does **not** resolve `options.credentials` from `options.request` via
140
+ * `httpAuth`. Tests that need principal-derived span attributes should
141
+ * supply `options.credentials` directly on the span options, or assert
142
+ * on the raw `options` captured by `startActiveSpan.mock.calls`.
143
+ *
144
+ * @alpha
145
+ */
146
+ interface TracingServiceMock extends TracingService {
147
+ startActiveSpan: jest.MockedFunction<TracingService['startActiveSpan']>;
148
+ context: MockedTracingServiceContextAPI;
149
+ propagation: MockedTracingServicePropagationAPI;
150
+ /** Spans created by `startActiveSpan` calls, in order. */
151
+ spans: MockedTracingServiceSpan[];
152
+ factory: ServiceFactory<TracingService>;
153
+ }
154
+ /**
155
+ * @alpha
156
+ */
157
+ declare namespace tracingServiceMock {
158
+ /**
159
+ * Returns the real `tracingServiceFactory` from `@backstage/backend-defaults`,
160
+ * for tests that want the full default implementation.
161
+ */
162
+ const factory: () => ServiceFactory<TracingService, "plugin", "singleton">;
163
+ /**
164
+ * Builds a mock `TracingService` backed by jest mocks.
165
+ */
166
+ const mock: () => TracingServiceMock;
167
+ }
168
+
169
+ export { MockActionsRegistry, ServiceMock, actionsRegistryServiceMock, actionsServiceMock, metricsServiceMock, tracingServiceMock };
170
+ export type { MockedTracingServiceContextAPI, MockedTracingServicePropagationAPI, MockedTracingServiceSpan, TracingServiceMock };
@@ -24,6 +24,7 @@ exports.mockCredentials = void 0;
24
24
  function none() {
25
25
  const result = {
26
26
  $$type: "@backstage/BackstageCredentials",
27
+ version: "v1",
27
28
  principal: { type: "none" }
28
29
  };
29
30
  Object.defineProperties(result, {
@@ -47,6 +48,7 @@ exports.mockCredentials = void 0;
47
48
  validateUserEntityRef(userEntityRef);
48
49
  const result = {
49
50
  $$type: "@backstage/BackstageCredentials",
51
+ version: "v1",
50
52
  principal: {
51
53
  type: "user",
52
54
  userEntityRef,
@@ -64,7 +66,7 @@ exports.mockCredentials = void 0;
64
66
  token: {
65
67
  enumerable: false,
66
68
  configurable: true,
67
- value: user.token()
69
+ value: userEntityRef !== DEFAULT_MOCK_USER_ENTITY_REF || options?.actor ? user.token(userEntityRef, options) : user.token()
68
70
  }
69
71
  });
70
72
  return result;
@@ -125,6 +127,7 @@ exports.mockCredentials = void 0;
125
127
  function service(subject = DEFAULT_MOCK_SERVICE_SUBJECT, accessRestrictions) {
126
128
  const result = {
127
129
  $$type: "@backstage/BackstageCredentials",
130
+ version: "v1",
128
131
  principal: {
129
132
  type: "service",
130
133
  subject,
@@ -1 +1 @@
1
- {"version":3,"file":"mockCredentials.cjs.js","sources":["../../src/services/mockCredentials.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 {\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalAccessRestrictions,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n} from '@backstage/backend-plugin-api';\n\nexport const DEFAULT_MOCK_USER_ENTITY_REF = 'user:default/mock';\nexport const DEFAULT_MOCK_SERVICE_SUBJECT = 'external:test-service';\n\nexport const MOCK_AUTH_COOKIE = 'backstage-auth';\n\nexport const MOCK_NONE_TOKEN = 'mock-none-token';\n\nexport const MOCK_USER_TOKEN = 'mock-user-token';\nexport const MOCK_USER_TOKEN_PREFIX = 'mock-user-token:';\nexport const MOCK_INVALID_USER_TOKEN = 'mock-invalid-user-token';\n\nexport const MOCK_USER_LIMITED_TOKEN_PREFIX = 'mock-limited-user-token:';\nexport const MOCK_INVALID_USER_LIMITED_TOKEN =\n 'mock-invalid-limited-user-token';\n\nexport const MOCK_SERVICE_TOKEN = 'mock-service-token';\nexport const MOCK_SERVICE_TOKEN_PREFIX = 'mock-service-token:';\nexport const MOCK_INVALID_SERVICE_TOKEN = 'mock-invalid-service-token';\n\nfunction validateUserEntityRef(ref: string) {\n if (!ref.match(/^.+:.+\\/.+$/)) {\n throw new TypeError(\n `Invalid user entity reference '${ref}', expected <kind>:<namespace>/<name>`,\n );\n }\n}\n\n/**\n * The payload that can be encoded into a mock user token.\n * @internal\n */\nexport type UserTokenPayload = {\n sub?: string;\n actor?: { subject: string };\n};\n\n/**\n * The payload that can be encoded into a mock service token.\n * @internal\n */\nexport type ServiceTokenPayload = {\n sub?: string; // service subject\n obo?: string; // user entity reference\n target?: string; // target plugin id\n};\n\n/**\n * @public\n */\nexport namespace mockCredentials {\n /**\n * Creates a mocked credentials object for a unauthenticated principal.\n */\n export function none(): BackstageCredentials<BackstageNonePrincipal> {\n const result = {\n $$type: '@backstage/BackstageCredentials',\n principal: { type: 'none' },\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => `mockCredentials{nonePrincipal}`,\n },\n });\n return result;\n }\n\n /**\n * Utilities related to none credentials.\n */\n export namespace none {\n /**\n * Returns an authorization header that translates to unauthenticated\n * credentials.\n *\n * This is useful when one wants to explicitly test unauthenticated requests\n * while still using the default behavior of the mock HttpAuthService where\n * it defaults to user credentials.\n */\n export function header(): string {\n // NOTE: there is no .token() version of this because only the\n // HttpAuthService should know about and consume this token\n return `Bearer ${MOCK_NONE_TOKEN}`;\n }\n }\n\n /**\n * Creates a mocked credentials object for a user principal.\n *\n * The default user entity reference is 'user:default/mock'.\n */\n export function user(\n userEntityRef: string = DEFAULT_MOCK_USER_ENTITY_REF,\n options?: { actor?: { subject: string } },\n ): BackstageCredentials<BackstageUserPrincipal> {\n validateUserEntityRef(userEntityRef);\n const result = {\n $$type: '@backstage/BackstageCredentials',\n principal: {\n type: 'user',\n userEntityRef,\n ...(options?.actor && {\n actor: { type: 'service', subject: options.actor.subject } as const,\n }),\n },\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n value: () =>\n `mockCredentials{userPrincipal{${userEntityRef}${\n options?.actor ? `,actor={${options.actor.subject}}` : ''\n }}}`,\n },\n token: {\n enumerable: false,\n configurable: true,\n value: user.token(),\n },\n });\n return result;\n }\n\n /**\n * Utilities related to user credentials.\n */\n export namespace user {\n /**\n * Creates a mocked user token. If a payload is provided it will be encoded\n * into the token and forwarded to the credentials object when authenticated\n * by the mock auth service.\n */\n export function token(\n userEntityRef?: string,\n options?: { actor?: { subject: string } },\n ): string {\n if (userEntityRef) {\n validateUserEntityRef(userEntityRef);\n return `${MOCK_USER_TOKEN_PREFIX}${JSON.stringify({\n sub: userEntityRef,\n ...(options?.actor && {\n actor: { subject: options.actor.subject },\n }),\n } satisfies UserTokenPayload)}`;\n }\n return MOCK_USER_TOKEN;\n }\n\n /**\n * Returns an authorization header with a mocked user token. If a payload is\n * provided it will be encoded into the token and forwarded to the\n * credentials object when authenticated by the mock auth service.\n */\n export function header(userEntityRef?: string): string {\n return `Bearer ${token(userEntityRef)}`;\n }\n\n export function invalidToken(): string {\n return MOCK_INVALID_USER_TOKEN;\n }\n\n export function invalidHeader(): string {\n return `Bearer ${invalidToken()}`;\n }\n }\n\n /**\n * Creates a mocked credentials object for a user principal with limited\n * access.\n *\n * The default user entity reference is 'user:default/mock'.\n */\n export function limitedUser(\n userEntityRef: string = DEFAULT_MOCK_USER_ENTITY_REF,\n ): BackstageCredentials<BackstageUserPrincipal> {\n return user(userEntityRef);\n }\n\n /**\n * Utilities related to limited user credentials.\n */\n export namespace limitedUser {\n /**\n * Creates a mocked limited user token. If a payload is provided it will be\n * encoded into the token and forwarded to the credentials object when\n * authenticated by the mock auth service.\n */\n export function token(\n userEntityRef: string = DEFAULT_MOCK_USER_ENTITY_REF,\n ): string {\n validateUserEntityRef(userEntityRef);\n return `${MOCK_USER_LIMITED_TOKEN_PREFIX}${JSON.stringify({\n sub: userEntityRef,\n } satisfies UserTokenPayload)}`;\n }\n\n /**\n * Returns an authorization header with a mocked limited user token. If a\n * payload is provided it will be encoded into the token and forwarded to\n * the credentials object when authenticated by the mock auth service.\n */\n export function cookie(userEntityRef?: string): string {\n return `${MOCK_AUTH_COOKIE}=${token(userEntityRef)}`;\n }\n\n export function invalidToken(): string {\n return MOCK_INVALID_USER_LIMITED_TOKEN;\n }\n\n export function invalidCookie(): string {\n return `${MOCK_AUTH_COOKIE}=${invalidToken()}`;\n }\n }\n\n /**\n * Creates a mocked credentials object for a service principal.\n *\n * The default subject is 'external:test-service', and no access restrictions.\n */\n export function service(\n subject: string = DEFAULT_MOCK_SERVICE_SUBJECT,\n accessRestrictions?: BackstagePrincipalAccessRestrictions,\n ): BackstageCredentials<BackstageServicePrincipal> {\n const result = {\n $$type: '@backstage/BackstageCredentials',\n principal: {\n type: 'service',\n subject,\n ...(accessRestrictions ? { accessRestrictions } : {}),\n },\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n value: () =>\n `mockCredentials{servicePrincipal{${subject}${\n accessRestrictions\n ? `,accessRestrictions=${JSON.stringify(accessRestrictions)}`\n : ''\n }}}`,\n },\n });\n return result;\n }\n\n /**\n * Utilities related to service credentials.\n */\n export namespace service {\n /**\n * Options for the creation of mock service tokens.\n */\n export type TokenOptions = {\n onBehalfOf: BackstageCredentials;\n targetPluginId: string;\n };\n\n /**\n * Creates a mocked service token. The provided options will be encoded into\n * the token and forwarded to the credentials object when authenticated by\n * the mock auth service.\n */\n export function token(options?: TokenOptions): string {\n if (options) {\n const { targetPluginId, onBehalfOf } = options; // for fixed ordering\n\n const oboPrincipal = onBehalfOf?.principal as\n | BackstageServicePrincipal\n | BackstageUserPrincipal\n | BackstageNonePrincipal;\n const obo =\n oboPrincipal.type === 'user' ? oboPrincipal.userEntityRef : undefined;\n const subject =\n oboPrincipal.type === 'service' ? oboPrincipal.subject : undefined;\n\n return `${MOCK_SERVICE_TOKEN_PREFIX}${JSON.stringify({\n sub: subject,\n obo,\n target: targetPluginId,\n } satisfies ServiceTokenPayload)}`;\n }\n return MOCK_SERVICE_TOKEN;\n }\n\n /**\n * Returns an authorization header with a mocked service token. The provided\n * options will be encoded into the token and forwarded to the credentials\n * object when authenticated by the mock auth service.\n */\n export function header(options?: TokenOptions): string {\n return `Bearer ${token(options)}`;\n }\n\n export function invalidToken(): string {\n return MOCK_INVALID_SERVICE_TOKEN;\n }\n\n export function invalidHeader(): string {\n return `Bearer ${invalidToken()}`;\n }\n }\n}\n"],"names":["mockCredentials","none","user","limitedUser","service"],"mappings":"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"}
1
+ {"version":3,"file":"mockCredentials.cjs.js","sources":["../../src/services/mockCredentials.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 {\n BackstageCredentials,\n BackstageNonePrincipal,\n BackstagePrincipalAccessRestrictions,\n BackstageServicePrincipal,\n BackstageUserPrincipal,\n} from '@backstage/backend-plugin-api';\n\nexport const DEFAULT_MOCK_USER_ENTITY_REF = 'user:default/mock';\nexport const DEFAULT_MOCK_SERVICE_SUBJECT = 'external:test-service';\n\nexport const MOCK_AUTH_COOKIE = 'backstage-auth';\n\nexport const MOCK_NONE_TOKEN = 'mock-none-token';\n\nexport const MOCK_USER_TOKEN = 'mock-user-token';\nexport const MOCK_USER_TOKEN_PREFIX = 'mock-user-token:';\nexport const MOCK_INVALID_USER_TOKEN = 'mock-invalid-user-token';\n\nexport const MOCK_USER_LIMITED_TOKEN_PREFIX = 'mock-limited-user-token:';\nexport const MOCK_INVALID_USER_LIMITED_TOKEN =\n 'mock-invalid-limited-user-token';\n\nexport const MOCK_SERVICE_TOKEN = 'mock-service-token';\nexport const MOCK_SERVICE_TOKEN_PREFIX = 'mock-service-token:';\nexport const MOCK_INVALID_SERVICE_TOKEN = 'mock-invalid-service-token';\n\nfunction validateUserEntityRef(ref: string) {\n if (!ref.match(/^.+:.+\\/.+$/)) {\n throw new TypeError(\n `Invalid user entity reference '${ref}', expected <kind>:<namespace>/<name>`,\n );\n }\n}\n\n/**\n * The payload that can be encoded into a mock user token.\n * @internal\n */\nexport type UserTokenPayload = {\n sub?: string;\n actor?: { subject: string };\n};\n\n/**\n * The payload that can be encoded into a mock service token.\n * @internal\n */\nexport type ServiceTokenPayload = {\n sub?: string; // service subject\n obo?: string; // user entity reference\n target?: string; // target plugin id\n};\n\n/**\n * @public\n */\nexport namespace mockCredentials {\n /**\n * Creates a mocked credentials object for a unauthenticated principal.\n */\n export function none(): BackstageCredentials<BackstageNonePrincipal> {\n const result = {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal: { type: 'none' },\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n writable: true,\n value: () => `mockCredentials{nonePrincipal}`,\n },\n });\n return result;\n }\n\n /**\n * Utilities related to none credentials.\n */\n export namespace none {\n /**\n * Returns an authorization header that translates to unauthenticated\n * credentials.\n *\n * This is useful when one wants to explicitly test unauthenticated requests\n * while still using the default behavior of the mock HttpAuthService where\n * it defaults to user credentials.\n */\n export function header(): string {\n // NOTE: there is no .token() version of this because only the\n // HttpAuthService should know about and consume this token\n return `Bearer ${MOCK_NONE_TOKEN}`;\n }\n }\n\n /**\n * Creates a mocked credentials object for a user principal.\n *\n * The default user entity reference is 'user:default/mock'.\n */\n export function user(\n userEntityRef: string = DEFAULT_MOCK_USER_ENTITY_REF,\n options?: { actor?: { subject: string } },\n ): BackstageCredentials<BackstageUserPrincipal> {\n validateUserEntityRef(userEntityRef);\n const result = {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal: {\n type: 'user',\n userEntityRef,\n ...(options?.actor && {\n actor: { type: 'service', subject: options.actor.subject } as const,\n }),\n },\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n value: () =>\n `mockCredentials{userPrincipal{${userEntityRef}${\n options?.actor ? `,actor={${options.actor.subject}}` : ''\n }}}`,\n },\n token: {\n enumerable: false,\n configurable: true,\n value:\n userEntityRef !== DEFAULT_MOCK_USER_ENTITY_REF || options?.actor\n ? user.token(userEntityRef, options)\n : user.token(),\n },\n });\n return result;\n }\n\n /**\n * Utilities related to user credentials.\n */\n export namespace user {\n /**\n * Creates a mocked user token. If a payload is provided it will be encoded\n * into the token and forwarded to the credentials object when authenticated\n * by the mock auth service.\n */\n export function token(\n userEntityRef?: string,\n options?: { actor?: { subject: string } },\n ): string {\n if (userEntityRef) {\n validateUserEntityRef(userEntityRef);\n return `${MOCK_USER_TOKEN_PREFIX}${JSON.stringify({\n sub: userEntityRef,\n ...(options?.actor && {\n actor: { subject: options.actor.subject },\n }),\n } satisfies UserTokenPayload)}`;\n }\n return MOCK_USER_TOKEN;\n }\n\n /**\n * Returns an authorization header with a mocked user token. If a payload is\n * provided it will be encoded into the token and forwarded to the\n * credentials object when authenticated by the mock auth service.\n */\n export function header(userEntityRef?: string): string {\n return `Bearer ${token(userEntityRef)}`;\n }\n\n export function invalidToken(): string {\n return MOCK_INVALID_USER_TOKEN;\n }\n\n export function invalidHeader(): string {\n return `Bearer ${invalidToken()}`;\n }\n }\n\n /**\n * Creates a mocked credentials object for a user principal with limited\n * access.\n *\n * The default user entity reference is 'user:default/mock'.\n */\n export function limitedUser(\n userEntityRef: string = DEFAULT_MOCK_USER_ENTITY_REF,\n ): BackstageCredentials<BackstageUserPrincipal> {\n return user(userEntityRef);\n }\n\n /**\n * Utilities related to limited user credentials.\n */\n export namespace limitedUser {\n /**\n * Creates a mocked limited user token. If a payload is provided it will be\n * encoded into the token and forwarded to the credentials object when\n * authenticated by the mock auth service.\n */\n export function token(\n userEntityRef: string = DEFAULT_MOCK_USER_ENTITY_REF,\n ): string {\n validateUserEntityRef(userEntityRef);\n return `${MOCK_USER_LIMITED_TOKEN_PREFIX}${JSON.stringify({\n sub: userEntityRef,\n } satisfies UserTokenPayload)}`;\n }\n\n /**\n * Returns an authorization header with a mocked limited user token. If a\n * payload is provided it will be encoded into the token and forwarded to\n * the credentials object when authenticated by the mock auth service.\n */\n export function cookie(userEntityRef?: string): string {\n return `${MOCK_AUTH_COOKIE}=${token(userEntityRef)}`;\n }\n\n export function invalidToken(): string {\n return MOCK_INVALID_USER_LIMITED_TOKEN;\n }\n\n export function invalidCookie(): string {\n return `${MOCK_AUTH_COOKIE}=${invalidToken()}`;\n }\n }\n\n /**\n * Creates a mocked credentials object for a service principal.\n *\n * The default subject is 'external:test-service', and no access restrictions.\n */\n export function service(\n subject: string = DEFAULT_MOCK_SERVICE_SUBJECT,\n accessRestrictions?: BackstagePrincipalAccessRestrictions,\n ): BackstageCredentials<BackstageServicePrincipal> {\n const result = {\n $$type: '@backstage/BackstageCredentials',\n version: 'v1',\n principal: {\n type: 'service',\n subject,\n ...(accessRestrictions ? { accessRestrictions } : {}),\n },\n } as const;\n Object.defineProperties(result, {\n toString: {\n enumerable: false,\n configurable: true,\n value: () =>\n `mockCredentials{servicePrincipal{${subject}${\n accessRestrictions\n ? `,accessRestrictions=${JSON.stringify(accessRestrictions)}`\n : ''\n }}}`,\n },\n });\n return result;\n }\n\n /**\n * Utilities related to service credentials.\n */\n export namespace service {\n /**\n * Options for the creation of mock service tokens.\n */\n export type TokenOptions = {\n onBehalfOf: BackstageCredentials;\n targetPluginId: string;\n };\n\n /**\n * Creates a mocked service token. The provided options will be encoded into\n * the token and forwarded to the credentials object when authenticated by\n * the mock auth service.\n */\n export function token(options?: TokenOptions): string {\n if (options) {\n const { targetPluginId, onBehalfOf } = options; // for fixed ordering\n\n const oboPrincipal = onBehalfOf?.principal as\n | BackstageServicePrincipal\n | BackstageUserPrincipal\n | BackstageNonePrincipal;\n const obo =\n oboPrincipal.type === 'user' ? oboPrincipal.userEntityRef : undefined;\n const subject =\n oboPrincipal.type === 'service' ? oboPrincipal.subject : undefined;\n\n return `${MOCK_SERVICE_TOKEN_PREFIX}${JSON.stringify({\n sub: subject,\n obo,\n target: targetPluginId,\n } satisfies ServiceTokenPayload)}`;\n }\n return MOCK_SERVICE_TOKEN;\n }\n\n /**\n * Returns an authorization header with a mocked service token. The provided\n * options will be encoded into the token and forwarded to the credentials\n * object when authenticated by the mock auth service.\n */\n export function header(options?: TokenOptions): string {\n return `Bearer ${token(options)}`;\n }\n\n export function invalidToken(): string {\n return MOCK_INVALID_SERVICE_TOKEN;\n }\n\n export function invalidHeader(): string {\n return `Bearer ${invalidToken()}`;\n }\n }\n}\n"],"names":["mockCredentials","none","user","limitedUser","service"],"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.1",
3
+ "version": "1.11.3",
4
4
  "description": "Test helpers library for Backstage backends",
5
5
  "backstage": {
6
6
  "role": "node-library"
@@ -57,15 +57,15 @@
57
57
  "test": "backstage-cli package test"
58
58
  },
59
59
  "dependencies": {
60
- "@backstage/backend-app-api": "1.7.0-next.0",
61
- "@backstage/backend-defaults": "0.17.1-next.1",
62
- "@backstage/backend-plugin-api": "1.9.1-next.0",
63
- "@backstage/config": "1.3.8-next.0",
64
- "@backstage/errors": "1.3.1-next.0",
65
- "@backstage/plugin-auth-node": "0.7.1-next.1",
66
- "@backstage/plugin-events-node": "0.4.22-next.0",
67
- "@backstage/plugin-permission-common": "0.9.9-next.1",
68
- "@backstage/types": "1.2.2",
60
+ "@backstage/backend-app-api": "^1.7.0",
61
+ "@backstage/backend-defaults": "^0.17.1",
62
+ "@backstage/backend-plugin-api": "^1.9.1",
63
+ "@backstage/config": "^1.3.8",
64
+ "@backstage/errors": "^1.3.1",
65
+ "@backstage/plugin-auth-node": "^0.7.1",
66
+ "@backstage/plugin-events-node": "^0.4.22",
67
+ "@backstage/plugin-permission-common": "^0.9.9",
68
+ "@backstage/types": "^1.2.2",
69
69
  "@keyv/memcache": "^2.0.1",
70
70
  "@keyv/redis": "^4.0.1",
71
71
  "@keyv/valkey": "^1.0.1",
@@ -90,7 +90,7 @@
90
90
  "zod-to-json-schema": "^3.25.1"
91
91
  },
92
92
  "devDependencies": {
93
- "@backstage/cli": "0.36.2-next.1",
93
+ "@backstage/cli": "^0.36.2",
94
94
  "@types/jest": "*",
95
95
  "@types/lodash": "^4.14.151",
96
96
  "@types/supertest": "^2.0.8",