// tools/generate-tests/generators/otel-test-generator.ts — SPEC-044
// Generates instrumentation test scaffolds for projects with OpenTelemetry.
/**
 * Returns true when the project has OTel installed.
 */
export function isOtelProject(knowledge) {
    return knowledge.otelDetection?.isInstalled === true;
}
/**
 * Generate OTel instrumentation test definitions.
 */
export function generateOtelTestDefs(title, testDir) {
    return [
        {
            name: `${title} — OTel: HTTP call genera span con atributos correctos`,
            type: 'integration',
            file: `${testDir}/instrumentation/`,
            description: 'Verificar que un HTTP call outbound genera un span con los atributos W3C TraceContext correctos',
            priority: 'critical',
            automatable: true,
        },
        {
            name: `${title} — OTel: trace_id y span_id presentes en logs`,
            type: 'unit',
            file: `${testDir}/instrumentation/`,
            description: 'Verificar que los log entries incluyen trace_id y span_id del span activo',
            priority: 'high',
            automatable: true,
        },
        {
            name: `${title} — OTel: métricas HTTP registradas con dimensiones correctas`,
            type: 'integration',
            file: `${testDir}/instrumentation/`,
            description: 'Verificar histograma http.server.request.duration con dimensiones http.method, http.status_code, http.route',
            priority: 'high',
            automatable: true,
        },
        {
            name: `${title} — OTel: servicio continúa operando sin Collector`,
            type: 'integration',
            file: `${testDir}/instrumentation/`,
            description: 'Verificar que el servicio no crashea cuando el OTel Collector no está disponible',
            priority: 'critical',
            automatable: true,
        },
    ];
}
// === Language-specific test content generators ===
function generateNodeOtelTest(title) {
    const slug = title.toLowerCase().replace(/\s+/g, '-');
    return `// Instrumentation tests for ${title} — OpenTelemetry
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import {
  NodeTracerProvider,
  InMemorySpanExporter,
  SimpleSpanProcessor,
} from '@opentelemetry/sdk-node';
import { trace, context } from '@opentelemetry/api';

// In-memory exporter for verifying spans in tests
const memoryExporter = new InMemorySpanExporter();
const provider = new NodeTracerProvider();
provider.addSpanProcessor(new SimpleSpanProcessor(memoryExporter));
provider.register();

const tracer = trace.getTracer('${slug}-test');

describe('${title} — OTel Instrumentation', () => {
  beforeAll(() => {
    memoryExporter.reset();
  });

  afterAll(() => {
    provider.shutdown();
  });

  it('HTTP call generates span with correct attributes', async () => {
    const span = tracer.startSpan('test-operation');
    const ctx = trace.setSpan(context.active(), span);

    // Perform the operation inside the span context
    context.with(ctx, () => {
      // TODO: call your HTTP client here
      // e.g. await httpClient.get('/your-endpoint');
    });

    span.end();

    const spans = memoryExporter.getFinishedSpans();
    expect(spans.length).toBeGreaterThan(0);
    const testSpan = spans.find((s) => s.name === 'test-operation');
    expect(testSpan).toBeDefined();
  });

  it('span has trace_id and span_id accessible for logs', async () => {
    const span = tracer.startSpan('log-context-test');
    const ctx = trace.setSpan(context.active(), span);

    let capturedTraceId: string | undefined;
    let capturedSpanId: string | undefined;

    context.with(ctx, () => {
      const activeSpan = trace.getActiveSpan();
      capturedTraceId = activeSpan?.spanContext().traceId;
      capturedSpanId = activeSpan?.spanContext().spanId;
    });

    span.end();

    expect(capturedTraceId).toBeDefined();
    expect(capturedTraceId).toHaveLength(32); // 128-bit trace ID as hex
    expect(capturedSpanId).toBeDefined();
    expect(capturedSpanId).toHaveLength(16); // 64-bit span ID as hex
  });

  it('service continues operating when Collector is unavailable', async () => {
    // The @opentelemetry/exporter-trace-otlp-http should not crash the service
    // when the endpoint is unreachable — it drops spans gracefully
    const span = tracer.startSpan('resilience-test');
    expect(() => span.end()).not.toThrow();
  });
});
`;
}
function generatePythonOtelTest(title) {
    const slug = title.toLowerCase().replace(/ /g, '_');
    return `"""Instrumentation tests for ${title} — OpenTelemetry."""
import pytest
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
from opentelemetry.sdk.trace.export import SimpleSpanProcessor


@pytest.fixture
def tracer_provider() -> TracerProvider:
    """Set up in-memory TracerProvider for tests."""
    exporter = InMemorySpanExporter()
    provider = TracerProvider()
    provider.add_span_processor(SimpleSpanProcessor(exporter))
    trace.set_tracer_provider(provider)
    yield provider
    exporter.clear()


@pytest.fixture
def memory_exporter(tracer_provider: TracerProvider) -> InMemorySpanExporter:
    for processor in tracer_provider._active_span_processor._span_processors:
        if hasattr(processor, 'span_exporter'):
            return processor.span_exporter
    return InMemorySpanExporter()


def test_${slug}_span_has_correct_attributes(memory_exporter: InMemorySpanExporter) -> None:
    """HTTP operation generates a span with correct OTel attributes."""
    tracer = trace.get_tracer("${slug}-test")
    with tracer.start_as_current_span("test-operation") as span:
        span.set_attribute("http.method", "GET")
        span.set_attribute("http.url", "/your-endpoint")

    spans = memory_exporter.get_finished_spans()
    assert len(spans) > 0
    test_span = next((s for s in spans if s.name == "test-operation"), None)
    assert test_span is not None
    assert test_span.attributes.get("http.method") == "GET"


def test_${slug}_trace_id_in_context(tracer_provider: TracerProvider) -> None:
    """Active span provides trace_id and span_id for log correlation."""
    tracer = trace.get_tracer("${slug}-test")
    with tracer.start_as_current_span("log-context") as span:
        ctx = span.get_span_context()
        assert ctx.trace_id != 0
        assert ctx.span_id != 0
`;
}
function generateGoOtelTest(title) {
    const pkg = title.toLowerCase().replace(/\s+/g, '_');
    return `// Instrumentation tests for ${title} — OpenTelemetry
package ${pkg}_test

import (
\t"context"
\t"testing"

\t"go.opentelemetry.io/otel"
\t"go.opentelemetry.io/otel/sdk/trace"
\t"go.opentelemetry.io/otel/sdk/trace/tracetest"
)

func TestSpanHasCorrectAttributes(t *testing.T) {
\t// Set up in-memory exporter
\texporter := tracetest.NewInMemoryExporter()
\tprovider := trace.NewTracerProvider(
\t\ttrace.WithSyncer(exporter),
\t)
\totel.SetTracerProvider(provider)
\tdefer provider.Shutdown(context.Background()) //nolint:errcheck

\ttracer := otel.Tracer("${pkg}-test")
\tctx, span := tracer.Start(context.Background(), "test-operation")
\tspan.End()
\t_ = ctx

\tspans := exporter.GetSpans()
\tif len(spans) == 0 {
\t\tt.Error("expected at least one span to be recorded")
\t}
\tif spans[0].Name != "test-operation" {
\t\tt.Errorf("expected span name 'test-operation', got '%s'", spans[0].Name)
\t}
}

func TestTraceIDAvailableForLogs(t *testing.T) {
\texporter := tracetest.NewInMemoryExporter()
\tprovider := trace.NewTracerProvider(trace.WithSyncer(exporter))
\totel.SetTracerProvider(provider)
\tdefer provider.Shutdown(context.Background()) //nolint:errcheck

\ttracer := otel.Tracer("${pkg}-test")
\tctx, span := tracer.Start(context.Background(), "log-context")
\tdefer span.End()

\tsc := trace.SpanFromContext(ctx).SpanContext()
\tif !sc.IsValid() {
\t\tt.Error("expected valid span context for log correlation")
\t}
\tif sc.TraceID().IsEmpty() {
\t\tt.Error("expected non-empty trace ID")
\t}
}
`;
}
function generateOtelTestContent(title, language) {
    switch (language) {
        case 'python':
            return generatePythonOtelTest(title);
        case 'go':
            return generateGoOtelTest(title);
        default:
            return generateNodeOtelTest(title);
    }
}
function getFileExtension(language) {
    const exts = {
        python: 'py',
        go: 'go',
        ruby: 'rb',
        java: 'java',
        javascript: 'test.ts',
        typescript: 'test.ts',
    };
    return exts[language] ?? 'test.ts';
}
/**
 * Generate OTel instrumentation test files for the given spec and knowledge.
 */
export function generateOtelTestFiles(spec, testDir, language, autoGenerate) {
    const slug = spec.id.toLowerCase().replace(/[^a-z0-9]/g, '-');
    const ext = getFileExtension(language);
    const content = generateOtelTestContent(spec.title, language);
    const framework = language === 'python' ? 'pytest' : language === 'go' ? 'go-test' : 'vitest';
    return [
        {
            path: `${testDir}/instrumentation/${slug}.otel.${ext}`,
            framework,
            content,
            ready: autoGenerate,
        },
    ];
}
//# sourceMappingURL=otel-test-generator.js.map