autotel 3.0.6 → 3.0.7
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/dist/attribute-redacting-processor.cjs +0 -1
- package/dist/attribute-redacting-processor.js +0 -1
- package/dist/attributes.cjs +0 -1
- package/dist/attributes.js +0 -1
- package/dist/auto.cjs +5 -6
- package/dist/auto.cjs.map +1 -1
- package/dist/auto.js +3 -4
- package/dist/auto.js.map +1 -1
- package/dist/business-baggage.cjs +0 -1
- package/dist/business-baggage.js +0 -1
- package/dist/{chunk-H5YFU4SF.js → chunk-6VVEOLG5.js} +4 -4
- package/dist/{chunk-H5YFU4SF.js.map → chunk-6VVEOLG5.js.map} +1 -1
- package/dist/{chunk-XCFDXZF3.cjs → chunk-727YZJUB.cjs} +7 -7
- package/dist/{chunk-XCFDXZF3.cjs.map → chunk-727YZJUB.cjs.map} +1 -1
- package/dist/{chunk-3SDILILG.js → chunk-7NDHLHZK.js} +3 -3
- package/dist/{chunk-3SDILILG.js.map → chunk-7NDHLHZK.js.map} +1 -1
- package/dist/{chunk-DAZ7EGR4.cjs → chunk-ADZDAWNV.cjs} +17 -17
- package/dist/{chunk-DAZ7EGR4.cjs.map → chunk-ADZDAWNV.cjs.map} +1 -1
- package/dist/{chunk-NCSMD3TK.cjs → chunk-BGAR6MCX.cjs} +4 -4
- package/dist/{chunk-NCSMD3TK.cjs.map → chunk-BGAR6MCX.cjs.map} +1 -1
- package/dist/{chunk-OC6X2VIN.cjs → chunk-BTEPYWDF.cjs} +4 -4
- package/dist/{chunk-OC6X2VIN.cjs.map → chunk-BTEPYWDF.cjs.map} +1 -1
- package/dist/chunk-EQIY6C3X.cjs +25 -0
- package/dist/chunk-EQIY6C3X.cjs.map +1 -0
- package/dist/{chunk-HLAVN3JR.js → chunk-I7ODAZJL.js} +3 -3
- package/dist/{chunk-HLAVN3JR.js.map → chunk-I7ODAZJL.js.map} +1 -1
- package/dist/{chunk-Z7VAOK5X.js → chunk-IC4AZUGC.js} +3 -3
- package/dist/{chunk-Z7VAOK5X.js.map → chunk-IC4AZUGC.js.map} +1 -1
- package/dist/{chunk-BPO2PQ3T.cjs → chunk-ISEHXVMD.cjs} +30 -26
- package/dist/chunk-ISEHXVMD.cjs.map +1 -0
- package/dist/{chunk-S4S4AINO.js → chunk-JITYRSI4.js} +5 -5
- package/dist/{chunk-S4S4AINO.js.map → chunk-JITYRSI4.js.map} +1 -1
- package/dist/{chunk-KKGM42RQ.cjs → chunk-KAELJC6T.cjs} +13 -13
- package/dist/{chunk-KKGM42RQ.cjs.map → chunk-KAELJC6T.cjs.map} +1 -1
- package/dist/{chunk-ZJ5E5OFB.js → chunk-KGBRZ7J5.js} +3 -3
- package/dist/{chunk-ZJ5E5OFB.js.map → chunk-KGBRZ7J5.js.map} +1 -1
- package/dist/{chunk-33WTKH7X.js → chunk-KPNV2GPW.js} +4 -4
- package/dist/chunk-KPNV2GPW.js.map +1 -0
- package/dist/{chunk-IRJHH6PH.cjs → chunk-LOTJ7SDI.cjs} +5 -5
- package/dist/{chunk-IRJHH6PH.cjs.map → chunk-LOTJ7SDI.cjs.map} +1 -1
- package/dist/{chunk-OM4OSBOP.js → chunk-MAITXZFR.js} +4 -4
- package/dist/{chunk-OM4OSBOP.js.map → chunk-MAITXZFR.js.map} +1 -1
- package/dist/{chunk-DSMSIVTG.js → chunk-MBEHEGQE.js} +3 -3
- package/dist/{chunk-DSMSIVTG.js.map → chunk-MBEHEGQE.js.map} +1 -1
- package/dist/{chunk-K4UDKM3P.cjs → chunk-NC5BG7B3.cjs} +11 -11
- package/dist/{chunk-K4UDKM3P.cjs.map → chunk-NC5BG7B3.cjs.map} +1 -1
- package/dist/{chunk-ZDPIWKWD.js → chunk-SIMG4IGE.js} +18 -14
- package/dist/chunk-SIMG4IGE.js.map +1 -0
- package/dist/{chunk-TY4NXDYR.cjs → chunk-VNMT2TDZ.cjs} +36 -36
- package/dist/{chunk-TY4NXDYR.cjs.map → chunk-VNMT2TDZ.cjs.map} +1 -1
- package/dist/config.cjs +0 -1
- package/dist/config.js +0 -1
- package/dist/correlation-id.cjs +12 -13
- package/dist/correlation-id.js +4 -5
- package/dist/db.cjs +0 -1
- package/dist/db.cjs.map +1 -1
- package/dist/db.js +0 -1
- package/dist/db.js.map +1 -1
- package/dist/decorators.cjs +7 -8
- package/dist/decorators.cjs.map +1 -1
- package/dist/decorators.js +6 -7
- package/dist/decorators.js.map +1 -1
- package/dist/drain-pipeline.cjs +0 -1
- package/dist/drain-pipeline.js +0 -1
- package/dist/enrichers.cjs +0 -2
- package/dist/enrichers.cjs.map +1 -1
- package/dist/enrichers.js +0 -2
- package/dist/enrichers.js.map +1 -1
- package/dist/event-testing.cjs +0 -1
- package/dist/event-testing.js +0 -1
- package/dist/event.cjs +8 -9
- package/dist/event.js +5 -6
- package/dist/exporters.cjs +0 -1
- package/dist/exporters.js +0 -1
- package/dist/filtering-span-processor.cjs +0 -1
- package/dist/filtering-span-processor.js +0 -1
- package/dist/functional.cjs +13 -14
- package/dist/functional.js +6 -7
- package/dist/http.cjs +5 -6
- package/dist/http.cjs.map +1 -1
- package/dist/http.js +4 -5
- package/dist/http.js.map +1 -1
- package/dist/index.cjs +82 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -15
- package/dist/index.js.map +1 -1
- package/dist/{init-D6JfWEjL.d.ts → init-BSyIyDs5.d.ts} +36 -1
- package/dist/{init-CMuTaFAV.d.cts → init-D9Bxx39e.d.cts} +36 -1
- package/dist/instrumentation.cjs +11 -12
- package/dist/instrumentation.cjs.map +1 -1
- package/dist/instrumentation.js +3 -4
- package/dist/instrumentation.js.map +1 -1
- package/dist/logger.cjs +0 -1
- package/dist/logger.js +0 -1
- package/dist/messaging-adapters.cjs +1 -1
- package/dist/messaging-adapters.js +1 -1
- package/dist/messaging-testing.cjs +0 -2
- package/dist/messaging-testing.cjs.map +1 -1
- package/dist/messaging-testing.js +0 -2
- package/dist/messaging-testing.js.map +1 -1
- package/dist/messaging.cjs +10 -11
- package/dist/messaging.js +7 -8
- package/dist/metric-helpers.cjs +0 -1
- package/dist/metric-helpers.js +0 -1
- package/dist/metric-testing.cjs +0 -1
- package/dist/metric-testing.js +0 -1
- package/dist/metric.cjs +0 -1
- package/dist/metric.js +0 -1
- package/dist/parse-error.cjs +0 -1
- package/dist/parse-error.js +0 -1
- package/dist/processors.cjs +0 -1
- package/dist/processors.js +0 -1
- package/dist/sampling.cjs +0 -1
- package/dist/sampling.js +0 -1
- package/dist/semantic-conventions.cjs +0 -1
- package/dist/semantic-conventions.js +0 -1
- package/dist/semantic-helpers.cjs +11 -12
- package/dist/semantic-helpers.js +7 -8
- package/dist/span-name-normalizer.cjs +0 -1
- package/dist/span-name-normalizer.js +0 -1
- package/dist/tail-sampling-processor.cjs +0 -1
- package/dist/tail-sampling-processor.js +0 -1
- package/dist/test-span-collector.cjs +1 -1
- package/dist/test-span-collector.js +1 -1
- package/dist/testing.cjs +0 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +0 -1
- package/dist/testing.js.map +1 -1
- package/dist/trace-helpers.cjs +14 -15
- package/dist/trace-helpers.js +2 -3
- package/dist/tracer-provider.cjs +0 -1
- package/dist/tracer-provider.js +0 -1
- package/dist/webhook.cjs +8 -9
- package/dist/webhook.cjs.map +1 -1
- package/dist/webhook.js +6 -7
- package/dist/webhook.js.map +1 -1
- package/dist/workflow-distributed.cjs +8 -9
- package/dist/workflow-distributed.cjs.map +1 -1
- package/dist/workflow-distributed.js +6 -7
- package/dist/workflow-distributed.js.map +1 -1
- package/dist/workflow.cjs +11 -12
- package/dist/workflow.js +7 -8
- package/dist/yaml-config.cjs +5 -6
- package/dist/yaml-config.d.cts +1 -1
- package/dist/yaml-config.d.ts +1 -1
- package/dist/yaml-config.js +2 -3
- package/package.json +1 -1
- package/src/init.customization.test.ts +80 -0
- package/src/init.ts +78 -15
- package/src/node-require.ts +7 -5
- package/dist/chunk-33WTKH7X.js.map +0 -1
- package/dist/chunk-BPO2PQ3T.cjs.map +0 -1
- package/dist/chunk-DGUM43GV.js +0 -10
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-JEQ2X3Z6.cjs +0 -12
- package/dist/chunk-JEQ2X3Z6.cjs.map +0 -1
- package/dist/chunk-YS6C2YJE.cjs +0 -25
- package/dist/chunk-YS6C2YJE.cjs.map +0 -1
- package/dist/chunk-ZDPIWKWD.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/instrumentation.ts"],"names":[],"mappings":"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","file":"instrumentation.js","sourcesContent":["import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\nimport { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { TailSamplingSpanProcessor } from './tail-sampling-processor';\nimport { getLogger } from './init';\nimport {\n resourceFromAttributes,\n detectResources,\n processDetector,\n hostDetector,\n type Resource,\n type ResourceDetector,\n} from '@opentelemetry/resources';\nimport {\n ATTR_SERVICE_NAME,\n ATTR_SERVICE_VERSION,\n} from '@opentelemetry/semantic-conventions/incubating';\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';\nimport { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';\nimport { requireModule } from './node-require';\n\n/**\n * Parse OTLP headers string into object format\n * @param headersString - Headers as \"key1=value1,key2=value2\" or \"Authorization=Basic ...\"\n * @returns Headers object for OTLP exporters\n */\nfunction parseOtlpHeaders(headersString?: string): Record<string, string> {\n if (!headersString) return {};\n\n const headers: Record<string, string> = {};\n const pairs = headersString.split(',');\n\n for (const pair of pairs) {\n const [key, ...valueParts] = pair.split('=');\n if (key && valueParts.length > 0) {\n headers[key.trim()] = valueParts.join('=').trim();\n }\n }\n\n return headers;\n}\n\n/**\n * Parse resource attributes string into object format\n * @param attributesString - Attributes as \"key1=value1,key2=value2\"\n * @returns Resource attributes object\n */\nfunction parseResourceAttributes(\n attributesString?: string,\n): Record<string, string> {\n if (!attributesString) return {};\n\n const attributes: Record<string, string> = {};\n const pairs = attributesString.split(',');\n\n for (const pair of pairs) {\n const [key, ...valueParts] = pair.split('=');\n if (key && valueParts.length > 0) {\n attributes[key.trim()] = valueParts.join('=').trim();\n }\n }\n\n return attributes;\n}\n\nexport interface InstrumentationConfig {\n serviceName: string;\n serviceVersion?: string;\n deploymentEnvironment?: string;\n otlpEndpoint?: string;\n /** Headers for authentication (e.g., Grafana Cloud, Honeycomb) */\n headers?: string;\n /** Resource attributes as comma-separated key=value pairs */\n resourceAttributes?: string;\n /** Enable async resource detection for process/host info (default: false) */\n detectResources?: boolean;\n /**\n * Use selective instrumentation instead of full auto-instrumentation\n * **Default: true** (performance-first)\n *\n * When true, auto-instrumentation is disabled. You can manually add\n * specific instrumentations via the `instrumentations` field.\n * This reduces overhead from ~81% to near-zero based on Platformatic benchmarks.\n *\n * Set to false to enable full auto-instrumentation (not recommended for production).\n *\n * @see https://blogger.platformatic.dev/the-hidden-cost-of-context\n */\n selectiveInstrumentation?: boolean;\n\n /**\n * Custom instrumentations to use (only when selectiveInstrumentation is true)\n * @example\n * ```typescript\n * import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'\n *\n * initInstrumentation({\n * serviceName: 'api',\n * selectiveInstrumentation: true,\n * instrumentations: [new HttpInstrumentation()]\n * })\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n instrumentations?: any[];\n}\n\n/**\n * Initialize OpenTelemetry instrumentation with OTLP exporters\n *\n * This sets up:\n * - Traces (OTLP HTTP)\n * - Metrics (OTLP HTTP)\n * - Logs (OTLP HTTP)\n * - Auto-instrumentation for common Node.js libraries\n *\n * @example\n * // Call this at the very start of your application\n * import { initInstrumentation } from '@your-org/otel-decorators'\n *\n * initInstrumentation({\n * serviceName: 'my-service' }\n * serviceVersion: '1.0.0',\n * deploymentEnvironment: 'production',\n * otlpEndpoint: 'http://localhost:4318'\n * })\n *\n * // Or with async resource detection (top-level await required)\n * await initInstrumentation({\n * serviceName: 'my-service' }\n * detectResources: true\n * })\n */\n// Enables graceful shutdown and prevents SDK leaks on hot-reload\nlet currentSDK: NodeSDK | null = null;\nlet shutdownHandlerRegistered = false;\n\n/**\n * Shutdown the OpenTelemetry SDK gracefully\n * Call this before process exit or during hot-reloads\n */\nexport async function shutdownInstrumentation(sdk?: NodeSDK): Promise<void> {\n const sdkToShutdown = sdk || currentSDK;\n if (!sdkToShutdown) {\n getLogger().warn({}, 'No SDK to shutdown');\n return;\n }\n\n try {\n await sdkToShutdown.shutdown();\n getLogger().info({}, 'OpenTelemetry terminated successfully');\n if (sdkToShutdown === currentSDK) {\n currentSDK = null;\n }\n } catch (error) {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n 'Error terminating OpenTelemetry',\n );\n throw error;\n }\n}\n\nexport async function initInstrumentation(\n config: InstrumentationConfig,\n): Promise<NodeSDK> {\n // Prevents resource leaks on hot-reload or multiple init calls\n if (currentSDK) {\n getLogger().info(\n {},\n 'Shutting down existing OpenTelemetry SDK before reinitializing...',\n );\n await shutdownInstrumentation(currentSDK);\n }\n\n // Parse headers and resource attributes\n const otlpHeaders = parseOtlpHeaders(config.headers);\n const customResourceAttributes = parseResourceAttributes(\n config.resourceAttributes,\n );\n\n let resource: Resource;\n\n // Dynamically load optional resource detectors\n const detectors: ResourceDetector[] = [processDetector, hostDetector];\n try {\n const awsDetectors = await import('@opentelemetry/resource-detector-aws');\n detectors.push(\n awsDetectors.awsEc2Detector,\n awsDetectors.awsEcsDetector,\n awsDetectors.awsEksDetector,\n );\n } catch {\n // ignore\n }\n try {\n const gcpDetectors = await import('@opentelemetry/resource-detector-gcp');\n detectors.push(gcpDetectors.gcpDetector);\n } catch {\n // ignore\n }\n try {\n const containerDetectors =\n await import('@opentelemetry/resource-detector-container');\n detectors.push(containerDetectors.containerDetector);\n } catch {\n // ignore\n }\n\n if (config.detectResources) {\n const detectedResource = await detectResources({\n detectors,\n });\n\n resource = detectedResource.merge(\n resourceFromAttributes({\n [ATTR_SERVICE_NAME]: config.serviceName,\n [ATTR_SERVICE_VERSION]: config.serviceVersion || '1.0.0',\n 'deployment.environment': config.deploymentEnvironment || 'development',\n ...customResourceAttributes, // Merge custom resource attributes\n }),\n );\n } else {\n resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: config.serviceName,\n [ATTR_SERVICE_VERSION]: config.serviceVersion || '1.0.0',\n 'deployment.environment': config.deploymentEnvironment || 'development',\n ...customResourceAttributes, // Merge custom resource attributes\n });\n }\n\n // Default to selective (near-zero overhead) vs full auto (~81% overhead)\n // Lazy-load to avoid importing ~40+ packages at module evaluation time\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let instrumentations: any[] = config.instrumentations || [];\n if (config.selectiveInstrumentation === false) {\n const mod = requireModule<{\n getNodeAutoInstrumentations: () => unknown[];\n }>('@opentelemetry/auto-instrumentations-node');\n instrumentations = [mod.getNodeAutoInstrumentations()];\n }\n\n const traceExporter = new OTLPTraceExporter({\n url: `${config.otlpEndpoint || 'http://localhost:4318'}/v1/traces`,\n headers: otlpHeaders,\n });\n\n // Enables tail sampling via autotel.sampling.tail.keep attribute\n const spanProcessor = new TailSamplingSpanProcessor(\n new BatchSpanProcessor(traceExporter),\n );\n\n const sdk = new NodeSDK({\n resource,\n spanProcessor, // Use our wrapped processor instead of traceExporter directly\n metricReader: new PeriodicExportingMetricReader({\n exporter: new OTLPMetricExporter({\n url: `${config.otlpEndpoint || 'http://localhost:4318'}/v1/metrics`,\n headers: otlpHeaders,\n }),\n }),\n logRecordProcessors: [\n new BatchLogRecordProcessor(\n new OTLPLogExporter({\n url: `${config.otlpEndpoint || 'http://localhost:4318'}/v1/logs`,\n headers: otlpHeaders,\n }),\n ),\n ],\n instrumentations,\n });\n\n try {\n await sdk.start();\n getLogger().info({}, 'OpenTelemetry instrumentation started successfully');\n } catch (error) {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n 'Failed to start OpenTelemetry SDK',\n );\n throw error;\n }\n\n // Track current SDK for shutdown handler\n currentSDK = sdk;\n\n if (!shutdownHandlerRegistered) {\n shutdownHandlerRegistered = true;\n\n const shutdownHandler = () => {\n shutdownInstrumentation()\n .then(() => {\n // eslint-disable-next-line unicorn/no-process-exit\n process.exit(0);\n })\n .catch((error) => {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n 'Shutdown error',\n );\n // eslint-disable-next-line unicorn/no-process-exit\n process.exit(1);\n });\n };\n\n process.on('SIGTERM', shutdownHandler);\n process.on('SIGINT', shutdownHandler);\n }\n\n return sdk;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/instrumentation.ts"],"names":[],"mappings":"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","file":"instrumentation.js","sourcesContent":["import { NodeSDK } from '@opentelemetry/sdk-node';\nimport { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';\nimport { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-http';\nimport { BatchLogRecordProcessor } from '@opentelemetry/sdk-logs';\nimport { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';\nimport { TailSamplingSpanProcessor } from './tail-sampling-processor';\nimport { getLogger } from './init';\nimport {\n resourceFromAttributes,\n detectResources,\n processDetector,\n hostDetector,\n type Resource,\n type ResourceDetector,\n} from '@opentelemetry/resources';\nimport {\n ATTR_SERVICE_NAME,\n ATTR_SERVICE_VERSION,\n} from '@opentelemetry/semantic-conventions/incubating';\nimport { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-http';\nimport { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';\nimport { requireModule } from './node-require';\n\n/**\n * Parse OTLP headers string into object format\n * @param headersString - Headers as \"key1=value1,key2=value2\" or \"Authorization=Basic ...\"\n * @returns Headers object for OTLP exporters\n */\nfunction parseOtlpHeaders(headersString?: string): Record<string, string> {\n if (!headersString) return {};\n\n const headers: Record<string, string> = {};\n const pairs = headersString.split(',');\n\n for (const pair of pairs) {\n const [key, ...valueParts] = pair.split('=');\n if (key && valueParts.length > 0) {\n headers[key.trim()] = valueParts.join('=').trim();\n }\n }\n\n return headers;\n}\n\n/**\n * Parse resource attributes string into object format\n * @param attributesString - Attributes as \"key1=value1,key2=value2\"\n * @returns Resource attributes object\n */\nfunction parseResourceAttributes(\n attributesString?: string,\n): Record<string, string> {\n if (!attributesString) return {};\n\n const attributes: Record<string, string> = {};\n const pairs = attributesString.split(',');\n\n for (const pair of pairs) {\n const [key, ...valueParts] = pair.split('=');\n if (key && valueParts.length > 0) {\n attributes[key.trim()] = valueParts.join('=').trim();\n }\n }\n\n return attributes;\n}\n\nexport interface InstrumentationConfig {\n serviceName: string;\n serviceVersion?: string;\n deploymentEnvironment?: string;\n otlpEndpoint?: string;\n /** Headers for authentication (e.g., Grafana Cloud, Honeycomb) */\n headers?: string;\n /** Resource attributes as comma-separated key=value pairs */\n resourceAttributes?: string;\n /** Enable async resource detection for process/host info (default: false) */\n detectResources?: boolean;\n /**\n * Use selective instrumentation instead of full auto-instrumentation\n * **Default: true** (performance-first)\n *\n * When true, auto-instrumentation is disabled. You can manually add\n * specific instrumentations via the `instrumentations` field.\n * This reduces overhead from ~81% to near-zero based on Platformatic benchmarks.\n *\n * Set to false to enable full auto-instrumentation (not recommended for production).\n *\n * @see https://blogger.platformatic.dev/the-hidden-cost-of-context\n */\n selectiveInstrumentation?: boolean;\n\n /**\n * Custom instrumentations to use (only when selectiveInstrumentation is true)\n * @example\n * ```typescript\n * import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'\n *\n * initInstrumentation({\n * serviceName: 'api',\n * selectiveInstrumentation: true,\n * instrumentations: [new HttpInstrumentation()]\n * })\n * ```\n */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n instrumentations?: any[];\n}\n\n/**\n * Initialize OpenTelemetry instrumentation with OTLP exporters\n *\n * This sets up:\n * - Traces (OTLP HTTP)\n * - Metrics (OTLP HTTP)\n * - Logs (OTLP HTTP)\n * - Auto-instrumentation for common Node.js libraries\n *\n * @example\n * // Call this at the very start of your application\n * import { initInstrumentation } from '@your-org/otel-decorators'\n *\n * initInstrumentation({\n * serviceName: 'my-service' }\n * serviceVersion: '1.0.0',\n * deploymentEnvironment: 'production',\n * otlpEndpoint: 'http://localhost:4318'\n * })\n *\n * // Or with async resource detection (top-level await required)\n * await initInstrumentation({\n * serviceName: 'my-service' }\n * detectResources: true\n * })\n */\n// Enables graceful shutdown and prevents SDK leaks on hot-reload\nlet currentSDK: NodeSDK | null = null;\nlet shutdownHandlerRegistered = false;\n\n/**\n * Shutdown the OpenTelemetry SDK gracefully\n * Call this before process exit or during hot-reloads\n */\nexport async function shutdownInstrumentation(sdk?: NodeSDK): Promise<void> {\n const sdkToShutdown = sdk || currentSDK;\n if (!sdkToShutdown) {\n getLogger().warn({}, 'No SDK to shutdown');\n return;\n }\n\n try {\n await sdkToShutdown.shutdown();\n getLogger().info({}, 'OpenTelemetry terminated successfully');\n if (sdkToShutdown === currentSDK) {\n currentSDK = null;\n }\n } catch (error) {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n 'Error terminating OpenTelemetry',\n );\n throw error;\n }\n}\n\nexport async function initInstrumentation(\n config: InstrumentationConfig,\n): Promise<NodeSDK> {\n // Prevents resource leaks on hot-reload or multiple init calls\n if (currentSDK) {\n getLogger().info(\n {},\n 'Shutting down existing OpenTelemetry SDK before reinitializing...',\n );\n await shutdownInstrumentation(currentSDK);\n }\n\n // Parse headers and resource attributes\n const otlpHeaders = parseOtlpHeaders(config.headers);\n const customResourceAttributes = parseResourceAttributes(\n config.resourceAttributes,\n );\n\n let resource: Resource;\n\n // Dynamically load optional resource detectors\n const detectors: ResourceDetector[] = [processDetector, hostDetector];\n try {\n const awsDetectors = await import('@opentelemetry/resource-detector-aws');\n detectors.push(\n awsDetectors.awsEc2Detector,\n awsDetectors.awsEcsDetector,\n awsDetectors.awsEksDetector,\n );\n } catch {\n // ignore\n }\n try {\n const gcpDetectors = await import('@opentelemetry/resource-detector-gcp');\n detectors.push(gcpDetectors.gcpDetector);\n } catch {\n // ignore\n }\n try {\n const containerDetectors =\n await import('@opentelemetry/resource-detector-container');\n detectors.push(containerDetectors.containerDetector);\n } catch {\n // ignore\n }\n\n if (config.detectResources) {\n const detectedResource = await detectResources({\n detectors,\n });\n\n resource = detectedResource.merge(\n resourceFromAttributes({\n [ATTR_SERVICE_NAME]: config.serviceName,\n [ATTR_SERVICE_VERSION]: config.serviceVersion || '1.0.0',\n 'deployment.environment': config.deploymentEnvironment || 'development',\n ...customResourceAttributes, // Merge custom resource attributes\n }),\n );\n } else {\n resource = resourceFromAttributes({\n [ATTR_SERVICE_NAME]: config.serviceName,\n [ATTR_SERVICE_VERSION]: config.serviceVersion || '1.0.0',\n 'deployment.environment': config.deploymentEnvironment || 'development',\n ...customResourceAttributes, // Merge custom resource attributes\n });\n }\n\n // Default to selective (near-zero overhead) vs full auto (~81% overhead)\n // Lazy-load to avoid importing ~40+ packages at module evaluation time\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let instrumentations: any[] = config.instrumentations || [];\n if (config.selectiveInstrumentation === false) {\n const mod = requireModule<{\n getNodeAutoInstrumentations: () => unknown[];\n }>('@opentelemetry/auto-instrumentations-node');\n instrumentations = [mod.getNodeAutoInstrumentations()];\n }\n\n const traceExporter = new OTLPTraceExporter({\n url: `${config.otlpEndpoint || 'http://localhost:4318'}/v1/traces`,\n headers: otlpHeaders,\n });\n\n // Enables tail sampling via autotel.sampling.tail.keep attribute\n const spanProcessor = new TailSamplingSpanProcessor(\n new BatchSpanProcessor(traceExporter),\n );\n\n const sdk = new NodeSDK({\n resource,\n spanProcessor, // Use our wrapped processor instead of traceExporter directly\n metricReader: new PeriodicExportingMetricReader({\n exporter: new OTLPMetricExporter({\n url: `${config.otlpEndpoint || 'http://localhost:4318'}/v1/metrics`,\n headers: otlpHeaders,\n }),\n }),\n logRecordProcessors: [\n new BatchLogRecordProcessor(\n new OTLPLogExporter({\n url: `${config.otlpEndpoint || 'http://localhost:4318'}/v1/logs`,\n headers: otlpHeaders,\n }),\n ),\n ],\n instrumentations,\n });\n\n try {\n await sdk.start();\n getLogger().info({}, 'OpenTelemetry instrumentation started successfully');\n } catch (error) {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n 'Failed to start OpenTelemetry SDK',\n );\n throw error;\n }\n\n // Track current SDK for shutdown handler\n currentSDK = sdk;\n\n if (!shutdownHandlerRegistered) {\n shutdownHandlerRegistered = true;\n\n const shutdownHandler = () => {\n shutdownInstrumentation()\n .then(() => {\n // eslint-disable-next-line unicorn/no-process-exit\n process.exit(0);\n })\n .catch((error) => {\n getLogger().error(\n {\n err: error instanceof Error ? error : undefined,\n },\n 'Shutdown error',\n );\n // eslint-disable-next-line unicorn/no-process-exit\n process.exit(1);\n });\n };\n\n process.on('SIGTERM', shutdownHandler);\n process.on('SIGINT', shutdownHandler);\n }\n\n return sdk;\n}\n"]}
|
package/dist/logger.cjs
CHANGED
package/dist/logger.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { LOG_LEVEL, LoggedOperation, autotelLogger, createBuiltinLogger, getActiveLogLevel, getTraceContext, runWithLogLevel } from './chunk-55ER2KD5.js';
|
|
2
2
|
import './chunk-J5QENANM.js';
|
|
3
3
|
import './chunk-HA2WBOGQ.js';
|
|
4
|
-
import './chunk-DGUM43GV.js';
|
|
5
4
|
//# sourceMappingURL=logger.js.map
|
|
6
5
|
//# sourceMappingURL=logger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/messaging-testing.ts"],"names":[],"mappings":"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","file":"messaging-testing.cjs","sourcesContent":["/**\n * Testing utilities for messaging instrumentation\n *\n * Provides mock producers, consumers, and assertion helpers\n * for testing event-driven code with Autotel's messaging module.\n *\n * @example Basic test setup\n * ```typescript\n * import { createMessagingTestHarness } from 'autotel/messaging-testing';\n *\n * describe('Order processing', () => {\n * const harness = createMessagingTestHarness();\n *\n * beforeEach(() => harness.reset());\n * afterAll(() => harness.shutdown());\n *\n * it('should process order and publish event', async () => {\n * await processOrder({ id: 'order-123' });\n *\n * harness.assertProducerCalled('orders', {\n * messageCount: 1,\n * hasTraceHeaders: true,\n * });\n * });\n * });\n * ```\n *\n * @module\n */\n\nimport type { Link, SpanContext } from '@opentelemetry/api';\nimport type {\n RebalanceEvent,\n PartitionAssignment,\n OutOfOrderInfo,\n} from './messaging';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Recorded producer call\n */\nexport interface RecordedProducerCall {\n /** Destination (topic/queue) */\n destination: string;\n\n /** System (kafka, sqs, etc.) */\n system: string;\n\n /** Message payload */\n payload: unknown;\n\n /** Headers injected */\n headers: Record<string, string>;\n\n /** Timestamp of call */\n timestamp: number;\n\n /** Trace ID from headers */\n traceId?: string;\n\n /** Span ID from headers */\n spanId?: string;\n}\n\n/**\n * Recorded consumer call\n */\nexport interface RecordedConsumerCall {\n /** Destination (topic/queue) */\n destination: string;\n\n /** System (kafka, sqs, etc.) */\n system: string;\n\n /** Consumer group */\n consumerGroup?: string;\n\n /** Message payload */\n payload: unknown;\n\n /** Headers extracted */\n headers?: Record<string, string>;\n\n /** Timestamp of call */\n timestamp: number;\n\n /** Producer links extracted */\n producerLinks: Link[];\n\n /** Whether message was duplicate */\n isDuplicate: boolean;\n\n /** Out of order info if detected */\n outOfOrderInfo: OutOfOrderInfo | null;\n\n /** DLQ reason if routed to DLQ */\n dlqReason?: string;\n\n /** Retry attempt number */\n retryAttempt?: number;\n}\n\n/**\n * Recorded rebalance event\n */\nexport interface RecordedRebalanceEvent extends RebalanceEvent {\n /** Destination (topic) */\n destination: string;\n\n /** Consumer group */\n consumerGroup: string;\n}\n\n/**\n * Mock message for testing\n */\nexport interface MockMessage<T = unknown> {\n /** Message payload */\n payload: T;\n\n /** Headers */\n headers?: Record<string, string>;\n\n /** Offset/sequence number */\n offset?: number;\n\n /** Partition */\n partition?: number;\n\n /** Key */\n key?: string;\n\n /** Message ID */\n messageId?: string;\n\n /** Timestamp */\n timestamp?: number;\n}\n\n/**\n * Producer assertion options\n */\nexport interface ProducerAssertionOptions {\n /** Expected number of messages */\n messageCount?: number;\n\n /** Whether trace headers should be present */\n hasTraceHeaders?: boolean;\n\n /** Expected destination */\n destination?: string;\n\n /** Custom matcher for payload */\n payloadMatcher?: (payload: unknown) => boolean;\n\n /** Expected trace ID */\n traceId?: string;\n}\n\n/**\n * Consumer assertion options\n */\nexport interface ConsumerAssertionOptions {\n /** Expected number of messages processed */\n messageCount?: number;\n\n /** Whether producer links should be present */\n hasProducerLinks?: boolean;\n\n /** Expected destination */\n destination?: string;\n\n /** Expected consumer group */\n consumerGroup?: string;\n\n /** Whether any messages were duplicates */\n hasDuplicates?: boolean;\n\n /** Whether any messages were out of order */\n hasOutOfOrder?: boolean;\n\n /** Whether any messages went to DLQ */\n hasDLQ?: boolean;\n}\n\n/**\n * Messaging test harness\n */\nexport interface MessagingTestHarness {\n /** All recorded producer calls */\n producerCalls: RecordedProducerCall[];\n\n /** All recorded consumer calls */\n consumerCalls: RecordedConsumerCall[];\n\n /** All recorded rebalance events */\n rebalanceEvents: RecordedRebalanceEvent[];\n\n /**\n * Record a producer call\n */\n recordProducerCall(call: Omit<RecordedProducerCall, 'timestamp'>): void;\n\n /**\n * Record a consumer call\n */\n recordConsumerCall(call: Omit<RecordedConsumerCall, 'timestamp'>): void;\n\n /**\n * Record a rebalance event\n */\n recordRebalanceEvent(event: RecordedRebalanceEvent): void;\n\n /**\n * Create a mock message with trace headers\n */\n createMockMessage<T>(\n payload: T,\n options?: Partial<MockMessage<T>>,\n ): MockMessage<T>;\n\n /**\n * Create mock trace headers\n */\n createMockTraceHeaders(\n traceId?: string,\n spanId?: string,\n ): Record<string, string>;\n\n /**\n * Assert producer was called with expected options\n */\n assertProducerCalled(\n destination: string,\n options?: ProducerAssertionOptions,\n ): void;\n\n /**\n * Assert producer was not called\n */\n assertProducerNotCalled(destination?: string): void;\n\n /**\n * Assert consumer processed messages with expected options\n */\n assertConsumerProcessed(\n destination: string,\n options?: ConsumerAssertionOptions,\n ): void;\n\n /**\n * Assert consumer was not called\n */\n assertConsumerNotCalled(destination?: string): void;\n\n /**\n * Assert rebalance occurred\n */\n assertRebalanceOccurred(\n destination: string,\n type: RebalanceEvent['type'],\n partitionCount?: number,\n ): void;\n\n /**\n * Get producer calls for destination\n */\n getProducerCalls(destination?: string): RecordedProducerCall[];\n\n /**\n * Get consumer calls for destination\n */\n getConsumerCalls(destination?: string): RecordedConsumerCall[];\n\n /**\n * Get the last producer call\n */\n getLastProducerCall(destination?: string): RecordedProducerCall | undefined;\n\n /**\n * Get the last consumer call\n */\n getLastConsumerCall(destination?: string): RecordedConsumerCall | undefined;\n\n /**\n * Reset all recorded calls\n */\n reset(): void;\n\n /**\n * Shutdown the harness\n */\n shutdown(): void;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Generate a random hex string\n */\nfunction randomHex(length: number): string {\n let result = '';\n const chars = '0123456789abcdef';\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n\n/**\n * Create a messaging test harness\n *\n * Provides utilities for recording and asserting on producer/consumer calls\n * during testing.\n *\n * @example\n * ```typescript\n * const harness = createMessagingTestHarness();\n *\n * // In your test setup\n * beforeEach(() => harness.reset());\n *\n * // In your tests\n * it('should publish order event', async () => {\n * await orderService.createOrder({ id: '123' });\n *\n * harness.assertProducerCalled('orders', {\n * messageCount: 1,\n * hasTraceHeaders: true,\n * });\n *\n * const lastCall = harness.getLastProducerCall('orders');\n * expect(lastCall?.payload).toMatchObject({ orderId: '123' });\n * });\n * ```\n */\nexport function createMessagingTestHarness(): MessagingTestHarness {\n const producerCalls: RecordedProducerCall[] = [];\n const consumerCalls: RecordedConsumerCall[] = [];\n const rebalanceEvents: RecordedRebalanceEvent[] = [];\n\n return {\n producerCalls,\n consumerCalls,\n rebalanceEvents,\n\n recordProducerCall(call) {\n producerCalls.push({\n ...call,\n timestamp: Date.now(),\n });\n },\n\n recordConsumerCall(call) {\n consumerCalls.push({\n ...call,\n timestamp: Date.now(),\n });\n },\n\n recordRebalanceEvent(event) {\n rebalanceEvents.push(event);\n },\n\n createMockMessage<T>(\n payload: T,\n options: Partial<MockMessage<T>> = {},\n ): MockMessage<T> {\n return {\n payload,\n headers: options.headers ?? this.createMockTraceHeaders(),\n offset: options.offset ?? Math.floor(Math.random() * 10_000),\n partition: options.partition ?? 0,\n key: options.key,\n messageId: options.messageId ?? `msg-${randomHex(8)}`,\n timestamp: options.timestamp ?? Date.now(),\n };\n },\n\n createMockTraceHeaders(\n traceId?: string,\n spanId?: string,\n ): Record<string, string> {\n const tid = traceId ?? randomHex(32);\n const sid = spanId ?? randomHex(16);\n return {\n traceparent: `00-${tid}-${sid}-01`,\n };\n },\n\n assertProducerCalled(\n destination: string,\n options: ProducerAssertionOptions = {},\n ) {\n const calls = producerCalls.filter((c) => c.destination === destination);\n\n if (calls.length === 0) {\n throw new Error(\n `Expected producer to be called for destination '${destination}', but it was not called`,\n );\n }\n\n if (\n options.messageCount !== undefined &&\n calls.length !== options.messageCount\n ) {\n throw new Error(\n `Expected ${options.messageCount} producer calls for '${destination}', got ${calls.length}`,\n );\n }\n\n if (options.hasTraceHeaders) {\n const withoutHeaders = calls.filter((c) => !c.headers?.traceparent);\n if (withoutHeaders.length > 0) {\n throw new Error(\n `Expected all producer calls for '${destination}' to have trace headers, but ${withoutHeaders.length} did not`,\n );\n }\n }\n\n if (options.traceId) {\n const matchingTraceId = calls.filter(\n (c) => c.traceId === options.traceId,\n );\n if (matchingTraceId.length === 0) {\n throw new Error(\n `Expected producer call for '${destination}' with traceId '${options.traceId}', but none found`,\n );\n }\n }\n\n if (options.payloadMatcher) {\n const matching = calls.filter((c) =>\n options.payloadMatcher!(c.payload),\n );\n if (matching.length === 0) {\n throw new Error(\n `Expected producer call for '${destination}' to match payload matcher, but none did`,\n );\n }\n }\n },\n\n assertProducerNotCalled(destination?: string) {\n if (destination) {\n const calls = producerCalls.filter(\n (c) => c.destination === destination,\n );\n if (calls.length > 0) {\n throw new Error(\n `Expected producer not to be called for '${destination}', but it was called ${calls.length} times`,\n );\n }\n } else {\n if (producerCalls.length > 0) {\n throw new Error(\n `Expected no producer calls, but ${producerCalls.length} calls were made`,\n );\n }\n }\n },\n\n assertConsumerProcessed(\n destination: string,\n options: ConsumerAssertionOptions = {},\n ) {\n const calls = consumerCalls.filter((c) => c.destination === destination);\n\n if (calls.length === 0) {\n throw new Error(\n `Expected consumer to process messages for destination '${destination}', but none were processed`,\n );\n }\n\n if (\n options.messageCount !== undefined &&\n calls.length !== options.messageCount\n ) {\n throw new Error(\n `Expected ${options.messageCount} consumer calls for '${destination}', got ${calls.length}`,\n );\n }\n\n if (options.consumerGroup) {\n const wrongGroup = calls.filter(\n (c) => c.consumerGroup !== options.consumerGroup,\n );\n if (wrongGroup.length > 0) {\n throw new Error(\n `Expected consumer group '${options.consumerGroup}' for '${destination}', but found different groups`,\n );\n }\n }\n\n if (options.hasProducerLinks) {\n const withoutLinks = calls.filter((c) => c.producerLinks.length === 0);\n if (withoutLinks.length > 0) {\n throw new Error(\n `Expected all consumer calls for '${destination}' to have producer links, but ${withoutLinks.length} did not`,\n );\n }\n }\n\n if (options.hasDuplicates !== undefined) {\n const duplicates = calls.filter((c) => c.isDuplicate);\n if (options.hasDuplicates && duplicates.length === 0) {\n throw new Error(\n `Expected duplicate messages for '${destination}', but none were detected`,\n );\n }\n if (!options.hasDuplicates && duplicates.length > 0) {\n throw new Error(\n `Expected no duplicate messages for '${destination}', but ${duplicates.length} were detected`,\n );\n }\n }\n\n if (options.hasOutOfOrder !== undefined) {\n const outOfOrder = calls.filter((c) => c.outOfOrderInfo !== null);\n if (options.hasOutOfOrder && outOfOrder.length === 0) {\n throw new Error(\n `Expected out-of-order messages for '${destination}', but none were detected`,\n );\n }\n if (!options.hasOutOfOrder && outOfOrder.length > 0) {\n throw new Error(\n `Expected no out-of-order messages for '${destination}', but ${outOfOrder.length} were detected`,\n );\n }\n }\n\n if (options.hasDLQ !== undefined) {\n const dlqCalls = calls.filter((c) => c.dlqReason !== undefined);\n if (options.hasDLQ && dlqCalls.length === 0) {\n throw new Error(\n `Expected DLQ routing for '${destination}', but none occurred`,\n );\n }\n if (!options.hasDLQ && dlqCalls.length > 0) {\n throw new Error(\n `Expected no DLQ routing for '${destination}', but ${dlqCalls.length} occurred`,\n );\n }\n }\n },\n\n assertConsumerNotCalled(destination?: string) {\n if (destination) {\n const calls = consumerCalls.filter(\n (c) => c.destination === destination,\n );\n if (calls.length > 0) {\n throw new Error(\n `Expected consumer not to be called for '${destination}', but it processed ${calls.length} messages`,\n );\n }\n } else {\n if (consumerCalls.length > 0) {\n throw new Error(\n `Expected no consumer calls, but ${consumerCalls.length} messages were processed`,\n );\n }\n }\n },\n\n assertRebalanceOccurred(\n destination: string,\n type: RebalanceEvent['type'],\n partitionCount?: number,\n ) {\n const events = rebalanceEvents.filter(\n (e) => e.destination === destination && e.type === type,\n );\n\n if (events.length === 0) {\n throw new Error(\n `Expected rebalance '${type}' for '${destination}', but none occurred`,\n );\n }\n\n if (partitionCount !== undefined) {\n const matching = events.filter(\n (e) => e.partitions.length === partitionCount,\n );\n if (matching.length === 0) {\n throw new Error(\n `Expected rebalance '${type}' for '${destination}' with ${partitionCount} partitions, but none matched`,\n );\n }\n }\n },\n\n getProducerCalls(destination?: string) {\n if (destination) {\n return producerCalls.filter((c) => c.destination === destination);\n }\n return [...producerCalls];\n },\n\n getConsumerCalls(destination?: string) {\n if (destination) {\n return consumerCalls.filter((c) => c.destination === destination);\n }\n return [...consumerCalls];\n },\n\n getLastProducerCall(destination?: string) {\n const calls = this.getProducerCalls(destination);\n return calls.at(-1);\n },\n\n getLastConsumerCall(destination?: string) {\n const calls = this.getConsumerCalls(destination);\n return calls.at(-1);\n },\n\n reset() {\n producerCalls.length = 0;\n consumerCalls.length = 0;\n rebalanceEvents.length = 0;\n },\n\n shutdown() {\n this.reset();\n },\n };\n}\n\n// ============================================================================\n// Mock Broker\n// ============================================================================\n\n/**\n * Mock message broker for testing\n */\nexport interface MockMessageBroker {\n /** Topics/queues in the broker */\n topics: Map<string, MockMessage[]>;\n\n /**\n * Publish a message to a topic\n */\n publish(topic: string, message: MockMessage): void;\n\n /**\n * Consume messages from a topic\n */\n consume(topic: string, count?: number): MockMessage[];\n\n /**\n * Peek at messages without consuming\n */\n peek(topic: string, count?: number): MockMessage[];\n\n /**\n * Get message count for topic\n */\n getMessageCount(topic: string): number;\n\n /**\n * Clear all messages\n */\n clear(topic?: string): void;\n\n /**\n * Create a topic\n */\n createTopic(topic: string): void;\n\n /**\n * Delete a topic\n */\n deleteTopic(topic: string): void;\n\n /**\n * List all topics\n */\n listTopics(): string[];\n}\n\n/**\n * Create a mock message broker for testing\n *\n * Simulates a message broker (Kafka, SQS, RabbitMQ, etc.) for unit testing.\n *\n * @example\n * ```typescript\n * const broker = createMockMessageBroker();\n *\n * // Producer publishes\n * broker.publish('orders', { payload: { orderId: '123' }, headers: {} });\n *\n * // Consumer receives\n * const messages = broker.consume('orders');\n * expect(messages).toHaveLength(1);\n * expect(messages[0].payload).toEqual({ orderId: '123' });\n * ```\n */\nexport function createMockMessageBroker(): MockMessageBroker {\n const topics = new Map<string, MockMessage[]>();\n\n return {\n topics,\n\n publish(topic: string, message: MockMessage) {\n if (!topics.has(topic)) {\n topics.set(topic, []);\n }\n topics.get(topic)!.push({\n ...message,\n timestamp: message.timestamp ?? Date.now(),\n offset: message.offset ?? topics.get(topic)!.length,\n });\n },\n\n consume(topic: string, count?: number) {\n const messages = topics.get(topic) ?? [];\n if (count === undefined) {\n const all = [...messages];\n messages.length = 0;\n return all;\n }\n return messages.splice(0, count);\n },\n\n peek(topic: string, count?: number) {\n const messages = topics.get(topic) ?? [];\n if (count === undefined) {\n return [...messages];\n }\n return messages.slice(0, count);\n },\n\n getMessageCount(topic: string) {\n return topics.get(topic)?.length ?? 0;\n },\n\n clear(topic?: string) {\n if (topic) {\n topics.set(topic, []);\n } else {\n topics.clear();\n }\n },\n\n createTopic(topic: string) {\n if (!topics.has(topic)) {\n topics.set(topic, []);\n }\n },\n\n deleteTopic(topic: string) {\n topics.delete(topic);\n },\n\n listTopics() {\n return [...topics.keys()];\n },\n };\n}\n\n// ============================================================================\n// Context Propagation Helpers\n// ============================================================================\n\n/**\n * Extract trace ID from traceparent header\n */\nexport function extractTraceIdFromHeader(traceparent: string): string | null {\n const parts = traceparent.split('-');\n if (parts.length >= 3 && parts[1] !== undefined) {\n return parts[1];\n }\n return null;\n}\n\n/**\n * Extract span ID from traceparent header\n */\nexport function extractSpanIdFromHeader(traceparent: string): string | null {\n const parts = traceparent.split('-');\n if (parts.length >= 4 && parts[2] !== undefined) {\n return parts[2];\n }\n return null;\n}\n\n/**\n * Create a mock span context\n */\nexport function createMockSpanContext(\n traceId?: string,\n spanId?: string,\n): SpanContext {\n return {\n traceId: traceId ?? randomHex(32),\n spanId: spanId ?? randomHex(16),\n traceFlags: 1,\n isRemote: true,\n };\n}\n\n/**\n * Create a mock link to a producer span\n */\nexport function createMockProducerLink(\n traceId?: string,\n spanId?: string,\n): Link {\n return {\n context: createMockSpanContext(traceId, spanId),\n attributes: {\n 'messaging.link.source': 'producer',\n },\n };\n}\n\n// ============================================================================\n// Scenario Builders\n// ============================================================================\n\n/**\n * Create a batch of mock messages\n */\nexport function createMockMessageBatch<T>(\n payloads: T[],\n options: {\n startOffset?: number;\n partition?: number;\n addTraceHeaders?: boolean;\n traceId?: string;\n } = {},\n): MockMessage<T>[] {\n const startOffset = options.startOffset ?? 0;\n const addTraceHeaders = options.addTraceHeaders ?? true;\n const traceId = options.traceId ?? randomHex(32);\n\n return payloads.map((payload, index) => ({\n payload,\n headers: addTraceHeaders\n ? { traceparent: `00-${traceId}-${randomHex(16)}-01` }\n : undefined,\n offset: startOffset + index,\n partition: options.partition ?? 0,\n messageId: `msg-${randomHex(8)}`,\n timestamp: Date.now() + index,\n }));\n}\n\n/**\n * Create a rebalance scenario\n */\nexport function createRebalanceScenario(\n topic: string,\n consumerGroup: string,\n partitions: number[],\n): {\n assignEvent: RecordedRebalanceEvent;\n revokeEvent: RecordedRebalanceEvent;\n} {\n const assignments: PartitionAssignment[] = partitions.map((p) => ({\n topic,\n partition: p,\n offset: 0,\n }));\n\n return {\n assignEvent: {\n type: 'assigned',\n partitions: assignments,\n timestamp: Date.now(),\n generation: 1,\n destination: topic,\n consumerGroup,\n },\n revokeEvent: {\n type: 'revoked',\n partitions: assignments,\n timestamp: Date.now() + 1000,\n generation: 2,\n destination: topic,\n consumerGroup,\n },\n };\n}\n\n/**\n * Create an out-of-order scenario\n */\nexport function createOutOfOrderScenario<T>(\n payloads: T[],\n outOfOrderIndices: number[],\n): MockMessage<T>[] {\n const messages = createMockMessageBatch(payloads, { addTraceHeaders: true });\n\n // Shuffle specified indices to create out-of-order scenario\n const shuffled = [...messages];\n for (const index of outOfOrderIndices) {\n if (index > 0 && index < shuffled.length) {\n // Swap with previous to create out-of-order\n const prev = shuffled[index - 1]!;\n const curr = shuffled[index]!;\n shuffled[index - 1] = curr;\n shuffled[index] = prev;\n }\n }\n\n return shuffled;\n}\n\n/**\n * Create a duplicate message scenario\n */\nexport function createDuplicateScenario<T>(\n payloads: T[],\n duplicateIndices: number[],\n): MockMessage<T>[] {\n const messages = createMockMessageBatch(payloads, { addTraceHeaders: true });\n const result = [...messages];\n\n for (const index of duplicateIndices) {\n const originalMessage = messages[index];\n if (index >= 0 && index < messages.length && originalMessage) {\n // Insert duplicate after the original\n result.splice(index + 1, 0, { ...originalMessage });\n }\n }\n\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/messaging-testing.ts"],"names":[],"mappings":"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","file":"messaging-testing.cjs","sourcesContent":["/**\n * Testing utilities for messaging instrumentation\n *\n * Provides mock producers, consumers, and assertion helpers\n * for testing event-driven code with Autotel's messaging module.\n *\n * @example Basic test setup\n * ```typescript\n * import { createMessagingTestHarness } from 'autotel/messaging-testing';\n *\n * describe('Order processing', () => {\n * const harness = createMessagingTestHarness();\n *\n * beforeEach(() => harness.reset());\n * afterAll(() => harness.shutdown());\n *\n * it('should process order and publish event', async () => {\n * await processOrder({ id: 'order-123' });\n *\n * harness.assertProducerCalled('orders', {\n * messageCount: 1,\n * hasTraceHeaders: true,\n * });\n * });\n * });\n * ```\n *\n * @module\n */\n\nimport type { Link, SpanContext } from '@opentelemetry/api';\nimport type {\n RebalanceEvent,\n PartitionAssignment,\n OutOfOrderInfo,\n} from './messaging';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Recorded producer call\n */\nexport interface RecordedProducerCall {\n /** Destination (topic/queue) */\n destination: string;\n\n /** System (kafka, sqs, etc.) */\n system: string;\n\n /** Message payload */\n payload: unknown;\n\n /** Headers injected */\n headers: Record<string, string>;\n\n /** Timestamp of call */\n timestamp: number;\n\n /** Trace ID from headers */\n traceId?: string;\n\n /** Span ID from headers */\n spanId?: string;\n}\n\n/**\n * Recorded consumer call\n */\nexport interface RecordedConsumerCall {\n /** Destination (topic/queue) */\n destination: string;\n\n /** System (kafka, sqs, etc.) */\n system: string;\n\n /** Consumer group */\n consumerGroup?: string;\n\n /** Message payload */\n payload: unknown;\n\n /** Headers extracted */\n headers?: Record<string, string>;\n\n /** Timestamp of call */\n timestamp: number;\n\n /** Producer links extracted */\n producerLinks: Link[];\n\n /** Whether message was duplicate */\n isDuplicate: boolean;\n\n /** Out of order info if detected */\n outOfOrderInfo: OutOfOrderInfo | null;\n\n /** DLQ reason if routed to DLQ */\n dlqReason?: string;\n\n /** Retry attempt number */\n retryAttempt?: number;\n}\n\n/**\n * Recorded rebalance event\n */\nexport interface RecordedRebalanceEvent extends RebalanceEvent {\n /** Destination (topic) */\n destination: string;\n\n /** Consumer group */\n consumerGroup: string;\n}\n\n/**\n * Mock message for testing\n */\nexport interface MockMessage<T = unknown> {\n /** Message payload */\n payload: T;\n\n /** Headers */\n headers?: Record<string, string>;\n\n /** Offset/sequence number */\n offset?: number;\n\n /** Partition */\n partition?: number;\n\n /** Key */\n key?: string;\n\n /** Message ID */\n messageId?: string;\n\n /** Timestamp */\n timestamp?: number;\n}\n\n/**\n * Producer assertion options\n */\nexport interface ProducerAssertionOptions {\n /** Expected number of messages */\n messageCount?: number;\n\n /** Whether trace headers should be present */\n hasTraceHeaders?: boolean;\n\n /** Expected destination */\n destination?: string;\n\n /** Custom matcher for payload */\n payloadMatcher?: (payload: unknown) => boolean;\n\n /** Expected trace ID */\n traceId?: string;\n}\n\n/**\n * Consumer assertion options\n */\nexport interface ConsumerAssertionOptions {\n /** Expected number of messages processed */\n messageCount?: number;\n\n /** Whether producer links should be present */\n hasProducerLinks?: boolean;\n\n /** Expected destination */\n destination?: string;\n\n /** Expected consumer group */\n consumerGroup?: string;\n\n /** Whether any messages were duplicates */\n hasDuplicates?: boolean;\n\n /** Whether any messages were out of order */\n hasOutOfOrder?: boolean;\n\n /** Whether any messages went to DLQ */\n hasDLQ?: boolean;\n}\n\n/**\n * Messaging test harness\n */\nexport interface MessagingTestHarness {\n /** All recorded producer calls */\n producerCalls: RecordedProducerCall[];\n\n /** All recorded consumer calls */\n consumerCalls: RecordedConsumerCall[];\n\n /** All recorded rebalance events */\n rebalanceEvents: RecordedRebalanceEvent[];\n\n /**\n * Record a producer call\n */\n recordProducerCall(call: Omit<RecordedProducerCall, 'timestamp'>): void;\n\n /**\n * Record a consumer call\n */\n recordConsumerCall(call: Omit<RecordedConsumerCall, 'timestamp'>): void;\n\n /**\n * Record a rebalance event\n */\n recordRebalanceEvent(event: RecordedRebalanceEvent): void;\n\n /**\n * Create a mock message with trace headers\n */\n createMockMessage<T>(\n payload: T,\n options?: Partial<MockMessage<T>>,\n ): MockMessage<T>;\n\n /**\n * Create mock trace headers\n */\n createMockTraceHeaders(\n traceId?: string,\n spanId?: string,\n ): Record<string, string>;\n\n /**\n * Assert producer was called with expected options\n */\n assertProducerCalled(\n destination: string,\n options?: ProducerAssertionOptions,\n ): void;\n\n /**\n * Assert producer was not called\n */\n assertProducerNotCalled(destination?: string): void;\n\n /**\n * Assert consumer processed messages with expected options\n */\n assertConsumerProcessed(\n destination: string,\n options?: ConsumerAssertionOptions,\n ): void;\n\n /**\n * Assert consumer was not called\n */\n assertConsumerNotCalled(destination?: string): void;\n\n /**\n * Assert rebalance occurred\n */\n assertRebalanceOccurred(\n destination: string,\n type: RebalanceEvent['type'],\n partitionCount?: number,\n ): void;\n\n /**\n * Get producer calls for destination\n */\n getProducerCalls(destination?: string): RecordedProducerCall[];\n\n /**\n * Get consumer calls for destination\n */\n getConsumerCalls(destination?: string): RecordedConsumerCall[];\n\n /**\n * Get the last producer call\n */\n getLastProducerCall(destination?: string): RecordedProducerCall | undefined;\n\n /**\n * Get the last consumer call\n */\n getLastConsumerCall(destination?: string): RecordedConsumerCall | undefined;\n\n /**\n * Reset all recorded calls\n */\n reset(): void;\n\n /**\n * Shutdown the harness\n */\n shutdown(): void;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Generate a random hex string\n */\nfunction randomHex(length: number): string {\n let result = '';\n const chars = '0123456789abcdef';\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n\n/**\n * Create a messaging test harness\n *\n * Provides utilities for recording and asserting on producer/consumer calls\n * during testing.\n *\n * @example\n * ```typescript\n * const harness = createMessagingTestHarness();\n *\n * // In your test setup\n * beforeEach(() => harness.reset());\n *\n * // In your tests\n * it('should publish order event', async () => {\n * await orderService.createOrder({ id: '123' });\n *\n * harness.assertProducerCalled('orders', {\n * messageCount: 1,\n * hasTraceHeaders: true,\n * });\n *\n * const lastCall = harness.getLastProducerCall('orders');\n * expect(lastCall?.payload).toMatchObject({ orderId: '123' });\n * });\n * ```\n */\nexport function createMessagingTestHarness(): MessagingTestHarness {\n const producerCalls: RecordedProducerCall[] = [];\n const consumerCalls: RecordedConsumerCall[] = [];\n const rebalanceEvents: RecordedRebalanceEvent[] = [];\n\n return {\n producerCalls,\n consumerCalls,\n rebalanceEvents,\n\n recordProducerCall(call) {\n producerCalls.push({\n ...call,\n timestamp: Date.now(),\n });\n },\n\n recordConsumerCall(call) {\n consumerCalls.push({\n ...call,\n timestamp: Date.now(),\n });\n },\n\n recordRebalanceEvent(event) {\n rebalanceEvents.push(event);\n },\n\n createMockMessage<T>(\n payload: T,\n options: Partial<MockMessage<T>> = {},\n ): MockMessage<T> {\n return {\n payload,\n headers: options.headers ?? this.createMockTraceHeaders(),\n offset: options.offset ?? Math.floor(Math.random() * 10_000),\n partition: options.partition ?? 0,\n key: options.key,\n messageId: options.messageId ?? `msg-${randomHex(8)}`,\n timestamp: options.timestamp ?? Date.now(),\n };\n },\n\n createMockTraceHeaders(\n traceId?: string,\n spanId?: string,\n ): Record<string, string> {\n const tid = traceId ?? randomHex(32);\n const sid = spanId ?? randomHex(16);\n return {\n traceparent: `00-${tid}-${sid}-01`,\n };\n },\n\n assertProducerCalled(\n destination: string,\n options: ProducerAssertionOptions = {},\n ) {\n const calls = producerCalls.filter((c) => c.destination === destination);\n\n if (calls.length === 0) {\n throw new Error(\n `Expected producer to be called for destination '${destination}', but it was not called`,\n );\n }\n\n if (\n options.messageCount !== undefined &&\n calls.length !== options.messageCount\n ) {\n throw new Error(\n `Expected ${options.messageCount} producer calls for '${destination}', got ${calls.length}`,\n );\n }\n\n if (options.hasTraceHeaders) {\n const withoutHeaders = calls.filter((c) => !c.headers?.traceparent);\n if (withoutHeaders.length > 0) {\n throw new Error(\n `Expected all producer calls for '${destination}' to have trace headers, but ${withoutHeaders.length} did not`,\n );\n }\n }\n\n if (options.traceId) {\n const matchingTraceId = calls.filter(\n (c) => c.traceId === options.traceId,\n );\n if (matchingTraceId.length === 0) {\n throw new Error(\n `Expected producer call for '${destination}' with traceId '${options.traceId}', but none found`,\n );\n }\n }\n\n if (options.payloadMatcher) {\n const matching = calls.filter((c) =>\n options.payloadMatcher!(c.payload),\n );\n if (matching.length === 0) {\n throw new Error(\n `Expected producer call for '${destination}' to match payload matcher, but none did`,\n );\n }\n }\n },\n\n assertProducerNotCalled(destination?: string) {\n if (destination) {\n const calls = producerCalls.filter(\n (c) => c.destination === destination,\n );\n if (calls.length > 0) {\n throw new Error(\n `Expected producer not to be called for '${destination}', but it was called ${calls.length} times`,\n );\n }\n } else {\n if (producerCalls.length > 0) {\n throw new Error(\n `Expected no producer calls, but ${producerCalls.length} calls were made`,\n );\n }\n }\n },\n\n assertConsumerProcessed(\n destination: string,\n options: ConsumerAssertionOptions = {},\n ) {\n const calls = consumerCalls.filter((c) => c.destination === destination);\n\n if (calls.length === 0) {\n throw new Error(\n `Expected consumer to process messages for destination '${destination}', but none were processed`,\n );\n }\n\n if (\n options.messageCount !== undefined &&\n calls.length !== options.messageCount\n ) {\n throw new Error(\n `Expected ${options.messageCount} consumer calls for '${destination}', got ${calls.length}`,\n );\n }\n\n if (options.consumerGroup) {\n const wrongGroup = calls.filter(\n (c) => c.consumerGroup !== options.consumerGroup,\n );\n if (wrongGroup.length > 0) {\n throw new Error(\n `Expected consumer group '${options.consumerGroup}' for '${destination}', but found different groups`,\n );\n }\n }\n\n if (options.hasProducerLinks) {\n const withoutLinks = calls.filter((c) => c.producerLinks.length === 0);\n if (withoutLinks.length > 0) {\n throw new Error(\n `Expected all consumer calls for '${destination}' to have producer links, but ${withoutLinks.length} did not`,\n );\n }\n }\n\n if (options.hasDuplicates !== undefined) {\n const duplicates = calls.filter((c) => c.isDuplicate);\n if (options.hasDuplicates && duplicates.length === 0) {\n throw new Error(\n `Expected duplicate messages for '${destination}', but none were detected`,\n );\n }\n if (!options.hasDuplicates && duplicates.length > 0) {\n throw new Error(\n `Expected no duplicate messages for '${destination}', but ${duplicates.length} were detected`,\n );\n }\n }\n\n if (options.hasOutOfOrder !== undefined) {\n const outOfOrder = calls.filter((c) => c.outOfOrderInfo !== null);\n if (options.hasOutOfOrder && outOfOrder.length === 0) {\n throw new Error(\n `Expected out-of-order messages for '${destination}', but none were detected`,\n );\n }\n if (!options.hasOutOfOrder && outOfOrder.length > 0) {\n throw new Error(\n `Expected no out-of-order messages for '${destination}', but ${outOfOrder.length} were detected`,\n );\n }\n }\n\n if (options.hasDLQ !== undefined) {\n const dlqCalls = calls.filter((c) => c.dlqReason !== undefined);\n if (options.hasDLQ && dlqCalls.length === 0) {\n throw new Error(\n `Expected DLQ routing for '${destination}', but none occurred`,\n );\n }\n if (!options.hasDLQ && dlqCalls.length > 0) {\n throw new Error(\n `Expected no DLQ routing for '${destination}', but ${dlqCalls.length} occurred`,\n );\n }\n }\n },\n\n assertConsumerNotCalled(destination?: string) {\n if (destination) {\n const calls = consumerCalls.filter(\n (c) => c.destination === destination,\n );\n if (calls.length > 0) {\n throw new Error(\n `Expected consumer not to be called for '${destination}', but it processed ${calls.length} messages`,\n );\n }\n } else {\n if (consumerCalls.length > 0) {\n throw new Error(\n `Expected no consumer calls, but ${consumerCalls.length} messages were processed`,\n );\n }\n }\n },\n\n assertRebalanceOccurred(\n destination: string,\n type: RebalanceEvent['type'],\n partitionCount?: number,\n ) {\n const events = rebalanceEvents.filter(\n (e) => e.destination === destination && e.type === type,\n );\n\n if (events.length === 0) {\n throw new Error(\n `Expected rebalance '${type}' for '${destination}', but none occurred`,\n );\n }\n\n if (partitionCount !== undefined) {\n const matching = events.filter(\n (e) => e.partitions.length === partitionCount,\n );\n if (matching.length === 0) {\n throw new Error(\n `Expected rebalance '${type}' for '${destination}' with ${partitionCount} partitions, but none matched`,\n );\n }\n }\n },\n\n getProducerCalls(destination?: string) {\n if (destination) {\n return producerCalls.filter((c) => c.destination === destination);\n }\n return [...producerCalls];\n },\n\n getConsumerCalls(destination?: string) {\n if (destination) {\n return consumerCalls.filter((c) => c.destination === destination);\n }\n return [...consumerCalls];\n },\n\n getLastProducerCall(destination?: string) {\n const calls = this.getProducerCalls(destination);\n return calls.at(-1);\n },\n\n getLastConsumerCall(destination?: string) {\n const calls = this.getConsumerCalls(destination);\n return calls.at(-1);\n },\n\n reset() {\n producerCalls.length = 0;\n consumerCalls.length = 0;\n rebalanceEvents.length = 0;\n },\n\n shutdown() {\n this.reset();\n },\n };\n}\n\n// ============================================================================\n// Mock Broker\n// ============================================================================\n\n/**\n * Mock message broker for testing\n */\nexport interface MockMessageBroker {\n /** Topics/queues in the broker */\n topics: Map<string, MockMessage[]>;\n\n /**\n * Publish a message to a topic\n */\n publish(topic: string, message: MockMessage): void;\n\n /**\n * Consume messages from a topic\n */\n consume(topic: string, count?: number): MockMessage[];\n\n /**\n * Peek at messages without consuming\n */\n peek(topic: string, count?: number): MockMessage[];\n\n /**\n * Get message count for topic\n */\n getMessageCount(topic: string): number;\n\n /**\n * Clear all messages\n */\n clear(topic?: string): void;\n\n /**\n * Create a topic\n */\n createTopic(topic: string): void;\n\n /**\n * Delete a topic\n */\n deleteTopic(topic: string): void;\n\n /**\n * List all topics\n */\n listTopics(): string[];\n}\n\n/**\n * Create a mock message broker for testing\n *\n * Simulates a message broker (Kafka, SQS, RabbitMQ, etc.) for unit testing.\n *\n * @example\n * ```typescript\n * const broker = createMockMessageBroker();\n *\n * // Producer publishes\n * broker.publish('orders', { payload: { orderId: '123' }, headers: {} });\n *\n * // Consumer receives\n * const messages = broker.consume('orders');\n * expect(messages).toHaveLength(1);\n * expect(messages[0].payload).toEqual({ orderId: '123' });\n * ```\n */\nexport function createMockMessageBroker(): MockMessageBroker {\n const topics = new Map<string, MockMessage[]>();\n\n return {\n topics,\n\n publish(topic: string, message: MockMessage) {\n if (!topics.has(topic)) {\n topics.set(topic, []);\n }\n topics.get(topic)!.push({\n ...message,\n timestamp: message.timestamp ?? Date.now(),\n offset: message.offset ?? topics.get(topic)!.length,\n });\n },\n\n consume(topic: string, count?: number) {\n const messages = topics.get(topic) ?? [];\n if (count === undefined) {\n const all = [...messages];\n messages.length = 0;\n return all;\n }\n return messages.splice(0, count);\n },\n\n peek(topic: string, count?: number) {\n const messages = topics.get(topic) ?? [];\n if (count === undefined) {\n return [...messages];\n }\n return messages.slice(0, count);\n },\n\n getMessageCount(topic: string) {\n return topics.get(topic)?.length ?? 0;\n },\n\n clear(topic?: string) {\n if (topic) {\n topics.set(topic, []);\n } else {\n topics.clear();\n }\n },\n\n createTopic(topic: string) {\n if (!topics.has(topic)) {\n topics.set(topic, []);\n }\n },\n\n deleteTopic(topic: string) {\n topics.delete(topic);\n },\n\n listTopics() {\n return [...topics.keys()];\n },\n };\n}\n\n// ============================================================================\n// Context Propagation Helpers\n// ============================================================================\n\n/**\n * Extract trace ID from traceparent header\n */\nexport function extractTraceIdFromHeader(traceparent: string): string | null {\n const parts = traceparent.split('-');\n if (parts.length >= 3 && parts[1] !== undefined) {\n return parts[1];\n }\n return null;\n}\n\n/**\n * Extract span ID from traceparent header\n */\nexport function extractSpanIdFromHeader(traceparent: string): string | null {\n const parts = traceparent.split('-');\n if (parts.length >= 4 && parts[2] !== undefined) {\n return parts[2];\n }\n return null;\n}\n\n/**\n * Create a mock span context\n */\nexport function createMockSpanContext(\n traceId?: string,\n spanId?: string,\n): SpanContext {\n return {\n traceId: traceId ?? randomHex(32),\n spanId: spanId ?? randomHex(16),\n traceFlags: 1,\n isRemote: true,\n };\n}\n\n/**\n * Create a mock link to a producer span\n */\nexport function createMockProducerLink(\n traceId?: string,\n spanId?: string,\n): Link {\n return {\n context: createMockSpanContext(traceId, spanId),\n attributes: {\n 'messaging.link.source': 'producer',\n },\n };\n}\n\n// ============================================================================\n// Scenario Builders\n// ============================================================================\n\n/**\n * Create a batch of mock messages\n */\nexport function createMockMessageBatch<T>(\n payloads: T[],\n options: {\n startOffset?: number;\n partition?: number;\n addTraceHeaders?: boolean;\n traceId?: string;\n } = {},\n): MockMessage<T>[] {\n const startOffset = options.startOffset ?? 0;\n const addTraceHeaders = options.addTraceHeaders ?? true;\n const traceId = options.traceId ?? randomHex(32);\n\n return payloads.map((payload, index) => ({\n payload,\n headers: addTraceHeaders\n ? { traceparent: `00-${traceId}-${randomHex(16)}-01` }\n : undefined,\n offset: startOffset + index,\n partition: options.partition ?? 0,\n messageId: `msg-${randomHex(8)}`,\n timestamp: Date.now() + index,\n }));\n}\n\n/**\n * Create a rebalance scenario\n */\nexport function createRebalanceScenario(\n topic: string,\n consumerGroup: string,\n partitions: number[],\n): {\n assignEvent: RecordedRebalanceEvent;\n revokeEvent: RecordedRebalanceEvent;\n} {\n const assignments: PartitionAssignment[] = partitions.map((p) => ({\n topic,\n partition: p,\n offset: 0,\n }));\n\n return {\n assignEvent: {\n type: 'assigned',\n partitions: assignments,\n timestamp: Date.now(),\n generation: 1,\n destination: topic,\n consumerGroup,\n },\n revokeEvent: {\n type: 'revoked',\n partitions: assignments,\n timestamp: Date.now() + 1000,\n generation: 2,\n destination: topic,\n consumerGroup,\n },\n };\n}\n\n/**\n * Create an out-of-order scenario\n */\nexport function createOutOfOrderScenario<T>(\n payloads: T[],\n outOfOrderIndices: number[],\n): MockMessage<T>[] {\n const messages = createMockMessageBatch(payloads, { addTraceHeaders: true });\n\n // Shuffle specified indices to create out-of-order scenario\n const shuffled = [...messages];\n for (const index of outOfOrderIndices) {\n if (index > 0 && index < shuffled.length) {\n // Swap with previous to create out-of-order\n const prev = shuffled[index - 1]!;\n const curr = shuffled[index]!;\n shuffled[index - 1] = curr;\n shuffled[index] = prev;\n }\n }\n\n return shuffled;\n}\n\n/**\n * Create a duplicate message scenario\n */\nexport function createDuplicateScenario<T>(\n payloads: T[],\n duplicateIndices: number[],\n): MockMessage<T>[] {\n const messages = createMockMessageBatch(payloads, { addTraceHeaders: true });\n const result = [...messages];\n\n for (const index of duplicateIndices) {\n const originalMessage = messages[index];\n if (index >= 0 && index < messages.length && originalMessage) {\n // Insert duplicate after the original\n result.splice(index + 1, 0, { ...originalMessage });\n }\n }\n\n return result;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/messaging-testing.ts"],"names":[],"mappings":";;;AAiTA,SAAS,UAAU,MAAA,EAAwB;AACzC,EAAA,IAAI,MAAA,GAAS,EAAA;AACb,EAAA,MAAM,KAAA,GAAQ,kBAAA;AACd,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,EAAQ,CAAA,EAAA,EAAK;AAC/B,IAAA,MAAA,IAAU,KAAA,CAAM,OAAO,IAAA,CAAK,KAAA,CAAM,KAAK,MAAA,EAAO,GAAI,KAAA,CAAM,MAAM,CAAC,CAAA;AAAA,EACjE;AACA,EAAA,OAAO,MAAA;AACT;AA6BO,SAAS,0BAAA,GAAmD;AACjE,EAAA,MAAM,gBAAwC,EAAC;AAC/C,EAAA,MAAM,gBAAwC,EAAC;AAC/C,EAAA,MAAM,kBAA4C,EAAC;AAEnD,EAAA,OAAO;AAAA,IACL,aAAA;AAAA,IACA,aAAA;AAAA,IACA,eAAA;AAAA,IAEA,mBAAmB,IAAA,EAAM;AACvB,MAAA,aAAA,CAAc,IAAA,CAAK;AAAA,QACjB,GAAG,IAAA;AAAA,QACH,SAAA,EAAW,KAAK,GAAA;AAAI,OACrB,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,mBAAmB,IAAA,EAAM;AACvB,MAAA,aAAA,CAAc,IAAA,CAAK;AAAA,QACjB,GAAG,IAAA;AAAA,QACH,SAAA,EAAW,KAAK,GAAA;AAAI,OACrB,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,qBAAqB,KAAA,EAAO;AAC1B,MAAA,eAAA,CAAgB,KAAK,KAAK,CAAA;AAAA,IAC5B,CAAA;AAAA,IAEA,iBAAA,CACE,OAAA,EACA,OAAA,GAAmC,EAAC,EACpB;AAChB,MAAA,OAAO;AAAA,QACL,OAAA;AAAA,QACA,OAAA,EAAS,OAAA,CAAQ,OAAA,IAAW,IAAA,CAAK,sBAAA,EAAuB;AAAA,QACxD,MAAA,EAAQ,QAAQ,MAAA,IAAU,IAAA,CAAK,MAAM,IAAA,CAAK,MAAA,KAAW,GAAM,CAAA;AAAA,QAC3D,SAAA,EAAW,QAAQ,SAAA,IAAa,CAAA;AAAA,QAChC,KAAK,OAAA,CAAQ,GAAA;AAAA,QACb,WAAW,OAAA,CAAQ,SAAA,IAAa,CAAA,IAAA,EAAO,SAAA,CAAU,CAAC,CAAC,CAAA,CAAA;AAAA,QACnD,SAAA,EAAW,OAAA,CAAQ,SAAA,IAAa,IAAA,CAAK,GAAA;AAAI,OAC3C;AAAA,IACF,CAAA;AAAA,IAEA,sBAAA,CACE,SACA,MAAA,EACwB;AACxB,MAAA,MAAM,GAAA,GAAM,OAAA,IAAW,SAAA,CAAU,EAAE,CAAA;AACnC,MAAA,MAAM,GAAA,GAAM,MAAA,IAAU,SAAA,CAAU,EAAE,CAAA;AAClC,MAAA,OAAO;AAAA,QACL,WAAA,EAAa,CAAA,GAAA,EAAM,GAAG,CAAA,CAAA,EAAI,GAAG,CAAA,GAAA;AAAA,OAC/B;AAAA,IACF,CAAA;AAAA,IAEA,oBAAA,CACE,WAAA,EACA,OAAA,GAAoC,EAAC,EACrC;AACA,MAAA,MAAM,QAAQ,aAAA,CAAc,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,gBAAgB,WAAW,CAAA;AAEvE,MAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,mDAAmD,WAAW,CAAA,wBAAA;AAAA,SAChE;AAAA,MACF;AAEA,MAAA,IACE,QAAQ,YAAA,KAAiB,MAAA,IACzB,KAAA,CAAM,MAAA,KAAW,QAAQ,YAAA,EACzB;AACA,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,YAAY,OAAA,CAAQ,YAAY,wBAAwB,WAAW,CAAA,OAAA,EAAU,MAAM,MAAM,CAAA;AAAA,SAC3F;AAAA,MACF;AAEA,MAAA,IAAI,QAAQ,eAAA,EAAiB;AAC3B,QAAA,MAAM,cAAA,GAAiB,MAAM,MAAA,CAAO,CAAC,MAAM,CAAC,CAAA,CAAE,SAAS,WAAW,CAAA;AAClE,QAAA,IAAI,cAAA,CAAe,SAAS,CAAA,EAAG;AAC7B,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,iCAAA,EAAoC,WAAW,CAAA,6BAAA,EAAgC,cAAA,CAAe,MAAM,CAAA,QAAA;AAAA,WACtG;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,QAAQ,OAAA,EAAS;AACnB,QAAA,MAAM,kBAAkB,KAAA,CAAM,MAAA;AAAA,UAC5B,CAAC,CAAA,KAAM,CAAA,CAAE,OAAA,KAAY,OAAA,CAAQ;AAAA,SAC/B;AACA,QAAA,IAAI,eAAA,CAAgB,WAAW,CAAA,EAAG;AAChC,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,4BAAA,EAA+B,WAAW,CAAA,gBAAA,EAAmB,OAAA,CAAQ,OAAO,CAAA,iBAAA;AAAA,WAC9E;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,QAAQ,cAAA,EAAgB;AAC1B,QAAA,MAAM,WAAW,KAAA,CAAM,MAAA;AAAA,UAAO,CAAC,CAAA,KAC7B,OAAA,CAAQ,cAAA,CAAgB,EAAE,OAAO;AAAA,SACnC;AACA,QAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,+BAA+B,WAAW,CAAA,wCAAA;AAAA,WAC5C;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IAEA,wBAAwB,WAAA,EAAsB;AAC5C,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,MAAM,QAAQ,aAAA,CAAc,MAAA;AAAA,UAC1B,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,KAAgB;AAAA,SAC3B;AACA,QAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,wCAAA,EAA2C,WAAW,CAAA,qBAAA,EAAwB,KAAA,CAAM,MAAM,CAAA,MAAA;AAAA,WAC5F;AAAA,QACF;AAAA,MACF,CAAA,MAAO;AACL,QAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC5B,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,gCAAA,EAAmC,cAAc,MAAM,CAAA,gBAAA;AAAA,WACzD;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IAEA,uBAAA,CACE,WAAA,EACA,OAAA,GAAoC,EAAC,EACrC;AACA,MAAA,MAAM,QAAQ,aAAA,CAAc,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,gBAAgB,WAAW,CAAA;AAEvE,MAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACtB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,0DAA0D,WAAW,CAAA,0BAAA;AAAA,SACvE;AAAA,MACF;AAEA,MAAA,IACE,QAAQ,YAAA,KAAiB,MAAA,IACzB,KAAA,CAAM,MAAA,KAAW,QAAQ,YAAA,EACzB;AACA,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,YAAY,OAAA,CAAQ,YAAY,wBAAwB,WAAW,CAAA,OAAA,EAAU,MAAM,MAAM,CAAA;AAAA,SAC3F;AAAA,MACF;AAEA,MAAA,IAAI,QAAQ,aAAA,EAAe;AACzB,QAAA,MAAM,aAAa,KAAA,CAAM,MAAA;AAAA,UACvB,CAAC,CAAA,KAAM,CAAA,CAAE,aAAA,KAAkB,OAAA,CAAQ;AAAA,SACrC;AACA,QAAA,IAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AACzB,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,yBAAA,EAA4B,OAAA,CAAQ,aAAa,CAAA,OAAA,EAAU,WAAW,CAAA,6BAAA;AAAA,WACxE;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,QAAQ,gBAAA,EAAkB;AAC5B,QAAA,MAAM,YAAA,GAAe,MAAM,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,aAAA,CAAc,WAAW,CAAC,CAAA;AACrE,QAAA,IAAI,YAAA,CAAa,SAAS,CAAA,EAAG;AAC3B,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,iCAAA,EAAoC,WAAW,CAAA,8BAAA,EAAiC,YAAA,CAAa,MAAM,CAAA,QAAA;AAAA,WACrG;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,CAAQ,kBAAkB,MAAA,EAAW;AACvC,QAAA,MAAM,aAAa,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,EAAE,WAAW,CAAA;AACpD,QAAA,IAAI,OAAA,CAAQ,aAAA,IAAiB,UAAA,CAAW,MAAA,KAAW,CAAA,EAAG;AACpD,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,oCAAoC,WAAW,CAAA,yBAAA;AAAA,WACjD;AAAA,QACF;AACA,QAAA,IAAI,CAAC,OAAA,CAAQ,aAAA,IAAiB,UAAA,CAAW,SAAS,CAAA,EAAG;AACnD,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,oCAAA,EAAuC,WAAW,CAAA,OAAA,EAAU,UAAA,CAAW,MAAM,CAAA,cAAA;AAAA,WAC/E;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,CAAQ,kBAAkB,MAAA,EAAW;AACvC,QAAA,MAAM,aAAa,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,mBAAmB,IAAI,CAAA;AAChE,QAAA,IAAI,OAAA,CAAQ,aAAA,IAAiB,UAAA,CAAW,MAAA,KAAW,CAAA,EAAG;AACpD,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,uCAAuC,WAAW,CAAA,yBAAA;AAAA,WACpD;AAAA,QACF;AACA,QAAA,IAAI,CAAC,OAAA,CAAQ,aAAA,IAAiB,UAAA,CAAW,SAAS,CAAA,EAAG;AACnD,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,uCAAA,EAA0C,WAAW,CAAA,OAAA,EAAU,UAAA,CAAW,MAAM,CAAA,cAAA;AAAA,WAClF;AAAA,QACF;AAAA,MACF;AAEA,MAAA,IAAI,OAAA,CAAQ,WAAW,MAAA,EAAW;AAChC,QAAA,MAAM,WAAW,KAAA,CAAM,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,cAAc,MAAS,CAAA;AAC9D,QAAA,IAAI,OAAA,CAAQ,MAAA,IAAU,QAAA,CAAS,MAAA,KAAW,CAAA,EAAG;AAC3C,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,6BAA6B,WAAW,CAAA,oBAAA;AAAA,WAC1C;AAAA,QACF;AACA,QAAA,IAAI,CAAC,OAAA,CAAQ,MAAA,IAAU,QAAA,CAAS,SAAS,CAAA,EAAG;AAC1C,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,6BAAA,EAAgC,WAAW,CAAA,OAAA,EAAU,QAAA,CAAS,MAAM,CAAA,SAAA;AAAA,WACtE;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IAEA,wBAAwB,WAAA,EAAsB;AAC5C,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,MAAM,QAAQ,aAAA,CAAc,MAAA;AAAA,UAC1B,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,KAAgB;AAAA,SAC3B;AACA,QAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,wCAAA,EAA2C,WAAW,CAAA,oBAAA,EAAuB,KAAA,CAAM,MAAM,CAAA,SAAA;AAAA,WAC3F;AAAA,QACF;AAAA,MACF,CAAA,MAAO;AACL,QAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC5B,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,gCAAA,EAAmC,cAAc,MAAM,CAAA,wBAAA;AAAA,WACzD;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IAEA,uBAAA,CACE,WAAA,EACA,IAAA,EACA,cAAA,EACA;AACA,MAAA,MAAM,SAAS,eAAA,CAAgB,MAAA;AAAA,QAC7B,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,KAAgB,WAAA,IAAe,EAAE,IAAA,KAAS;AAAA,OACrD;AAEA,MAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,QAAA,MAAM,IAAI,KAAA;AAAA,UACR,CAAA,oBAAA,EAAuB,IAAI,CAAA,OAAA,EAAU,WAAW,CAAA,oBAAA;AAAA,SAClD;AAAA,MACF;AAEA,MAAA,IAAI,mBAAmB,MAAA,EAAW;AAChC,QAAA,MAAM,WAAW,MAAA,CAAO,MAAA;AAAA,UACtB,CAAC,CAAA,KAAM,CAAA,CAAE,UAAA,CAAW,MAAA,KAAW;AAAA,SACjC;AACA,QAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,UAAA,MAAM,IAAI,KAAA;AAAA,YACR,CAAA,oBAAA,EAAuB,IAAI,CAAA,OAAA,EAAU,WAAW,UAAU,cAAc,CAAA,6BAAA;AAAA,WAC1E;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IAEA,iBAAiB,WAAA,EAAsB;AACrC,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,OAAO,cAAc,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,gBAAgB,WAAW,CAAA;AAAA,MAClE;AACA,MAAA,OAAO,CAAC,GAAG,aAAa,CAAA;AAAA,IAC1B,CAAA;AAAA,IAEA,iBAAiB,WAAA,EAAsB;AACrC,MAAA,IAAI,WAAA,EAAa;AACf,QAAA,OAAO,cAAc,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,gBAAgB,WAAW,CAAA;AAAA,MAClE;AACA,MAAA,OAAO,CAAC,GAAG,aAAa,CAAA;AAAA,IAC1B,CAAA;AAAA,IAEA,oBAAoB,WAAA,EAAsB;AACxC,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,gBAAA,CAAiB,WAAW,CAAA;AAC/C,MAAA,OAAO,KAAA,CAAM,GAAG,EAAE,CAAA;AAAA,IACpB,CAAA;AAAA,IAEA,oBAAoB,WAAA,EAAsB;AACxC,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,gBAAA,CAAiB,WAAW,CAAA;AAC/C,MAAA,OAAO,KAAA,CAAM,GAAG,EAAE,CAAA;AAAA,IACpB,CAAA;AAAA,IAEA,KAAA,GAAQ;AACN,MAAA,aAAA,CAAc,MAAA,GAAS,CAAA;AACvB,MAAA,aAAA,CAAc,MAAA,GAAS,CAAA;AACvB,MAAA,eAAA,CAAgB,MAAA,GAAS,CAAA;AAAA,IAC3B,CAAA;AAAA,IAEA,QAAA,GAAW;AACT,MAAA,IAAA,CAAK,KAAA,EAAM;AAAA,IACb;AAAA,GACF;AACF;AAwEO,SAAS,uBAAA,GAA6C;AAC3D,EAAA,MAAM,MAAA,uBAAa,GAAA,EAA2B;AAE9C,EAAA,OAAO;AAAA,IACL,MAAA;AAAA,IAEA,OAAA,CAAQ,OAAe,OAAA,EAAsB;AAC3C,MAAA,IAAI,CAAC,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,EAAG;AACtB,QAAA,MAAA,CAAO,GAAA,CAAI,KAAA,EAAO,EAAE,CAAA;AAAA,MACtB;AACA,MAAA,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,CAAG,IAAA,CAAK;AAAA,QACtB,GAAG,OAAA;AAAA,QACH,SAAA,EAAW,OAAA,CAAQ,SAAA,IAAa,IAAA,CAAK,GAAA,EAAI;AAAA,QACzC,QAAQ,OAAA,CAAQ,MAAA,IAAU,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,CAAG;AAAA,OAC9C,CAAA;AAAA,IACH,CAAA;AAAA,IAEA,OAAA,CAAQ,OAAe,KAAA,EAAgB;AACrC,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,KAAK,KAAK,EAAC;AACvC,MAAA,IAAI,UAAU,MAAA,EAAW;AACvB,QAAA,MAAM,GAAA,GAAM,CAAC,GAAG,QAAQ,CAAA;AACxB,QAAA,QAAA,CAAS,MAAA,GAAS,CAAA;AAClB,QAAA,OAAO,GAAA;AAAA,MACT;AACA,MAAA,OAAO,QAAA,CAAS,MAAA,CAAO,CAAA,EAAG,KAAK,CAAA;AAAA,IACjC,CAAA;AAAA,IAEA,IAAA,CAAK,OAAe,KAAA,EAAgB;AAClC,MAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,CAAI,KAAK,KAAK,EAAC;AACvC,MAAA,IAAI,UAAU,MAAA,EAAW;AACvB,QAAA,OAAO,CAAC,GAAG,QAAQ,CAAA;AAAA,MACrB;AACA,MAAA,OAAO,QAAA,CAAS,KAAA,CAAM,CAAA,EAAG,KAAK,CAAA;AAAA,IAChC,CAAA;AAAA,IAEA,gBAAgB,KAAA,EAAe;AAC7B,MAAA,OAAO,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,EAAG,MAAA,IAAU,CAAA;AAAA,IACtC,CAAA;AAAA,IAEA,MAAM,KAAA,EAAgB;AACpB,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,MAAA,CAAO,GAAA,CAAI,KAAA,EAAO,EAAE,CAAA;AAAA,MACtB,CAAA,MAAO;AACL,QAAA,MAAA,CAAO,KAAA,EAAM;AAAA,MACf;AAAA,IACF,CAAA;AAAA,IAEA,YAAY,KAAA,EAAe;AACzB,MAAA,IAAI,CAAC,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA,EAAG;AACtB,QAAA,MAAA,CAAO,GAAA,CAAI,KAAA,EAAO,EAAE,CAAA;AAAA,MACtB;AAAA,IACF,CAAA;AAAA,IAEA,YAAY,KAAA,EAAe;AACzB,MAAA,MAAA,CAAO,OAAO,KAAK,CAAA;AAAA,IACrB,CAAA;AAAA,IAEA,UAAA,GAAa;AACX,MAAA,OAAO,CAAC,GAAG,MAAA,CAAO,IAAA,EAAM,CAAA;AAAA,IAC1B;AAAA,GACF;AACF;AASO,SAAS,yBAAyB,WAAA,EAAoC;AAC3E,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,KAAA,CAAM,GAAG,CAAA;AACnC,EAAA,IAAI,MAAM,MAAA,IAAU,CAAA,IAAK,KAAA,CAAM,CAAC,MAAM,MAAA,EAAW;AAC/C,IAAA,OAAO,MAAM,CAAC,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,IAAA;AACT;AAKO,SAAS,wBAAwB,WAAA,EAAoC;AAC1E,EAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,KAAA,CAAM,GAAG,CAAA;AACnC,EAAA,IAAI,MAAM,MAAA,IAAU,CAAA,IAAK,KAAA,CAAM,CAAC,MAAM,MAAA,EAAW;AAC/C,IAAA,OAAO,MAAM,CAAC,CAAA;AAAA,EAChB;AACA,EAAA,OAAO,IAAA;AACT;AAKO,SAAS,qBAAA,CACd,SACA,MAAA,EACa;AACb,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,OAAA,IAAW,SAAA,CAAU,EAAE,CAAA;AAAA,IAChC,MAAA,EAAQ,MAAA,IAAU,SAAA,CAAU,EAAE,CAAA;AAAA,IAC9B,UAAA,EAAY,CAAA;AAAA,IACZ,QAAA,EAAU;AAAA,GACZ;AACF;AAKO,SAAS,sBAAA,CACd,SACA,MAAA,EACM;AACN,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,qBAAA,CAAsB,OAAA,EAAS,MAAM,CAAA;AAAA,IAC9C,UAAA,EAAY;AAAA,MACV,uBAAA,EAAyB;AAAA;AAC3B,GACF;AACF;AASO,SAAS,sBAAA,CACd,QAAA,EACA,OAAA,GAKI,EAAC,EACa;AAClB,EAAA,MAAM,WAAA,GAAc,QAAQ,WAAA,IAAe,CAAA;AAC3C,EAAA,MAAM,eAAA,GAAkB,QAAQ,eAAA,IAAmB,IAAA;AACnD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,SAAA,CAAU,EAAE,CAAA;AAE/C,EAAA,OAAO,QAAA,CAAS,GAAA,CAAI,CAAC,OAAA,EAAS,KAAA,MAAW;AAAA,IACvC,OAAA;AAAA,IACA,OAAA,EAAS,eAAA,GACL,EAAE,WAAA,EAAa,CAAA,GAAA,EAAM,OAAO,CAAA,CAAA,EAAI,SAAA,CAAU,EAAE,CAAC,CAAA,GAAA,CAAA,EAAM,GACnD,MAAA;AAAA,IACJ,QAAQ,WAAA,GAAc,KAAA;AAAA,IACtB,SAAA,EAAW,QAAQ,SAAA,IAAa,CAAA;AAAA,IAChC,SAAA,EAAW,CAAA,IAAA,EAAO,SAAA,CAAU,CAAC,CAAC,CAAA,CAAA;AAAA,IAC9B,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,GAC1B,CAAE,CAAA;AACJ;AAKO,SAAS,uBAAA,CACd,KAAA,EACA,aAAA,EACA,UAAA,EAIA;AACA,EAAA,MAAM,WAAA,GAAqC,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,IAChE,KAAA;AAAA,IACA,SAAA,EAAW,CAAA;AAAA,IACX,MAAA,EAAQ;AAAA,GACV,CAAE,CAAA;AAEF,EAAA,OAAO;AAAA,IACL,WAAA,EAAa;AAAA,MACX,IAAA,EAAM,UAAA;AAAA,MACN,UAAA,EAAY,WAAA;AAAA,MACZ,SAAA,EAAW,KAAK,GAAA,EAAI;AAAA,MACpB,UAAA,EAAY,CAAA;AAAA,MACZ,WAAA,EAAa,KAAA;AAAA,MACb;AAAA,KACF;AAAA,IACA,WAAA,EAAa;AAAA,MACX,IAAA,EAAM,SAAA;AAAA,MACN,UAAA,EAAY,WAAA;AAAA,MACZ,SAAA,EAAW,IAAA,CAAK,GAAA,EAAI,GAAI,GAAA;AAAA,MACxB,UAAA,EAAY,CAAA;AAAA,MACZ,WAAA,EAAa,KAAA;AAAA,MACb;AAAA;AACF,GACF;AACF;AAKO,SAAS,wBAAA,CACd,UACA,iBAAA,EACkB;AAClB,EAAA,MAAM,WAAW,sBAAA,CAAuB,QAAA,EAAU,EAAE,eAAA,EAAiB,MAAM,CAAA;AAG3E,EAAA,MAAM,QAAA,GAAW,CAAC,GAAG,QAAQ,CAAA;AAC7B,EAAA,KAAA,MAAW,SAAS,iBAAA,EAAmB;AACrC,IAAA,IAAI,KAAA,GAAQ,CAAA,IAAK,KAAA,GAAQ,QAAA,CAAS,MAAA,EAAQ;AAExC,MAAA,MAAM,IAAA,GAAO,QAAA,CAAS,KAAA,GAAQ,CAAC,CAAA;AAC/B,MAAA,MAAM,IAAA,GAAO,SAAS,KAAK,CAAA;AAC3B,MAAA,QAAA,CAAS,KAAA,GAAQ,CAAC,CAAA,GAAI,IAAA;AACtB,MAAA,QAAA,CAAS,KAAK,CAAA,GAAI,IAAA;AAAA,IACpB;AAAA,EACF;AAEA,EAAA,OAAO,QAAA;AACT;AAKO,SAAS,uBAAA,CACd,UACA,gBAAA,EACkB;AAClB,EAAA,MAAM,WAAW,sBAAA,CAAuB,QAAA,EAAU,EAAE,eAAA,EAAiB,MAAM,CAAA;AAC3E,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,QAAQ,CAAA;AAE3B,EAAA,KAAA,MAAW,SAAS,gBAAA,EAAkB;AACpC,IAAA,MAAM,eAAA,GAAkB,SAAS,KAAK,CAAA;AACtC,IAAA,IAAI,KAAA,IAAS,CAAA,IAAK,KAAA,GAAQ,QAAA,CAAS,UAAU,eAAA,EAAiB;AAE5D,MAAA,MAAA,CAAO,OAAO,KAAA,GAAQ,CAAA,EAAG,GAAG,EAAE,GAAG,iBAAiB,CAAA;AAAA,IACpD;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT","file":"messaging-testing.js","sourcesContent":["/**\n * Testing utilities for messaging instrumentation\n *\n * Provides mock producers, consumers, and assertion helpers\n * for testing event-driven code with Autotel's messaging module.\n *\n * @example Basic test setup\n * ```typescript\n * import { createMessagingTestHarness } from 'autotel/messaging-testing';\n *\n * describe('Order processing', () => {\n * const harness = createMessagingTestHarness();\n *\n * beforeEach(() => harness.reset());\n * afterAll(() => harness.shutdown());\n *\n * it('should process order and publish event', async () => {\n * await processOrder({ id: 'order-123' });\n *\n * harness.assertProducerCalled('orders', {\n * messageCount: 1,\n * hasTraceHeaders: true,\n * });\n * });\n * });\n * ```\n *\n * @module\n */\n\nimport type { Link, SpanContext } from '@opentelemetry/api';\nimport type {\n RebalanceEvent,\n PartitionAssignment,\n OutOfOrderInfo,\n} from './messaging';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Recorded producer call\n */\nexport interface RecordedProducerCall {\n /** Destination (topic/queue) */\n destination: string;\n\n /** System (kafka, sqs, etc.) */\n system: string;\n\n /** Message payload */\n payload: unknown;\n\n /** Headers injected */\n headers: Record<string, string>;\n\n /** Timestamp of call */\n timestamp: number;\n\n /** Trace ID from headers */\n traceId?: string;\n\n /** Span ID from headers */\n spanId?: string;\n}\n\n/**\n * Recorded consumer call\n */\nexport interface RecordedConsumerCall {\n /** Destination (topic/queue) */\n destination: string;\n\n /** System (kafka, sqs, etc.) */\n system: string;\n\n /** Consumer group */\n consumerGroup?: string;\n\n /** Message payload */\n payload: unknown;\n\n /** Headers extracted */\n headers?: Record<string, string>;\n\n /** Timestamp of call */\n timestamp: number;\n\n /** Producer links extracted */\n producerLinks: Link[];\n\n /** Whether message was duplicate */\n isDuplicate: boolean;\n\n /** Out of order info if detected */\n outOfOrderInfo: OutOfOrderInfo | null;\n\n /** DLQ reason if routed to DLQ */\n dlqReason?: string;\n\n /** Retry attempt number */\n retryAttempt?: number;\n}\n\n/**\n * Recorded rebalance event\n */\nexport interface RecordedRebalanceEvent extends RebalanceEvent {\n /** Destination (topic) */\n destination: string;\n\n /** Consumer group */\n consumerGroup: string;\n}\n\n/**\n * Mock message for testing\n */\nexport interface MockMessage<T = unknown> {\n /** Message payload */\n payload: T;\n\n /** Headers */\n headers?: Record<string, string>;\n\n /** Offset/sequence number */\n offset?: number;\n\n /** Partition */\n partition?: number;\n\n /** Key */\n key?: string;\n\n /** Message ID */\n messageId?: string;\n\n /** Timestamp */\n timestamp?: number;\n}\n\n/**\n * Producer assertion options\n */\nexport interface ProducerAssertionOptions {\n /** Expected number of messages */\n messageCount?: number;\n\n /** Whether trace headers should be present */\n hasTraceHeaders?: boolean;\n\n /** Expected destination */\n destination?: string;\n\n /** Custom matcher for payload */\n payloadMatcher?: (payload: unknown) => boolean;\n\n /** Expected trace ID */\n traceId?: string;\n}\n\n/**\n * Consumer assertion options\n */\nexport interface ConsumerAssertionOptions {\n /** Expected number of messages processed */\n messageCount?: number;\n\n /** Whether producer links should be present */\n hasProducerLinks?: boolean;\n\n /** Expected destination */\n destination?: string;\n\n /** Expected consumer group */\n consumerGroup?: string;\n\n /** Whether any messages were duplicates */\n hasDuplicates?: boolean;\n\n /** Whether any messages were out of order */\n hasOutOfOrder?: boolean;\n\n /** Whether any messages went to DLQ */\n hasDLQ?: boolean;\n}\n\n/**\n * Messaging test harness\n */\nexport interface MessagingTestHarness {\n /** All recorded producer calls */\n producerCalls: RecordedProducerCall[];\n\n /** All recorded consumer calls */\n consumerCalls: RecordedConsumerCall[];\n\n /** All recorded rebalance events */\n rebalanceEvents: RecordedRebalanceEvent[];\n\n /**\n * Record a producer call\n */\n recordProducerCall(call: Omit<RecordedProducerCall, 'timestamp'>): void;\n\n /**\n * Record a consumer call\n */\n recordConsumerCall(call: Omit<RecordedConsumerCall, 'timestamp'>): void;\n\n /**\n * Record a rebalance event\n */\n recordRebalanceEvent(event: RecordedRebalanceEvent): void;\n\n /**\n * Create a mock message with trace headers\n */\n createMockMessage<T>(\n payload: T,\n options?: Partial<MockMessage<T>>,\n ): MockMessage<T>;\n\n /**\n * Create mock trace headers\n */\n createMockTraceHeaders(\n traceId?: string,\n spanId?: string,\n ): Record<string, string>;\n\n /**\n * Assert producer was called with expected options\n */\n assertProducerCalled(\n destination: string,\n options?: ProducerAssertionOptions,\n ): void;\n\n /**\n * Assert producer was not called\n */\n assertProducerNotCalled(destination?: string): void;\n\n /**\n * Assert consumer processed messages with expected options\n */\n assertConsumerProcessed(\n destination: string,\n options?: ConsumerAssertionOptions,\n ): void;\n\n /**\n * Assert consumer was not called\n */\n assertConsumerNotCalled(destination?: string): void;\n\n /**\n * Assert rebalance occurred\n */\n assertRebalanceOccurred(\n destination: string,\n type: RebalanceEvent['type'],\n partitionCount?: number,\n ): void;\n\n /**\n * Get producer calls for destination\n */\n getProducerCalls(destination?: string): RecordedProducerCall[];\n\n /**\n * Get consumer calls for destination\n */\n getConsumerCalls(destination?: string): RecordedConsumerCall[];\n\n /**\n * Get the last producer call\n */\n getLastProducerCall(destination?: string): RecordedProducerCall | undefined;\n\n /**\n * Get the last consumer call\n */\n getLastConsumerCall(destination?: string): RecordedConsumerCall | undefined;\n\n /**\n * Reset all recorded calls\n */\n reset(): void;\n\n /**\n * Shutdown the harness\n */\n shutdown(): void;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Generate a random hex string\n */\nfunction randomHex(length: number): string {\n let result = '';\n const chars = '0123456789abcdef';\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n\n/**\n * Create a messaging test harness\n *\n * Provides utilities for recording and asserting on producer/consumer calls\n * during testing.\n *\n * @example\n * ```typescript\n * const harness = createMessagingTestHarness();\n *\n * // In your test setup\n * beforeEach(() => harness.reset());\n *\n * // In your tests\n * it('should publish order event', async () => {\n * await orderService.createOrder({ id: '123' });\n *\n * harness.assertProducerCalled('orders', {\n * messageCount: 1,\n * hasTraceHeaders: true,\n * });\n *\n * const lastCall = harness.getLastProducerCall('orders');\n * expect(lastCall?.payload).toMatchObject({ orderId: '123' });\n * });\n * ```\n */\nexport function createMessagingTestHarness(): MessagingTestHarness {\n const producerCalls: RecordedProducerCall[] = [];\n const consumerCalls: RecordedConsumerCall[] = [];\n const rebalanceEvents: RecordedRebalanceEvent[] = [];\n\n return {\n producerCalls,\n consumerCalls,\n rebalanceEvents,\n\n recordProducerCall(call) {\n producerCalls.push({\n ...call,\n timestamp: Date.now(),\n });\n },\n\n recordConsumerCall(call) {\n consumerCalls.push({\n ...call,\n timestamp: Date.now(),\n });\n },\n\n recordRebalanceEvent(event) {\n rebalanceEvents.push(event);\n },\n\n createMockMessage<T>(\n payload: T,\n options: Partial<MockMessage<T>> = {},\n ): MockMessage<T> {\n return {\n payload,\n headers: options.headers ?? this.createMockTraceHeaders(),\n offset: options.offset ?? Math.floor(Math.random() * 10_000),\n partition: options.partition ?? 0,\n key: options.key,\n messageId: options.messageId ?? `msg-${randomHex(8)}`,\n timestamp: options.timestamp ?? Date.now(),\n };\n },\n\n createMockTraceHeaders(\n traceId?: string,\n spanId?: string,\n ): Record<string, string> {\n const tid = traceId ?? randomHex(32);\n const sid = spanId ?? randomHex(16);\n return {\n traceparent: `00-${tid}-${sid}-01`,\n };\n },\n\n assertProducerCalled(\n destination: string,\n options: ProducerAssertionOptions = {},\n ) {\n const calls = producerCalls.filter((c) => c.destination === destination);\n\n if (calls.length === 0) {\n throw new Error(\n `Expected producer to be called for destination '${destination}', but it was not called`,\n );\n }\n\n if (\n options.messageCount !== undefined &&\n calls.length !== options.messageCount\n ) {\n throw new Error(\n `Expected ${options.messageCount} producer calls for '${destination}', got ${calls.length}`,\n );\n }\n\n if (options.hasTraceHeaders) {\n const withoutHeaders = calls.filter((c) => !c.headers?.traceparent);\n if (withoutHeaders.length > 0) {\n throw new Error(\n `Expected all producer calls for '${destination}' to have trace headers, but ${withoutHeaders.length} did not`,\n );\n }\n }\n\n if (options.traceId) {\n const matchingTraceId = calls.filter(\n (c) => c.traceId === options.traceId,\n );\n if (matchingTraceId.length === 0) {\n throw new Error(\n `Expected producer call for '${destination}' with traceId '${options.traceId}', but none found`,\n );\n }\n }\n\n if (options.payloadMatcher) {\n const matching = calls.filter((c) =>\n options.payloadMatcher!(c.payload),\n );\n if (matching.length === 0) {\n throw new Error(\n `Expected producer call for '${destination}' to match payload matcher, but none did`,\n );\n }\n }\n },\n\n assertProducerNotCalled(destination?: string) {\n if (destination) {\n const calls = producerCalls.filter(\n (c) => c.destination === destination,\n );\n if (calls.length > 0) {\n throw new Error(\n `Expected producer not to be called for '${destination}', but it was called ${calls.length} times`,\n );\n }\n } else {\n if (producerCalls.length > 0) {\n throw new Error(\n `Expected no producer calls, but ${producerCalls.length} calls were made`,\n );\n }\n }\n },\n\n assertConsumerProcessed(\n destination: string,\n options: ConsumerAssertionOptions = {},\n ) {\n const calls = consumerCalls.filter((c) => c.destination === destination);\n\n if (calls.length === 0) {\n throw new Error(\n `Expected consumer to process messages for destination '${destination}', but none were processed`,\n );\n }\n\n if (\n options.messageCount !== undefined &&\n calls.length !== options.messageCount\n ) {\n throw new Error(\n `Expected ${options.messageCount} consumer calls for '${destination}', got ${calls.length}`,\n );\n }\n\n if (options.consumerGroup) {\n const wrongGroup = calls.filter(\n (c) => c.consumerGroup !== options.consumerGroup,\n );\n if (wrongGroup.length > 0) {\n throw new Error(\n `Expected consumer group '${options.consumerGroup}' for '${destination}', but found different groups`,\n );\n }\n }\n\n if (options.hasProducerLinks) {\n const withoutLinks = calls.filter((c) => c.producerLinks.length === 0);\n if (withoutLinks.length > 0) {\n throw new Error(\n `Expected all consumer calls for '${destination}' to have producer links, but ${withoutLinks.length} did not`,\n );\n }\n }\n\n if (options.hasDuplicates !== undefined) {\n const duplicates = calls.filter((c) => c.isDuplicate);\n if (options.hasDuplicates && duplicates.length === 0) {\n throw new Error(\n `Expected duplicate messages for '${destination}', but none were detected`,\n );\n }\n if (!options.hasDuplicates && duplicates.length > 0) {\n throw new Error(\n `Expected no duplicate messages for '${destination}', but ${duplicates.length} were detected`,\n );\n }\n }\n\n if (options.hasOutOfOrder !== undefined) {\n const outOfOrder = calls.filter((c) => c.outOfOrderInfo !== null);\n if (options.hasOutOfOrder && outOfOrder.length === 0) {\n throw new Error(\n `Expected out-of-order messages for '${destination}', but none were detected`,\n );\n }\n if (!options.hasOutOfOrder && outOfOrder.length > 0) {\n throw new Error(\n `Expected no out-of-order messages for '${destination}', but ${outOfOrder.length} were detected`,\n );\n }\n }\n\n if (options.hasDLQ !== undefined) {\n const dlqCalls = calls.filter((c) => c.dlqReason !== undefined);\n if (options.hasDLQ && dlqCalls.length === 0) {\n throw new Error(\n `Expected DLQ routing for '${destination}', but none occurred`,\n );\n }\n if (!options.hasDLQ && dlqCalls.length > 0) {\n throw new Error(\n `Expected no DLQ routing for '${destination}', but ${dlqCalls.length} occurred`,\n );\n }\n }\n },\n\n assertConsumerNotCalled(destination?: string) {\n if (destination) {\n const calls = consumerCalls.filter(\n (c) => c.destination === destination,\n );\n if (calls.length > 0) {\n throw new Error(\n `Expected consumer not to be called for '${destination}', but it processed ${calls.length} messages`,\n );\n }\n } else {\n if (consumerCalls.length > 0) {\n throw new Error(\n `Expected no consumer calls, but ${consumerCalls.length} messages were processed`,\n );\n }\n }\n },\n\n assertRebalanceOccurred(\n destination: string,\n type: RebalanceEvent['type'],\n partitionCount?: number,\n ) {\n const events = rebalanceEvents.filter(\n (e) => e.destination === destination && e.type === type,\n );\n\n if (events.length === 0) {\n throw new Error(\n `Expected rebalance '${type}' for '${destination}', but none occurred`,\n );\n }\n\n if (partitionCount !== undefined) {\n const matching = events.filter(\n (e) => e.partitions.length === partitionCount,\n );\n if (matching.length === 0) {\n throw new Error(\n `Expected rebalance '${type}' for '${destination}' with ${partitionCount} partitions, but none matched`,\n );\n }\n }\n },\n\n getProducerCalls(destination?: string) {\n if (destination) {\n return producerCalls.filter((c) => c.destination === destination);\n }\n return [...producerCalls];\n },\n\n getConsumerCalls(destination?: string) {\n if (destination) {\n return consumerCalls.filter((c) => c.destination === destination);\n }\n return [...consumerCalls];\n },\n\n getLastProducerCall(destination?: string) {\n const calls = this.getProducerCalls(destination);\n return calls.at(-1);\n },\n\n getLastConsumerCall(destination?: string) {\n const calls = this.getConsumerCalls(destination);\n return calls.at(-1);\n },\n\n reset() {\n producerCalls.length = 0;\n consumerCalls.length = 0;\n rebalanceEvents.length = 0;\n },\n\n shutdown() {\n this.reset();\n },\n };\n}\n\n// ============================================================================\n// Mock Broker\n// ============================================================================\n\n/**\n * Mock message broker for testing\n */\nexport interface MockMessageBroker {\n /** Topics/queues in the broker */\n topics: Map<string, MockMessage[]>;\n\n /**\n * Publish a message to a topic\n */\n publish(topic: string, message: MockMessage): void;\n\n /**\n * Consume messages from a topic\n */\n consume(topic: string, count?: number): MockMessage[];\n\n /**\n * Peek at messages without consuming\n */\n peek(topic: string, count?: number): MockMessage[];\n\n /**\n * Get message count for topic\n */\n getMessageCount(topic: string): number;\n\n /**\n * Clear all messages\n */\n clear(topic?: string): void;\n\n /**\n * Create a topic\n */\n createTopic(topic: string): void;\n\n /**\n * Delete a topic\n */\n deleteTopic(topic: string): void;\n\n /**\n * List all topics\n */\n listTopics(): string[];\n}\n\n/**\n * Create a mock message broker for testing\n *\n * Simulates a message broker (Kafka, SQS, RabbitMQ, etc.) for unit testing.\n *\n * @example\n * ```typescript\n * const broker = createMockMessageBroker();\n *\n * // Producer publishes\n * broker.publish('orders', { payload: { orderId: '123' }, headers: {} });\n *\n * // Consumer receives\n * const messages = broker.consume('orders');\n * expect(messages).toHaveLength(1);\n * expect(messages[0].payload).toEqual({ orderId: '123' });\n * ```\n */\nexport function createMockMessageBroker(): MockMessageBroker {\n const topics = new Map<string, MockMessage[]>();\n\n return {\n topics,\n\n publish(topic: string, message: MockMessage) {\n if (!topics.has(topic)) {\n topics.set(topic, []);\n }\n topics.get(topic)!.push({\n ...message,\n timestamp: message.timestamp ?? Date.now(),\n offset: message.offset ?? topics.get(topic)!.length,\n });\n },\n\n consume(topic: string, count?: number) {\n const messages = topics.get(topic) ?? [];\n if (count === undefined) {\n const all = [...messages];\n messages.length = 0;\n return all;\n }\n return messages.splice(0, count);\n },\n\n peek(topic: string, count?: number) {\n const messages = topics.get(topic) ?? [];\n if (count === undefined) {\n return [...messages];\n }\n return messages.slice(0, count);\n },\n\n getMessageCount(topic: string) {\n return topics.get(topic)?.length ?? 0;\n },\n\n clear(topic?: string) {\n if (topic) {\n topics.set(topic, []);\n } else {\n topics.clear();\n }\n },\n\n createTopic(topic: string) {\n if (!topics.has(topic)) {\n topics.set(topic, []);\n }\n },\n\n deleteTopic(topic: string) {\n topics.delete(topic);\n },\n\n listTopics() {\n return [...topics.keys()];\n },\n };\n}\n\n// ============================================================================\n// Context Propagation Helpers\n// ============================================================================\n\n/**\n * Extract trace ID from traceparent header\n */\nexport function extractTraceIdFromHeader(traceparent: string): string | null {\n const parts = traceparent.split('-');\n if (parts.length >= 3 && parts[1] !== undefined) {\n return parts[1];\n }\n return null;\n}\n\n/**\n * Extract span ID from traceparent header\n */\nexport function extractSpanIdFromHeader(traceparent: string): string | null {\n const parts = traceparent.split('-');\n if (parts.length >= 4 && parts[2] !== undefined) {\n return parts[2];\n }\n return null;\n}\n\n/**\n * Create a mock span context\n */\nexport function createMockSpanContext(\n traceId?: string,\n spanId?: string,\n): SpanContext {\n return {\n traceId: traceId ?? randomHex(32),\n spanId: spanId ?? randomHex(16),\n traceFlags: 1,\n isRemote: true,\n };\n}\n\n/**\n * Create a mock link to a producer span\n */\nexport function createMockProducerLink(\n traceId?: string,\n spanId?: string,\n): Link {\n return {\n context: createMockSpanContext(traceId, spanId),\n attributes: {\n 'messaging.link.source': 'producer',\n },\n };\n}\n\n// ============================================================================\n// Scenario Builders\n// ============================================================================\n\n/**\n * Create a batch of mock messages\n */\nexport function createMockMessageBatch<T>(\n payloads: T[],\n options: {\n startOffset?: number;\n partition?: number;\n addTraceHeaders?: boolean;\n traceId?: string;\n } = {},\n): MockMessage<T>[] {\n const startOffset = options.startOffset ?? 0;\n const addTraceHeaders = options.addTraceHeaders ?? true;\n const traceId = options.traceId ?? randomHex(32);\n\n return payloads.map((payload, index) => ({\n payload,\n headers: addTraceHeaders\n ? { traceparent: `00-${traceId}-${randomHex(16)}-01` }\n : undefined,\n offset: startOffset + index,\n partition: options.partition ?? 0,\n messageId: `msg-${randomHex(8)}`,\n timestamp: Date.now() + index,\n }));\n}\n\n/**\n * Create a rebalance scenario\n */\nexport function createRebalanceScenario(\n topic: string,\n consumerGroup: string,\n partitions: number[],\n): {\n assignEvent: RecordedRebalanceEvent;\n revokeEvent: RecordedRebalanceEvent;\n} {\n const assignments: PartitionAssignment[] = partitions.map((p) => ({\n topic,\n partition: p,\n offset: 0,\n }));\n\n return {\n assignEvent: {\n type: 'assigned',\n partitions: assignments,\n timestamp: Date.now(),\n generation: 1,\n destination: topic,\n consumerGroup,\n },\n revokeEvent: {\n type: 'revoked',\n partitions: assignments,\n timestamp: Date.now() + 1000,\n generation: 2,\n destination: topic,\n consumerGroup,\n },\n };\n}\n\n/**\n * Create an out-of-order scenario\n */\nexport function createOutOfOrderScenario<T>(\n payloads: T[],\n outOfOrderIndices: number[],\n): MockMessage<T>[] {\n const messages = createMockMessageBatch(payloads, { addTraceHeaders: true });\n\n // Shuffle specified indices to create out-of-order scenario\n const shuffled = [...messages];\n for (const index of outOfOrderIndices) {\n if (index > 0 && index < shuffled.length) {\n // Swap with previous to create out-of-order\n const prev = shuffled[index - 1]!;\n const curr = shuffled[index]!;\n shuffled[index - 1] = curr;\n shuffled[index] = prev;\n }\n }\n\n return shuffled;\n}\n\n/**\n * Create a duplicate message scenario\n */\nexport function createDuplicateScenario<T>(\n payloads: T[],\n duplicateIndices: number[],\n): MockMessage<T>[] {\n const messages = createMockMessageBatch(payloads, { addTraceHeaders: true });\n const result = [...messages];\n\n for (const index of duplicateIndices) {\n const originalMessage = messages[index];\n if (index >= 0 && index < messages.length && originalMessage) {\n // Insert duplicate after the original\n result.splice(index + 1, 0, { ...originalMessage });\n }\n }\n\n return result;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/messaging-testing.ts"],"names":[],"mappings":"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","file":"messaging-testing.js","sourcesContent":["/**\n * Testing utilities for messaging instrumentation\n *\n * Provides mock producers, consumers, and assertion helpers\n * for testing event-driven code with Autotel's messaging module.\n *\n * @example Basic test setup\n * ```typescript\n * import { createMessagingTestHarness } from 'autotel/messaging-testing';\n *\n * describe('Order processing', () => {\n * const harness = createMessagingTestHarness();\n *\n * beforeEach(() => harness.reset());\n * afterAll(() => harness.shutdown());\n *\n * it('should process order and publish event', async () => {\n * await processOrder({ id: 'order-123' });\n *\n * harness.assertProducerCalled('orders', {\n * messageCount: 1,\n * hasTraceHeaders: true,\n * });\n * });\n * });\n * ```\n *\n * @module\n */\n\nimport type { Link, SpanContext } from '@opentelemetry/api';\nimport type {\n RebalanceEvent,\n PartitionAssignment,\n OutOfOrderInfo,\n} from './messaging';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * Recorded producer call\n */\nexport interface RecordedProducerCall {\n /** Destination (topic/queue) */\n destination: string;\n\n /** System (kafka, sqs, etc.) */\n system: string;\n\n /** Message payload */\n payload: unknown;\n\n /** Headers injected */\n headers: Record<string, string>;\n\n /** Timestamp of call */\n timestamp: number;\n\n /** Trace ID from headers */\n traceId?: string;\n\n /** Span ID from headers */\n spanId?: string;\n}\n\n/**\n * Recorded consumer call\n */\nexport interface RecordedConsumerCall {\n /** Destination (topic/queue) */\n destination: string;\n\n /** System (kafka, sqs, etc.) */\n system: string;\n\n /** Consumer group */\n consumerGroup?: string;\n\n /** Message payload */\n payload: unknown;\n\n /** Headers extracted */\n headers?: Record<string, string>;\n\n /** Timestamp of call */\n timestamp: number;\n\n /** Producer links extracted */\n producerLinks: Link[];\n\n /** Whether message was duplicate */\n isDuplicate: boolean;\n\n /** Out of order info if detected */\n outOfOrderInfo: OutOfOrderInfo | null;\n\n /** DLQ reason if routed to DLQ */\n dlqReason?: string;\n\n /** Retry attempt number */\n retryAttempt?: number;\n}\n\n/**\n * Recorded rebalance event\n */\nexport interface RecordedRebalanceEvent extends RebalanceEvent {\n /** Destination (topic) */\n destination: string;\n\n /** Consumer group */\n consumerGroup: string;\n}\n\n/**\n * Mock message for testing\n */\nexport interface MockMessage<T = unknown> {\n /** Message payload */\n payload: T;\n\n /** Headers */\n headers?: Record<string, string>;\n\n /** Offset/sequence number */\n offset?: number;\n\n /** Partition */\n partition?: number;\n\n /** Key */\n key?: string;\n\n /** Message ID */\n messageId?: string;\n\n /** Timestamp */\n timestamp?: number;\n}\n\n/**\n * Producer assertion options\n */\nexport interface ProducerAssertionOptions {\n /** Expected number of messages */\n messageCount?: number;\n\n /** Whether trace headers should be present */\n hasTraceHeaders?: boolean;\n\n /** Expected destination */\n destination?: string;\n\n /** Custom matcher for payload */\n payloadMatcher?: (payload: unknown) => boolean;\n\n /** Expected trace ID */\n traceId?: string;\n}\n\n/**\n * Consumer assertion options\n */\nexport interface ConsumerAssertionOptions {\n /** Expected number of messages processed */\n messageCount?: number;\n\n /** Whether producer links should be present */\n hasProducerLinks?: boolean;\n\n /** Expected destination */\n destination?: string;\n\n /** Expected consumer group */\n consumerGroup?: string;\n\n /** Whether any messages were duplicates */\n hasDuplicates?: boolean;\n\n /** Whether any messages were out of order */\n hasOutOfOrder?: boolean;\n\n /** Whether any messages went to DLQ */\n hasDLQ?: boolean;\n}\n\n/**\n * Messaging test harness\n */\nexport interface MessagingTestHarness {\n /** All recorded producer calls */\n producerCalls: RecordedProducerCall[];\n\n /** All recorded consumer calls */\n consumerCalls: RecordedConsumerCall[];\n\n /** All recorded rebalance events */\n rebalanceEvents: RecordedRebalanceEvent[];\n\n /**\n * Record a producer call\n */\n recordProducerCall(call: Omit<RecordedProducerCall, 'timestamp'>): void;\n\n /**\n * Record a consumer call\n */\n recordConsumerCall(call: Omit<RecordedConsumerCall, 'timestamp'>): void;\n\n /**\n * Record a rebalance event\n */\n recordRebalanceEvent(event: RecordedRebalanceEvent): void;\n\n /**\n * Create a mock message with trace headers\n */\n createMockMessage<T>(\n payload: T,\n options?: Partial<MockMessage<T>>,\n ): MockMessage<T>;\n\n /**\n * Create mock trace headers\n */\n createMockTraceHeaders(\n traceId?: string,\n spanId?: string,\n ): Record<string, string>;\n\n /**\n * Assert producer was called with expected options\n */\n assertProducerCalled(\n destination: string,\n options?: ProducerAssertionOptions,\n ): void;\n\n /**\n * Assert producer was not called\n */\n assertProducerNotCalled(destination?: string): void;\n\n /**\n * Assert consumer processed messages with expected options\n */\n assertConsumerProcessed(\n destination: string,\n options?: ConsumerAssertionOptions,\n ): void;\n\n /**\n * Assert consumer was not called\n */\n assertConsumerNotCalled(destination?: string): void;\n\n /**\n * Assert rebalance occurred\n */\n assertRebalanceOccurred(\n destination: string,\n type: RebalanceEvent['type'],\n partitionCount?: number,\n ): void;\n\n /**\n * Get producer calls for destination\n */\n getProducerCalls(destination?: string): RecordedProducerCall[];\n\n /**\n * Get consumer calls for destination\n */\n getConsumerCalls(destination?: string): RecordedConsumerCall[];\n\n /**\n * Get the last producer call\n */\n getLastProducerCall(destination?: string): RecordedProducerCall | undefined;\n\n /**\n * Get the last consumer call\n */\n getLastConsumerCall(destination?: string): RecordedConsumerCall | undefined;\n\n /**\n * Reset all recorded calls\n */\n reset(): void;\n\n /**\n * Shutdown the harness\n */\n shutdown(): void;\n}\n\n// ============================================================================\n// Implementation\n// ============================================================================\n\n/**\n * Generate a random hex string\n */\nfunction randomHex(length: number): string {\n let result = '';\n const chars = '0123456789abcdef';\n for (let i = 0; i < length; i++) {\n result += chars.charAt(Math.floor(Math.random() * chars.length));\n }\n return result;\n}\n\n/**\n * Create a messaging test harness\n *\n * Provides utilities for recording and asserting on producer/consumer calls\n * during testing.\n *\n * @example\n * ```typescript\n * const harness = createMessagingTestHarness();\n *\n * // In your test setup\n * beforeEach(() => harness.reset());\n *\n * // In your tests\n * it('should publish order event', async () => {\n * await orderService.createOrder({ id: '123' });\n *\n * harness.assertProducerCalled('orders', {\n * messageCount: 1,\n * hasTraceHeaders: true,\n * });\n *\n * const lastCall = harness.getLastProducerCall('orders');\n * expect(lastCall?.payload).toMatchObject({ orderId: '123' });\n * });\n * ```\n */\nexport function createMessagingTestHarness(): MessagingTestHarness {\n const producerCalls: RecordedProducerCall[] = [];\n const consumerCalls: RecordedConsumerCall[] = [];\n const rebalanceEvents: RecordedRebalanceEvent[] = [];\n\n return {\n producerCalls,\n consumerCalls,\n rebalanceEvents,\n\n recordProducerCall(call) {\n producerCalls.push({\n ...call,\n timestamp: Date.now(),\n });\n },\n\n recordConsumerCall(call) {\n consumerCalls.push({\n ...call,\n timestamp: Date.now(),\n });\n },\n\n recordRebalanceEvent(event) {\n rebalanceEvents.push(event);\n },\n\n createMockMessage<T>(\n payload: T,\n options: Partial<MockMessage<T>> = {},\n ): MockMessage<T> {\n return {\n payload,\n headers: options.headers ?? this.createMockTraceHeaders(),\n offset: options.offset ?? Math.floor(Math.random() * 10_000),\n partition: options.partition ?? 0,\n key: options.key,\n messageId: options.messageId ?? `msg-${randomHex(8)}`,\n timestamp: options.timestamp ?? Date.now(),\n };\n },\n\n createMockTraceHeaders(\n traceId?: string,\n spanId?: string,\n ): Record<string, string> {\n const tid = traceId ?? randomHex(32);\n const sid = spanId ?? randomHex(16);\n return {\n traceparent: `00-${tid}-${sid}-01`,\n };\n },\n\n assertProducerCalled(\n destination: string,\n options: ProducerAssertionOptions = {},\n ) {\n const calls = producerCalls.filter((c) => c.destination === destination);\n\n if (calls.length === 0) {\n throw new Error(\n `Expected producer to be called for destination '${destination}', but it was not called`,\n );\n }\n\n if (\n options.messageCount !== undefined &&\n calls.length !== options.messageCount\n ) {\n throw new Error(\n `Expected ${options.messageCount} producer calls for '${destination}', got ${calls.length}`,\n );\n }\n\n if (options.hasTraceHeaders) {\n const withoutHeaders = calls.filter((c) => !c.headers?.traceparent);\n if (withoutHeaders.length > 0) {\n throw new Error(\n `Expected all producer calls for '${destination}' to have trace headers, but ${withoutHeaders.length} did not`,\n );\n }\n }\n\n if (options.traceId) {\n const matchingTraceId = calls.filter(\n (c) => c.traceId === options.traceId,\n );\n if (matchingTraceId.length === 0) {\n throw new Error(\n `Expected producer call for '${destination}' with traceId '${options.traceId}', but none found`,\n );\n }\n }\n\n if (options.payloadMatcher) {\n const matching = calls.filter((c) =>\n options.payloadMatcher!(c.payload),\n );\n if (matching.length === 0) {\n throw new Error(\n `Expected producer call for '${destination}' to match payload matcher, but none did`,\n );\n }\n }\n },\n\n assertProducerNotCalled(destination?: string) {\n if (destination) {\n const calls = producerCalls.filter(\n (c) => c.destination === destination,\n );\n if (calls.length > 0) {\n throw new Error(\n `Expected producer not to be called for '${destination}', but it was called ${calls.length} times`,\n );\n }\n } else {\n if (producerCalls.length > 0) {\n throw new Error(\n `Expected no producer calls, but ${producerCalls.length} calls were made`,\n );\n }\n }\n },\n\n assertConsumerProcessed(\n destination: string,\n options: ConsumerAssertionOptions = {},\n ) {\n const calls = consumerCalls.filter((c) => c.destination === destination);\n\n if (calls.length === 0) {\n throw new Error(\n `Expected consumer to process messages for destination '${destination}', but none were processed`,\n );\n }\n\n if (\n options.messageCount !== undefined &&\n calls.length !== options.messageCount\n ) {\n throw new Error(\n `Expected ${options.messageCount} consumer calls for '${destination}', got ${calls.length}`,\n );\n }\n\n if (options.consumerGroup) {\n const wrongGroup = calls.filter(\n (c) => c.consumerGroup !== options.consumerGroup,\n );\n if (wrongGroup.length > 0) {\n throw new Error(\n `Expected consumer group '${options.consumerGroup}' for '${destination}', but found different groups`,\n );\n }\n }\n\n if (options.hasProducerLinks) {\n const withoutLinks = calls.filter((c) => c.producerLinks.length === 0);\n if (withoutLinks.length > 0) {\n throw new Error(\n `Expected all consumer calls for '${destination}' to have producer links, but ${withoutLinks.length} did not`,\n );\n }\n }\n\n if (options.hasDuplicates !== undefined) {\n const duplicates = calls.filter((c) => c.isDuplicate);\n if (options.hasDuplicates && duplicates.length === 0) {\n throw new Error(\n `Expected duplicate messages for '${destination}', but none were detected`,\n );\n }\n if (!options.hasDuplicates && duplicates.length > 0) {\n throw new Error(\n `Expected no duplicate messages for '${destination}', but ${duplicates.length} were detected`,\n );\n }\n }\n\n if (options.hasOutOfOrder !== undefined) {\n const outOfOrder = calls.filter((c) => c.outOfOrderInfo !== null);\n if (options.hasOutOfOrder && outOfOrder.length === 0) {\n throw new Error(\n `Expected out-of-order messages for '${destination}', but none were detected`,\n );\n }\n if (!options.hasOutOfOrder && outOfOrder.length > 0) {\n throw new Error(\n `Expected no out-of-order messages for '${destination}', but ${outOfOrder.length} were detected`,\n );\n }\n }\n\n if (options.hasDLQ !== undefined) {\n const dlqCalls = calls.filter((c) => c.dlqReason !== undefined);\n if (options.hasDLQ && dlqCalls.length === 0) {\n throw new Error(\n `Expected DLQ routing for '${destination}', but none occurred`,\n );\n }\n if (!options.hasDLQ && dlqCalls.length > 0) {\n throw new Error(\n `Expected no DLQ routing for '${destination}', but ${dlqCalls.length} occurred`,\n );\n }\n }\n },\n\n assertConsumerNotCalled(destination?: string) {\n if (destination) {\n const calls = consumerCalls.filter(\n (c) => c.destination === destination,\n );\n if (calls.length > 0) {\n throw new Error(\n `Expected consumer not to be called for '${destination}', but it processed ${calls.length} messages`,\n );\n }\n } else {\n if (consumerCalls.length > 0) {\n throw new Error(\n `Expected no consumer calls, but ${consumerCalls.length} messages were processed`,\n );\n }\n }\n },\n\n assertRebalanceOccurred(\n destination: string,\n type: RebalanceEvent['type'],\n partitionCount?: number,\n ) {\n const events = rebalanceEvents.filter(\n (e) => e.destination === destination && e.type === type,\n );\n\n if (events.length === 0) {\n throw new Error(\n `Expected rebalance '${type}' for '${destination}', but none occurred`,\n );\n }\n\n if (partitionCount !== undefined) {\n const matching = events.filter(\n (e) => e.partitions.length === partitionCount,\n );\n if (matching.length === 0) {\n throw new Error(\n `Expected rebalance '${type}' for '${destination}' with ${partitionCount} partitions, but none matched`,\n );\n }\n }\n },\n\n getProducerCalls(destination?: string) {\n if (destination) {\n return producerCalls.filter((c) => c.destination === destination);\n }\n return [...producerCalls];\n },\n\n getConsumerCalls(destination?: string) {\n if (destination) {\n return consumerCalls.filter((c) => c.destination === destination);\n }\n return [...consumerCalls];\n },\n\n getLastProducerCall(destination?: string) {\n const calls = this.getProducerCalls(destination);\n return calls.at(-1);\n },\n\n getLastConsumerCall(destination?: string) {\n const calls = this.getConsumerCalls(destination);\n return calls.at(-1);\n },\n\n reset() {\n producerCalls.length = 0;\n consumerCalls.length = 0;\n rebalanceEvents.length = 0;\n },\n\n shutdown() {\n this.reset();\n },\n };\n}\n\n// ============================================================================\n// Mock Broker\n// ============================================================================\n\n/**\n * Mock message broker for testing\n */\nexport interface MockMessageBroker {\n /** Topics/queues in the broker */\n topics: Map<string, MockMessage[]>;\n\n /**\n * Publish a message to a topic\n */\n publish(topic: string, message: MockMessage): void;\n\n /**\n * Consume messages from a topic\n */\n consume(topic: string, count?: number): MockMessage[];\n\n /**\n * Peek at messages without consuming\n */\n peek(topic: string, count?: number): MockMessage[];\n\n /**\n * Get message count for topic\n */\n getMessageCount(topic: string): number;\n\n /**\n * Clear all messages\n */\n clear(topic?: string): void;\n\n /**\n * Create a topic\n */\n createTopic(topic: string): void;\n\n /**\n * Delete a topic\n */\n deleteTopic(topic: string): void;\n\n /**\n * List all topics\n */\n listTopics(): string[];\n}\n\n/**\n * Create a mock message broker for testing\n *\n * Simulates a message broker (Kafka, SQS, RabbitMQ, etc.) for unit testing.\n *\n * @example\n * ```typescript\n * const broker = createMockMessageBroker();\n *\n * // Producer publishes\n * broker.publish('orders', { payload: { orderId: '123' }, headers: {} });\n *\n * // Consumer receives\n * const messages = broker.consume('orders');\n * expect(messages).toHaveLength(1);\n * expect(messages[0].payload).toEqual({ orderId: '123' });\n * ```\n */\nexport function createMockMessageBroker(): MockMessageBroker {\n const topics = new Map<string, MockMessage[]>();\n\n return {\n topics,\n\n publish(topic: string, message: MockMessage) {\n if (!topics.has(topic)) {\n topics.set(topic, []);\n }\n topics.get(topic)!.push({\n ...message,\n timestamp: message.timestamp ?? Date.now(),\n offset: message.offset ?? topics.get(topic)!.length,\n });\n },\n\n consume(topic: string, count?: number) {\n const messages = topics.get(topic) ?? [];\n if (count === undefined) {\n const all = [...messages];\n messages.length = 0;\n return all;\n }\n return messages.splice(0, count);\n },\n\n peek(topic: string, count?: number) {\n const messages = topics.get(topic) ?? [];\n if (count === undefined) {\n return [...messages];\n }\n return messages.slice(0, count);\n },\n\n getMessageCount(topic: string) {\n return topics.get(topic)?.length ?? 0;\n },\n\n clear(topic?: string) {\n if (topic) {\n topics.set(topic, []);\n } else {\n topics.clear();\n }\n },\n\n createTopic(topic: string) {\n if (!topics.has(topic)) {\n topics.set(topic, []);\n }\n },\n\n deleteTopic(topic: string) {\n topics.delete(topic);\n },\n\n listTopics() {\n return [...topics.keys()];\n },\n };\n}\n\n// ============================================================================\n// Context Propagation Helpers\n// ============================================================================\n\n/**\n * Extract trace ID from traceparent header\n */\nexport function extractTraceIdFromHeader(traceparent: string): string | null {\n const parts = traceparent.split('-');\n if (parts.length >= 3 && parts[1] !== undefined) {\n return parts[1];\n }\n return null;\n}\n\n/**\n * Extract span ID from traceparent header\n */\nexport function extractSpanIdFromHeader(traceparent: string): string | null {\n const parts = traceparent.split('-');\n if (parts.length >= 4 && parts[2] !== undefined) {\n return parts[2];\n }\n return null;\n}\n\n/**\n * Create a mock span context\n */\nexport function createMockSpanContext(\n traceId?: string,\n spanId?: string,\n): SpanContext {\n return {\n traceId: traceId ?? randomHex(32),\n spanId: spanId ?? randomHex(16),\n traceFlags: 1,\n isRemote: true,\n };\n}\n\n/**\n * Create a mock link to a producer span\n */\nexport function createMockProducerLink(\n traceId?: string,\n spanId?: string,\n): Link {\n return {\n context: createMockSpanContext(traceId, spanId),\n attributes: {\n 'messaging.link.source': 'producer',\n },\n };\n}\n\n// ============================================================================\n// Scenario Builders\n// ============================================================================\n\n/**\n * Create a batch of mock messages\n */\nexport function createMockMessageBatch<T>(\n payloads: T[],\n options: {\n startOffset?: number;\n partition?: number;\n addTraceHeaders?: boolean;\n traceId?: string;\n } = {},\n): MockMessage<T>[] {\n const startOffset = options.startOffset ?? 0;\n const addTraceHeaders = options.addTraceHeaders ?? true;\n const traceId = options.traceId ?? randomHex(32);\n\n return payloads.map((payload, index) => ({\n payload,\n headers: addTraceHeaders\n ? { traceparent: `00-${traceId}-${randomHex(16)}-01` }\n : undefined,\n offset: startOffset + index,\n partition: options.partition ?? 0,\n messageId: `msg-${randomHex(8)}`,\n timestamp: Date.now() + index,\n }));\n}\n\n/**\n * Create a rebalance scenario\n */\nexport function createRebalanceScenario(\n topic: string,\n consumerGroup: string,\n partitions: number[],\n): {\n assignEvent: RecordedRebalanceEvent;\n revokeEvent: RecordedRebalanceEvent;\n} {\n const assignments: PartitionAssignment[] = partitions.map((p) => ({\n topic,\n partition: p,\n offset: 0,\n }));\n\n return {\n assignEvent: {\n type: 'assigned',\n partitions: assignments,\n timestamp: Date.now(),\n generation: 1,\n destination: topic,\n consumerGroup,\n },\n revokeEvent: {\n type: 'revoked',\n partitions: assignments,\n timestamp: Date.now() + 1000,\n generation: 2,\n destination: topic,\n consumerGroup,\n },\n };\n}\n\n/**\n * Create an out-of-order scenario\n */\nexport function createOutOfOrderScenario<T>(\n payloads: T[],\n outOfOrderIndices: number[],\n): MockMessage<T>[] {\n const messages = createMockMessageBatch(payloads, { addTraceHeaders: true });\n\n // Shuffle specified indices to create out-of-order scenario\n const shuffled = [...messages];\n for (const index of outOfOrderIndices) {\n if (index > 0 && index < shuffled.length) {\n // Swap with previous to create out-of-order\n const prev = shuffled[index - 1]!;\n const curr = shuffled[index]!;\n shuffled[index - 1] = curr;\n shuffled[index] = prev;\n }\n }\n\n return shuffled;\n}\n\n/**\n * Create a duplicate message scenario\n */\nexport function createDuplicateScenario<T>(\n payloads: T[],\n duplicateIndices: number[],\n): MockMessage<T>[] {\n const messages = createMockMessageBatch(payloads, { addTraceHeaders: true });\n const result = [...messages];\n\n for (const index of duplicateIndices) {\n const originalMessage = messages[index];\n if (index >= 0 && index < messages.length && originalMessage) {\n // Insert duplicate after the original\n result.splice(index + 1, 0, { ...originalMessage });\n }\n }\n\n return result;\n}\n"]}
|
package/dist/messaging.cjs
CHANGED
|
@@ -1,39 +1,38 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkLOTJ7SDI_cjs = require('./chunk-LOTJ7SDI.cjs');
|
|
4
4
|
require('./chunk-4P6ZOARG.cjs');
|
|
5
|
-
require('./chunk-
|
|
6
|
-
require('./chunk-
|
|
5
|
+
require('./chunk-VNMT2TDZ.cjs');
|
|
6
|
+
require('./chunk-BGAR6MCX.cjs');
|
|
7
7
|
require('./chunk-VQTCQKHQ.cjs');
|
|
8
|
-
require('./chunk-
|
|
9
|
-
require('./chunk-
|
|
10
|
-
require('./chunk-
|
|
8
|
+
require('./chunk-KAELJC6T.cjs');
|
|
9
|
+
require('./chunk-ISEHXVMD.cjs');
|
|
10
|
+
require('./chunk-BTEPYWDF.cjs');
|
|
11
11
|
require('./chunk-CEAQK2QY.cjs');
|
|
12
12
|
require('./chunk-ZNMBW67B.cjs');
|
|
13
13
|
require('./chunk-IOYFAFHJ.cjs');
|
|
14
14
|
require('./chunk-NXLRY2CE.cjs');
|
|
15
15
|
require('./chunk-CU6IDACR.cjs');
|
|
16
16
|
require('./chunk-6S5RUKU3.cjs');
|
|
17
|
-
require('./chunk-
|
|
17
|
+
require('./chunk-EQIY6C3X.cjs');
|
|
18
18
|
require('./chunk-VH77IPJN.cjs');
|
|
19
19
|
require('./chunk-FU6R566Y.cjs');
|
|
20
20
|
require('./chunk-ESLWRGAG.cjs');
|
|
21
21
|
require('./chunk-YREV3LGG.cjs');
|
|
22
|
-
require('./chunk-JEQ2X3Z6.cjs');
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
|
|
26
25
|
Object.defineProperty(exports, "clearOrderingState", {
|
|
27
26
|
enumerable: true,
|
|
28
|
-
get: function () { return
|
|
27
|
+
get: function () { return chunkLOTJ7SDI_cjs.clearOrderingState; }
|
|
29
28
|
});
|
|
30
29
|
Object.defineProperty(exports, "traceConsumer", {
|
|
31
30
|
enumerable: true,
|
|
32
|
-
get: function () { return
|
|
31
|
+
get: function () { return chunkLOTJ7SDI_cjs.traceConsumer; }
|
|
33
32
|
});
|
|
34
33
|
Object.defineProperty(exports, "traceProducer", {
|
|
35
34
|
enumerable: true,
|
|
36
|
-
get: function () { return
|
|
35
|
+
get: function () { return chunkLOTJ7SDI_cjs.traceProducer; }
|
|
37
36
|
});
|
|
38
37
|
//# sourceMappingURL=messaging.cjs.map
|
|
39
38
|
//# sourceMappingURL=messaging.cjs.map
|
package/dist/messaging.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
export { clearOrderingState, traceConsumer, traceProducer } from './chunk-
|
|
1
|
+
export { clearOrderingState, traceConsumer, traceProducer } from './chunk-KGBRZ7J5.js';
|
|
2
2
|
import './chunk-KIL5CUN6.js';
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
3
|
+
import './chunk-JITYRSI4.js';
|
|
4
|
+
import './chunk-MBEHEGQE.js';
|
|
5
5
|
import './chunk-SEO6NAQT.js';
|
|
6
|
-
import './chunk-
|
|
7
|
-
import './chunk-
|
|
8
|
-
import './chunk-
|
|
6
|
+
import './chunk-IC4AZUGC.js';
|
|
7
|
+
import './chunk-SIMG4IGE.js';
|
|
8
|
+
import './chunk-7NDHLHZK.js';
|
|
9
9
|
import './chunk-A4E5AQFK.js';
|
|
10
10
|
import './chunk-WGWSHJ2N.js';
|
|
11
11
|
import './chunk-GYR5K654.js';
|
|
12
12
|
import './chunk-JVWJDHDB.js';
|
|
13
13
|
import './chunk-6UQRVUN3.js';
|
|
14
14
|
import './chunk-3QXBFGKP.js';
|
|
15
|
-
import './chunk-
|
|
15
|
+
import './chunk-KPNV2GPW.js';
|
|
16
16
|
import './chunk-DPSA4QLA.js';
|
|
17
17
|
import './chunk-55ER2KD5.js';
|
|
18
18
|
import './chunk-J5QENANM.js';
|
|
19
19
|
import './chunk-HA2WBOGQ.js';
|
|
20
|
-
import './chunk-DGUM43GV.js';
|
|
21
20
|
//# sourceMappingURL=messaging.js.map
|
|
22
21
|
//# sourceMappingURL=messaging.js.map
|
package/dist/metric-helpers.cjs
CHANGED
package/dist/metric-helpers.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { createCounter, createHistogram, createObservableGauge, createUpDownCounter, getMeter } from './chunk-TQ5UWA7S.js';
|
|
2
2
|
import './chunk-J5QENANM.js';
|
|
3
3
|
import './chunk-HA2WBOGQ.js';
|
|
4
|
-
import './chunk-DGUM43GV.js';
|
|
5
4
|
//# sourceMappingURL=metric-helpers.js.map
|
|
6
5
|
//# sourceMappingURL=metric-helpers.js.map
|
package/dist/metric-testing.cjs
CHANGED
package/dist/metric-testing.js
CHANGED