Skip to content

feat(test): Add functional test to verify splunk 403 behavior for LOG…#3329

Merged
openshift-merge-bot[bot] merged 1 commit into
openshift:masterfrom
jcantrill:log9610
Jul 8, 2026
Merged

feat(test): Add functional test to verify splunk 403 behavior for LOG…#3329
openshift-merge-bot[bot] merged 1 commit into
openshift:masterfrom
jcantrill:log9610

Conversation

@jcantrill

@jcantrill jcantrill commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

…-9610

Description

This PR:

  • Adds a functional test to verify the collector's behavior when receiving a 403 from a splunk sink

Links

https://redhat.atlassian.net/browse/LOG-9610

cc @vparfonov @Clee2691

Summary by CodeRabbit

  • Tests
    • Added a new functional test covering Splunk log forwarding when the authentication token is invalid.
    • Verifies the system’s retry behavior by asserting 403/forbidden indicators appear in collector logs.
    • Confirms metrics include failed HTTP response samples with status="403".

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c54f5cd3-f29d-4130-9906-3e64a561ff65

📥 Commits

Reviewing files that changed from the base of the PR and between 4fbda7b and ba5764f.

📒 Files selected for processing (1)
  • test/functional/outputs/splunk/403_forbidden_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/functional/outputs/splunk/403_forbidden_test.go

📝 Walkthrough

Walkthrough

Adds a new functional test for Splunk output that deploys an invalid HEC token, checks collector logs for 403 failures, and verifies the collector metrics endpoint reports 403 responses.

Changes

Splunk 403 Forbidden Test

Layer / File(s) Summary
Test setup and collector config
test/functional/outputs/splunk/403_forbidden_test.go
Creates an invalid-token Secret, configures Splunk forwarding, strips Prometheus auth from the collector config, deploys the stack, and waits for Splunk readiness.
Collector log assertion
test/functional/outputs/splunk/403_forbidden_test.go
Writes an application log, waits for retries, reads collector logs, and checks for forbidden and 403-related strings.
Metrics 403 assertion
test/functional/outputs/splunk/403_forbidden_test.go
Queries /metrics over HTTPS, verifies vector_http_client_responses_total is present, and confirms a sample line includes status="403".

Estimated code review effort: 2 (Simple) | ~12 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers the main intent, but it omits the required /cc and /assign commands and leaves the Links section incomplete. Add the required /cc and /assign lines from OWNERS and complete the Links section with the expected linked PRs, issue, or proposal entries.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is specific and matches the PR’s main change: adding a Splunk 403 functional test.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@openshift-ci openshift-ci Bot requested review from alanconway and cahartma July 2, 2026 17:27
@openshift-ci

openshift-ci Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: jcantrill

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 2, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
test/functional/outputs/splunk/403_forbidden_test.go (2)

96-125: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Fixed sleeps instead of polling risk test flakiness.

Line 97's time.Sleep(15 * time.Second) and the single, non-retried metrics fetch (lines 120-125) hard-code timing assumptions about how quickly Vector retries/logs and exposes updated metrics. Under CI load these fixed windows are a classic source of flaky tests. Prefer Eventually polling (already used elsewhere in this package, e.g. splunk.WaitOnSplunk) for both the log assertion and the metrics fetch/assertion.

♻️ Example refactor for the log assertion
-		// Wait for logs to be attempted to be sent and retried
-		time.Sleep(15 * time.Second)
-
-		// Read collector logs and verify forbidden error is logged
-		collectorLog, err := framework.ReadCollectorLogs()
-		Expect(err).To(BeNil(), "Expected no errors reading collector logs")
-		Expect(collectorLog).ToNot(BeEmpty(), "Expected collector logs to not be empty")
-
-		// Verify that the collector logs contain a forbidden error message
-		// Vector logs HTTP errors with the status code
-		Expect(collectorLog).To(
-			Or(
+		// Read collector logs and verify forbidden error is logged
+		var collectorLog string
+		Eventually(func() (string, error) {
+			var err error
+			collectorLog, err = framework.ReadCollectorLogs()
+			return collectorLog, err
+		}, 30*time.Second, 3*time.Second).Should(
+			Or(
 				ContainSubstring("forbidden"),
 				ContainSubstring("Forbidden"),
 				ContainSubstring("status: 403"),
 				ContainSubstring("status=403"),
 				And(
 					ContainSubstring("error"),
 					ContainSubstring("403"),
 				),
 			),
 			"Expected collector logs to contain forbidden error or 403 status",
 		)

A similar Eventually wrap around the metrics curl + status="403" search would make that assertion resilient too.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/functional/outputs/splunk/403_forbidden_test.go` around lines 96 - 125,
Replace the fixed wait and one-shot metrics check in the 403 forbidden test with
polling-based assertions to reduce flakiness. In the test that uses
`framework.ReadCollectorLogs()` and the `metricsURL`/`curlCmd` flow, use
`Eventually` (similar to `splunk.WaitOnSplunk`) to repeatedly read collector
logs until the forbidden/403 substring appears, and wrap the metrics curl plus
`status="403"` verification in a retrying `Eventually` as well. Keep the
existing `collectorLog` and `metrics` checks, but make both outcomes wait on the
expected condition instead of relying on `time.Sleep(15 * time.Second)` and a
single fetch.

54-81: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Fragile auth-section removal via hardcoded property strings.

This relies on exact-match strings for every property inside [sinks.prometheus_output.auth] (strategy = "sar", path = "/metrics", verb = "get"). If the generated auth block ever gains an additional property that doesn't match one of the three hardcoded prefixes, skipNext is reset to false and that orphan line leaks into the output outside any section header, silently producing a malformed/incorrect config and breaking the premise of the test (unauthenticated /metrics).

A simpler and more robust approach is to skip everything between the auth header and the next [section] header, without needing to know the specific property names:

♻️ Proposed simplification
 framework.VisitConfig = func(conf string) string {
-			// Remove the [sinks.prometheus_output.auth] section
-			lines := strings.Split(conf, "\n")
-			var result []string
-			skipNext := false
-			for _, line := range lines {
-				// Skip the [sinks.prometheus_output.auth] section and its properties
-				if strings.Contains(line, "[sinks.prometheus_output.auth]") {
-					skipNext = true
-					continue
-				}
-				if skipNext {
-					// Skip lines that are part of the auth section (strategy, path, verb)
-					trimmed := strings.TrimSpace(line)
-					if trimmed == `strategy = "sar"` || trimmed == `path = "/metrics"` || trimmed == `verb = "get"` {
-						continue
-					}
-					// Stop skipping when we hit a non-auth line or another section
-					if !strings.HasPrefix(trimmed, "strategy") && !strings.HasPrefix(trimmed, "path") && !strings.HasPrefix(trimmed, "verb") {
-						skipNext = false
-					}
-				}
-				if !skipNext {
-					result = append(result, line)
-				}
-			}
-			return strings.Join(result, "\n")
+			// Remove the [sinks.prometheus_output.auth] section entirely by
+			// skipping every line until the next section header is found.
+			lines := strings.Split(conf, "\n")
+			var result []string
+			inAuthSection := false
+			for _, line := range lines {
+				trimmed := strings.TrimSpace(line)
+				if trimmed == `[sinks.prometheus_output.auth]` {
+					inAuthSection = true
+					continue
+				}
+				if inAuthSection {
+					if strings.HasPrefix(trimmed, "[") {
+						inAuthSection = false
+					} else {
+						continue
+					}
+				}
+				result = append(result, line)
+			}
+			return strings.Join(result, "\n")
 		}

For an even more robust option, consider parsing with a TOML library (e.g. github.com/BurntSushi/toml or github.com/pelletier/go-toml) instead of manual string manipulation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/functional/outputs/splunk/403_forbidden_test.go` around lines 54 - 81,
The auth-section stripping in VisitConfig is too brittle because it depends on
hardcoded property strings inside [sinks.prometheus_output.auth]. Update the
logic to skip every line from that section header until the next section header,
so any future auth properties are removed automatically. Keep the fix localized
to framework.VisitConfig in the 403_forbidden_test.go test helper and preserve
the rest of the config unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/functional/outputs/splunk/403_forbidden_test.go`:
- Line 143: The GinkgoWriter logging in the 403 metric loop ignores the error
returned by fmt.Fprintf, which triggers the errcheck violation. Update the code
in the test helper/loop that writes “Found 403 metric” to either handle the
returned error explicitly or switch to a write path that cannot fail in a way
that satisfies linting, keeping the change localized to the GinkgoWriter usage.

---

Nitpick comments:
In `@test/functional/outputs/splunk/403_forbidden_test.go`:
- Around line 96-125: Replace the fixed wait and one-shot metrics check in the
403 forbidden test with polling-based assertions to reduce flakiness. In the
test that uses `framework.ReadCollectorLogs()` and the `metricsURL`/`curlCmd`
flow, use `Eventually` (similar to `splunk.WaitOnSplunk`) to repeatedly read
collector logs until the forbidden/403 substring appears, and wrap the metrics
curl plus `status="403"` verification in a retrying `Eventually` as well. Keep
the existing `collectorLog` and `metrics` checks, but make both outcomes wait on
the expected condition instead of relying on `time.Sleep(15 * time.Second)` and
a single fetch.
- Around line 54-81: The auth-section stripping in VisitConfig is too brittle
because it depends on hardcoded property strings inside
[sinks.prometheus_output.auth]. Update the logic to skip every line from that
section header until the next section header, so any future auth properties are
removed automatically. Keep the fix localized to framework.VisitConfig in the
403_forbidden_test.go test helper and preserve the rest of the config unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ab95c3f9-103d-4950-8138-9a3805de3da7

📥 Commits

Reviewing files that changed from the base of the PR and between c02ef14 and 4fbda7b.

📒 Files selected for processing (1)
  • test/functional/outputs/splunk/403_forbidden_test.go

Comment thread test/functional/outputs/splunk/403_forbidden_test.go Outdated
@Clee2691

Clee2691 commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Jul 8, 2026
@openshift-merge-bot

Copy link
Copy Markdown
Contributor

/retest-required

Remaining retests: 0 against base HEAD 8907da0 and 2 for PR HEAD ba5764f in total

@openshift-ci

openshift-ci Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

@jcantrill: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-using-bundle ba5764f link false /test e2e-using-bundle

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@openshift-merge-bot openshift-merge-bot Bot merged commit 4bc3b90 into openshift:master Jul 8, 2026
9 of 10 checks passed
@jcantrill jcantrill deleted the log9610 branch July 9, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. lgtm Indicates that a PR is ready to be merged. release/6.6

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants