Repository: opentofu/opentofu
File: internal/command/e2etest/init_test.go (Go)

Code before:
	}

	return string(marshaledV[1 : len(marshaledV)-2])
}

// TestTelemetrySchemaConflict reproduces the issue where OpenTofu fails to initialize
// telemetry due to conflicting OpenTelemetry schema URLs from different semconv versions.
//
// The issue occurs because different parts of the codebase import different versions
// of go.opentelemetry.io/otel/semconv:
// - internal/tracing/init.go can be using a different versions from other parts of the
// codebase.
//
// When OTEL_* variables are set, OpenTelemetry tries to initialize and
// detects these conflicting schema URLs, causing conflicting schema errors.
// For more information, see: https://github.com/opentofu/opentofu/pull/3446
func TestTelemetrySchemaConflict(t *testing.T) {
	t.Parallel()

	fixturePath := filepath.Join("testdata", "empty")
	tf := e2e.NewBinary(t, tofuBin, fixturePath)

	// Set the environment variable that triggers telemetry initialization errors
	tf.AddEnv("OTEL_TRACES_EXPORTER=otlp")
	tf.AddEnv("OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317")
	tf.AddEnv("OTEL_EXPORTER_OTLP_INSECURE=true")

	_, stderr, err := tf.Run("init")

	if err != nil {
		t.Fatalf("Expected success, got error: %s", err)
	}

	if strings.Contains(stderr, "Could not initialize telemetry") {
		t.Errorf("Expected no error message to contain 'Could not initialize telemetry', but got: %s", stderr)
	}

	if strings.Contains(stderr, "conflicting Schema URL") {
		t.Errorf("Expected no error message to contain 'conflicting Schema URL', but got: %s", stderr)
	}
}


Review comment (bug):
This particular configuration seems a little risky because in some execution environments there might actually be a real otlp server running at `http://localhost:4317`.

Could we set this to something that is definitely unresolvable and obviously intentionally invalid, like `OTEL_EXPORTER_OTLP_ENDPOINT=https://invalid/`? (The domain name `invalid` is required by [RFC 6761](https://www.rfc-editor.org/rfc/rfc6761.html) to always fail resolution.)

We could then extend the comment above to say that the configuration is intentionally invalid because we're only testing whether we can initialize, not actually trying to send telemetry, and we expect the telemetry system to gracefully tolerate the collector being unavailable, just so it's hopefully clearer to a future maintainer of this test what part of it is important _and_ what part of it isn't important.


Code after:
	}

	return string(marshaledV[1 : len(marshaledV)-2])
}

// TestTelemetrySchemaConflict reproduces the issue where OpenTofu fails to initialize
// telemetry due to conflicting OpenTelemetry schema URLs from different semconv versions.
//
// The issue occurs because different parts of the codebase import different versions
// of go.opentelemetry.io/otel/semconv, like internal/tracing/init.go.
//
// When OTEL_* variables are set, OpenTelemetry tries to initialize and
// detects these conflicting schema URLs, causing conflicting schema errors.
// For more information, see: https://github.com/opentofu/opentofu/pull/3446
func TestTelemetrySchemaConflict(t *testing.T) {
	t.Parallel()

	fixturePath := filepath.Join("testdata", "empty")
	tf := e2e.NewBinary(t, tofuBin, fixturePath)

	// Set the environment variable that triggers telemetry initialization errors
	tf.AddEnv("OTEL_TRACES_EXPORTER=otlp")
	// We're actually using an invalid endpoint because the key error is the
	// initialization error. Sending the traces themselves is not relevant to this test.
	tf.AddEnv("OTEL_EXPORTER_OTLP_ENDPOINT=http://invalid/")
	tf.AddEnv("OTEL_EXPORTER_OTLP_INSECURE=true")

	_, stderr, err := tf.Run("init")

	if err != nil {
		t.Fatalf("Expected success, got error: %s", err)
	}

	if strings.Contains(stderr, "Could not initialize telemetry") {
		t.Errorf("Expected no error message to contain 'Could not initialize telemetry', but got: %s", stderr)
	}

	if strings.Contains(stderr, "conflicting Schema URL") {
		t.Errorf("Expected no error message to contain 'conflicting Schema URL', but got: %s", stderr)
	}
}