Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# ADR-41906: Formal OTEL Observability Compatibility Test Suite (v0.4.0)

**Date**: 2026-06-27
**Status**: Draft
**Deciders**: Unknown (automated draft from PR #41906 — review and finalize)

---

### Context

The repository has a formal specification `specs/otel-observability-spec.md` (v0.4.0) that defines 15 predicates for Level 1/2 `observability.otlp` behavior: endpoint form normalization, deterministic header serialization, Sentry `Authorization → x-sentry-auth` rewrite, `if-missing` policy validation, OTEL service-name construction, static domain extraction, expression exclusion from allowlisting, top-level header scoping, fan-out declaration-order preservation, mirror path constants, empty URL entry discard, and nil/empty header normalization. Without explicit test coverage mapped to these predicates, the implementation can silently diverge from the spec as either evolves. The existing `observability_otlp.go` helpers implement these behaviors, but predicate-level regression protection was absent.

### Decision

We will add a dedicated formal test file `pkg/workflow/otel_observability_formal_test.go` that maps each of the 15 predicates in `specs/otel-observability-spec.md` v0.4.0 to an explicit `TestFormal_*` test. Tests assert against the public compiler/runtime behavior of `observability_otlp.go` helpers (e.g., `collectAllOTLPEndpoints`, `normalizeOTLPHeadersForEndpoint`, `otelServiceName`) rather than implementation internals, making the spec a continuously-enforced compatibility contract verified on every CI run.

### Alternatives Considered

#### Alternative 1: Integration/End-to-End Tests

Test the full OTEL pipeline end-to-end (workflow compilation → OTLP emission → collector receipt) rather than testing each predicate in isolation. This would be more realistic but far slower to run and harder to isolate failures to specific predicates. It would also require a running OTEL collector in CI, adding infrastructure complexity. Unit-level predicate tests provide faster feedback and pinpoint exactly which invariant broke.

#### Alternative 2: Property-Based / Fuzz Testing

Use Go's `testing/quick` or fuzz infrastructure to cover the input space for endpoint normalization and header serialization rather than explicit hand-written cases. This would catch edge cases the spec authors didn't enumerate, but would not verify that the specific named invariants from the formal spec are met. Explicit named tests serve as a living checklist against the spec document, which fuzz tests cannot replicate.

### Consequences

#### Positive
- All 15 v0.4.0 predicates from the formal spec are continuously enforced; any regression breaks CI immediately.
- `TestFormal_*` tests serve as executable documentation — future contributors can cross-reference the spec and know exactly which test covers which predicate.
- Tests run at unit speed with no external dependencies, giving fast CI feedback.

#### Negative
- Tests directly call package-internal functions (`collectAllOTLPEndpoints`, `normalizeOTLPHeadersForEndpoint`, etc.), so internal API refactors require corresponding test updates even if observable behavior is unchanged.
- When `specs/otel-observability-spec.md` is updated (v0.5.0, etc.), the test file must be manually updated to reflect new or changed predicates — there is no automated linkage between the spec document and the test file.

#### Neutral
- The formal test file lives in `package workflow` (not `package workflow_test`), giving it access to unexported symbols — this is intentional to allow contract-level assertions without adding a testing-only public API.
- The `determinismTestIterations = 10` constant for `TestFormal_HeaderMapDeterminism` is a pragmatic choice; it is not derived from the formal spec and may need tuning if map iteration order changes are suspected.

---

*ADR created by [adr-writer agent]. Review and finalize before changing status from Draft to Accepted.*
245 changes: 245 additions & 0 deletions pkg/workflow/otel_observability_formal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,245 @@
package workflow

import (
"testing"

"github.com/github/gh-aw/pkg/constants"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

const determinismTestIterations = 10

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/grill-with-docs] No spec predicate references appear in the file. The PR description explicitly maps each test to a named predicate in specs/otel-observability-spec.md (v0.4.0), but none of those references appear inside the test file itself. Without them, the traceability that makes a "formal spec" test suite valuable is lost as soon as someone reads the file without the PR context.

💡 Suggestion

Add a package-level or per-test doc comment linking to the spec section. For example:

// otel_observability_formal_test.go implements formal compatibility checks for
// specs/otel-observability-spec.md v0.4.0 — Level 1 and Level 2 predicates.
// Each TestFormal_* function corresponds to a named predicate in that document.

Or per-test: // Spec: endpoint-form-normalization (v0.4.0 §3.1)

@copilot please address this.

const authPlaceholder = "******"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] authPlaceholder = "******" uses the same 6-asterisk pattern that GitHub Actions masking produces for redacted secrets. Using the mask output as a test input conflates "placeholder token" with "masked output" and could produce confusing test failure messages if masking logic changes.

💡 Suggestion

Use a realistic, clearly-fake token value that cannot be confused with a masked secret:

const authPlaceholder = "test-auth-token-placeholder"

This also makes Sentry rewrite assertions easier to read: "x-sentry-auth=test-auth-token-placeholder" clearly communicates the rename without implying the value was masked.

@copilot please address this.


func TestFormal_EndpointFormNormalization(t *testing.T) {
t.Run("string object and array normalize to ordered entries", func(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] All three endpoint forms (string, object, array) are bundled inside one t.Run("string object and array normalize to ordered entries"). If the array form assertion fails, the test name doesn't tell you which form was the culprit.

💡 Suggestion

Give each form its own subtest for isolated, self-describing failures:

func TestFormal_EndpointFormNormalization(t *testing.T) {
    t.Run("string form", func(t *testing.T) { ... })
    t.Run("object form", func(t *testing.T) { ... })
    t.Run("array form", func(t *testing.T) { ... })
    t.Run("empty and absent", func(t *testing.T) { ... })
}

Each subtest name then appears directly in the failure output, matching the spec predicate language.

@copilot please address this.

stringForm := map[string]any{
"observability": map[string]any{
"otlp": map[string]any{
"endpoint": "https://string.example.com:4317",
},
},
}
assert.Equal(t,
[]otlpEndpointEntry{{URL: "https://string.example.com:4317"}},
collectAllOTLPEndpoints(stringForm),
)
Comment on lines +23 to +26

objectForm := map[string]any{
"observability": map[string]any{
"otlp": map[string]any{
"endpoint": map[string]any{"url": "https://object.example.com:4317"},
},
},
}
assert.Equal(t,
[]otlpEndpointEntry{{URL: "https://object.example.com:4317"}},
collectAllOTLPEndpoints(objectForm),
)

arrayForm := map[string]any{
"observability": map[string]any{
"otlp": map[string]any{
"endpoint": []any{
map[string]any{"url": "https://first.example.com:4317"},
map[string]any{"url": "https://second.example.com:4317"},
},
},
},
}
assert.Equal(t,
[]otlpEndpointEntry{
{URL: "https://first.example.com:4317"},
{URL: "https://second.example.com:4317"},
},
collectAllOTLPEndpoints(arrayForm),
)
})

t.Run("empty and absent normalize to empty", func(t *testing.T) {
assert.Empty(t, collectAllOTLPEndpoints(nil))
assert.Empty(t, collectAllOTLPEndpoints(map[string]any{}))
assert.Empty(t, collectAllOTLPEndpoints(map[string]any{"observability": map[string]any{}}))
})
}

func TestFormal_HeaderMapDeterminism(t *testing.T) {
headers := map[string]any{"z": "3", "a": "1", "m": "2"}
want := "a=1,m=2,z=3"

for range determinismTestIterations {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] The determinism loop calls the same map object 10 times, but Go randomises map iteration order at map creation, not per iteration. So all 10 calls see the same internal order and the loop adds no additional coverage — it's the same assertion repeated.

💡 Suggestion

The actual invariant being tested is that normalizeOTLPHeadersForEndpoint sorts keys before joining. A clearer test would assert the sorted order directly, or — if you want to guard against future regressions where sorting is removed — create a fresh map in each iteration:

for range determinismTestIterations {
    h := map[string]any{"z": "3", "a": "1", "m": "2"}
    assert.Equal(t, "a=1,m=2,z=3", normalizeOTLPHeadersForEndpoint(h, "(example.com/redacted)"))
}

Alternatively, rename the constant to mapKeyOrderIterations to signal intent more precisely, and add a comment explaining the Go randomisation behaviour being guarded against.

@copilot please address this.

assert.Equal(t, want, normalizeOTLPHeadersForEndpoint(headers, "https://example.com:4317"))
}
}

func TestFormal_SentryAuthHeaderRewrite(t *testing.T) {
normalizedSentryHeaders := normalizeOTLPHeadersForEndpoint("Authorization="+authPlaceholder, "https://o0.ingest.sentry.io/api/0/envelope/")
normalizedNonSentryHeaders := normalizeOTLPHeadersForEndpoint("Authorization="+authPlaceholder, "https://otlp.example.com:4317")
normalizedSentryMixedHeaders := normalizeOTLPHeadersForEndpoint(
map[string]any{"Authorization": authPlaceholder, "X-Tenant": "acme"},
"https://o0.ingest.sentry.io/api/0/envelope/",
)

assert.Equal(t, "x-sentry-auth="+authPlaceholder, normalizedSentryHeaders)
assert.Equal(t, "Authorization="+authPlaceholder, normalizedNonSentryHeaders)
assert.Equal(t, "x-sentry-auth="+authPlaceholder+",X-Tenant=acme", normalizedSentryMixedHeaders)
}

func TestFormal_IfMissingPolicyValidation(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] TestFormal_IfMissingPolicyValidation tests only the three happy-path values (error, WARN, Ignore) — this is exactly what TestFormal_InvalidIfMissingFallsBackToDefault (line 193) also verifies indirectly. The split creates a fragmented picture: valid modes here, invalid modes there, with no clear canonical location.

💡 Suggestion

Consolidate all normalizeOTLPIfMissingMode assertions — valid and invalid — into a single table-driven test:

func TestFormal_IfMissingPolicy(t *testing.T) {
    cases := []struct{ input, want string }{
        {"error", "error"}, {"WARN", "warn"}, {" Ignore ", "ignore"},
        {"fail", ""}, {"silent", ""}, {"skip", ""}, {"abort", ""},
    }
    for _, tc := range cases {
        t.Run(tc.input, func(t *testing.T) {
            assert.Equal(t, tc.want, normalizeOTLPIfMissingMode(tc.input))
        })
    }
}

@copilot please address this.

assert.Equal(t, "error", normalizeOTLPIfMissingMode("error"))
assert.Equal(t, "warn", normalizeOTLPIfMissingMode("WARN"))
assert.Equal(t, "ignore", normalizeOTLPIfMissingMode(" Ignore "))
}

func TestFormal_ServiceNameFormation(t *testing.T) {
assert.Equal(t, "gh-aw", otelServiceName(nil))
assert.Equal(t, "gh-aw.repo-triage-weekly", otelServiceName(&WorkflowData{WorkflowID: "repo-triage-weekly", Name: "Sample Name"}))
assert.Equal(t, "gh-aw.repo-triage-weekly", otelServiceName(&WorkflowData{WorkflowID: "Repo Triage/Weekly", Name: "Sample Name"}))
assert.Equal(t, "gh-aw.workflow-name", otelServiceName(&WorkflowData{Name: "Workflow Name"}))
}

func TestFormal_StaticDomainExtraction(t *testing.T) {
assert.Equal(t, "traces.example.com", extractOTLPEndpointDomain("https://traces.example.com:4317"))
assert.Empty(t, extractOTLPEndpointDomain(""))
assert.Empty(t, extractOTLPEndpointDomain("${{ secrets.OTLP_ENDPOINT }}"))
}

func TestFormal_ExpressionProducesNoAllowlistEntry(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] TestFormal_ExpressionProducesNoAllowlistEntry is a duplicate — line 104 of TestFormal_StaticDomainExtraction already asserts assert.Empty(t, extractOTLPEndpointDomain("${{ secrets.OTLP_ENDPOINT }}")). Having a standalone test for the same single assertion adds noise without adding coverage.

💡 Suggestion

Either remove TestFormal_ExpressionProducesNoAllowlistEntry entirely (the predicate is already covered), or remove the expression case from TestFormal_StaticDomainExtraction and keep this as the sole location for that invariant to make the predicate mapping unambiguous.

@copilot please address this.

assert.Empty(t, extractOTLPEndpointDomain("${{ secrets.OTLP_ENDPOINT }}"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exact duplicate of TestFormal_StaticDomainExtraction line 104 — adds zero coverage and silently inflates the spec-test count.

💡 Suggested fix

Either delete this function or replace with a genuinely distinct input not yet covered (e.g. a Sentry-named secret expression, a bare hostname without scheme, or a URL with user-info that should still extract the domain):

func TestFormal_ExpressionProducesNoAllowlistEntry(t *testing.T) {
	// Sentry-style secret expression also produces no domain
	assert.Empty(t, extractOTLPEndpointDomain(
		"${{ secrets."+constants.OTELSentryEndpointSecretName+" }}",
	))
}

As-is, if someone deletes the shared assertion from TestFormal_StaticDomainExtraction during a refactor, this duplicate gives false confidence that the predicate is still covered.

}
Comment on lines +107 to +109

func TestFormal_TopLevelHeadersApplyToStringFormOnly(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] TestFormal_TopLevelHeadersApplyToStringFormOnly covers string form and object form but omits the array form. The spec predicate likely also implies that top-level headers should not be silently lost or duplicated when combined with array-form endpoints — that case is untested.

💡 Suggestion

Add a third case for array form:

arrayForm := map[string]any{
    "observability": map[string]any{
        "otlp": map[string]any{
            "endpoint": []any{
                map[string]any{"url": "(array.example.com/redacted)"},
            },
            "headers": "Authorization=" + authPlaceholder,
        },
    },
}
arrayEntries := collectAllOTLPEndpoints(arrayForm)
require.Len(t, arrayEntries, 1)
// Assert: top-level headers do NOT propagate to array-form entries
assert.Empty(t, arrayEntries[0].Headers)

(Adjust the assertion to match actual spec behaviour if the intent differs.)

@copilot please address this.

stringForm := map[string]any{
"observability": map[string]any{
"otlp": map[string]any{
"endpoint": "https://string.example.com:4317",
"headers": "Authorization=" + authPlaceholder,
},
},
}
entries := collectAllOTLPEndpoints(stringForm)
require.Len(t, entries, 1)
assert.Equal(t, "Authorization="+authPlaceholder, entries[0].Headers)

objectForm := map[string]any{
"observability": map[string]any{
"otlp": map[string]any{
"endpoint": map[string]any{
"url": "https://object.example.com:4317",
"headers": "X-Per-Entry=v",
},
"headers": "Authorization=" + authPlaceholder,
},
},
}
objectEntries := collectAllOTLPEndpoints(objectForm)
require.Len(t, objectEntries, 1)
assert.Equal(t, "X-Per-Entry=v", objectEntries[0].Headers)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Array form is not tested — the function name claims "string form only" but only verifies string and object forms; a regression where array-form entries incorrectly inherit the top-level headers field would go undetected.

💡 Suggested fix

Add an array-form assertion to complete the spec contract:

// Array form: per-entry headers take effect; top-level headers are ignored
arrayForm := map[string]any{
	"observability": map[string]any{
		"otlp": map[string]any{
			"endpoint": []any{
				map[string]any{
					"url":     "(first.example.com/redacted)",
					"headers": "X-Per-Entry=v1",
				},
			},
			"headers": "Authorization=" + authPlaceholder, // top-level — must NOT apply
		},
	},
}
arrayEntries := collectAllOTLPEndpoints(arrayForm)
require.Len(t, arrayEntries, 1)
assert.Equal(t, "X-Per-Entry=v1", arrayEntries[0].Headers)

Without this, the invariant that top-level headers is strictly scoped to the backward-compat string form has a blind spot for array input.

}

func TestFormal_FanOutPreservesDeclarationOrder(t *testing.T) {
frontmatter := map[string]any{
"observability": map[string]any{
"otlp": map[string]any{
"endpoint": []any{
map[string]any{"url": "https://one.example.com:4317"},
map[string]any{"url": "https://two.example.com:4317"},
map[string]any{"url": "https://three.example.com:4317"},
},
},
},
}

entries := collectAllOTLPEndpoints(frontmatter)
require.Len(t, entries, 3)
assert.Equal(t, "https://one.example.com:4317", entries[0].URL)
assert.Equal(t, "https://two.example.com:4317", entries[1].URL)
assert.Equal(t, "https://three.example.com:4317", entries[2].URL)
}

func TestFormal_MirrorPathConstant(t *testing.T) {
assert.Equal(t, "/tmp/gh-aw/otel.jsonl", constants.TmpGhAwDirSlash+constants.OtelJsonlFilename)
}

func TestFormal_EmptyURLEntriesDiscarded(t *testing.T) {
frontmatter := map[string]any{
"observability": map[string]any{
"otlp": map[string]any{
"endpoint": []any{
map[string]any{"url": ""},
map[string]any{"url": "https://valid.example.com:4317"},
},
},
},
}

assert.Equal(t, []otlpEndpointEntry{{URL: "https://valid.example.com:4317"}}, collectAllOTLPEndpoints(frontmatter))
}

func TestFormal_StringHeaderFormPreservedForNonSentry(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] TestFormal_StringHeaderFormPreservedForNonSentry is redundant — the same assertion is already made at line 84 inside TestFormal_SentryAuthHeaderRewrite (assert.Equal(t, "Authorization="+authPlaceholder, normalizedNonSentryHeaders)). Duplicate formal predicates dilute clarity about what each test uniquely covers.

💡 Suggestion

Remove this function. The non-Sentry preservation invariant is already a named assertion in TestFormal_SentryAuthHeaderRewrite. If isolation is desired, remove the non-Sentry case from the Sentry test and keep this function as the canonical location instead.

@copilot please address this.

assert.Equal(t,
"Authorization="+authPlaceholder,
normalizeOTLPHeadersForEndpoint("Authorization="+authPlaceholder, "https://otlp.example.com:4317"),
)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Duplicate of normalizedNonSentryHeaders assertion in TestFormal_SentryAuthHeaderRewrite — this function's single assertion is already present on line 84 of the same file.

💡 Suggested fix

Remove TestFormal_StringHeaderFormPreservedForNonSentry unless it can test a distinct input (e.g., a multi-pair non-Sentry string, or a string with whitespace around =). The current duplication means a failure here also fails in TestFormal_SentryAuthHeaderRewrite, doubling noise without adding signal.


func TestFormal_NilAndEmptyHeadersYieldEmptyString(t *testing.T) {
assert.Empty(t, normalizeOTLPHeadersForEndpoint(nil, "https://example.com:4317"))
assert.Empty(t, normalizeOTLPHeadersForEndpoint("", "https://example.com:4317"))
assert.Empty(t, normalizeOTLPHeadersForEndpoint(map[string]any{}, "https://example.com:4317"))
}

func TestFormal_InvalidIfMissingFallsBackToDefault(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] TestFormal_InvalidIfMissingFallsBackToDefault mixes two abstraction levels in one function: lines 193-195 test normalizeOTLPIfMissingMode (unit), while lines 197-238 test injectOTLPConfig (integration). A failure here gives no signal about which layer broke.

💡 Suggestion

Split into two focused tests:

func TestFormal_InvalidIfMissingModesReturnEmpty(t *testing.T) {
    for _, mode := range []string{"fail", "silent", "skip", "abort"} {
        t.Run(mode, func(t *testing.T) {
            assert.Empty(t, normalizeOTLPIfMissingMode(mode))
        })
    }
}

func TestFormal_InvalidIfMissingNotInjected(t *testing.T) {
    // ...injectOTLPConfig assertions...
}

Using t.Run per mode also surfaces which exact value caused the failure.

@copilot please address this.

for _, mode := range []string{"fail", "silent", "skip", "abort"} {
assert.Empty(t, normalizeOTLPIfMissingMode(mode))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loop without subtests loses per-iteration failure context — when normalizeOTLPIfMissingMode fails for one of these modes, the failure message says only "expected empty string" with no indication of which mode triggered it.

💡 Suggested fix
for _, mode := range []string{"fail", "silent", "skip", "abort"} {
	t.Run(mode, func(t *testing.T) {
		assert.Empty(t, normalizeOTLPIfMissingMode(mode))
	})
}

This is also a good place to add "error"normalizeOTLPIfMissingMode("error") returns "error" (a valid normalized value), but injectOTLPConfig only injects GH_AW_OTLP_IF_MISSING for "warn" and "ignore". Explicitly asserting that an "error" mode does not emit that env var would close the integration gap between this unit test and TestFormal_InvalidIfMissingFallsBackToDefault.


workflowData := &WorkflowData{
RawFrontmatter: map[string]any{
"observability": map[string]any{
"otlp": map[string]any{
"endpoint": "https://traces.example.com:4317",
"if-missing": "fail",
},
},
},
ParsedFrontmatter: &FrontmatterConfig{
Observability: &ObservabilityConfig{
OTLP: &OTLPConfig{
Endpoint: "https://traces.example.com:4317",
IfMissing: "fail",
},
},
},
}
(&Compiler{}).injectOTLPConfig(workflowData)
assert.NotContains(t, workflowData.Env, "GH_AW_OTLP_IF_MISSING")

validWorkflowData := &WorkflowData{
RawFrontmatter: map[string]any{
"observability": map[string]any{
"otlp": map[string]any{
"endpoint": "https://traces.example.com:4317",
"if-missing": "warn",
},
},
},
ParsedFrontmatter: &FrontmatterConfig{
Observability: &ObservabilityConfig{
OTLP: &OTLPConfig{
Endpoint: "https://traces.example.com:4317",
IfMissing: "warn",
},
},
},
}
(&Compiler{}).injectOTLPConfig(validWorkflowData)
assert.Contains(t, validWorkflowData.Env, "GH_AW_OTLP_IF_MISSING")
assert.Contains(t, validWorkflowData.Env, "warn")
Comment on lines +237 to +238
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Substring "warn" is too broad — this assertion passes if any injected env var value contains the four letters warn, not specifically GH_AW_OTLP_IF_MISSING: warn.

💡 Suggested fix

Pin both the key and the value together so a future rename or value-format change doesn't silently pass this check:

assert.Contains(t, validWorkflowData.Env, "GH_AW_OTLP_IF_MISSING: warn")

For example, if injectOTLPConfig were changed to emit GH_AW_OTLP_IF_MISSING_MODE: warn instead, the current assertion would still pass while the spec invariant is violated.


func TestFormal_AbsentObservabilityProducesNoEndpoints(t *testing.T) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[/tdd] TestFormal_AbsentObservabilityProducesNoEndpoints duplicates two of the three assertions already in the "empty and absent normalize to empty" subtest (lines 60-62): collectAllOTLPEndpoints(nil) and collectAllOTLPEndpoints(map[string]any{}). The only unique case is map[string]any{"observability": nil}.

💡 Suggestion

Move the unique case (observability: nil) into the existing subtest inside TestFormal_EndpointFormNormalization, and remove this function entirely. Or, conversely, absorb the existing cases here and remove the overlap from TestFormal_EndpointFormNormalization.

@copilot please address this.

assert.Empty(t, collectAllOTLPEndpoints(nil))
assert.Empty(t, collectAllOTLPEndpoints(map[string]any{}))
assert.Empty(t, collectAllOTLPEndpoints(map[string]any{"observability": nil}))
}
Loading