Skip to content

Add sosreport tools e2e test#16

Merged
arkadeepsen merged 3 commits intoovn-kubernetes:mainfrom
Meina-rh:sosreport_e2e
Feb 11, 2026
Merged

Add sosreport tools e2e test#16
arkadeepsen merged 3 commits intoovn-kubernetes:mainfrom
Meina-rh:sosreport_e2e

Conversation

@Meina-rh
Copy link
Contributor

@Meina-rh Meina-rh commented Dec 1, 2025

Add sosreport tools e2e test

go test -test.timeout 180m -v . -ginkgo.v -ginkgo.focus="Sosreport Tools"                                    
=== RUN   TestE2e
Running Suite: E2e Suite - /home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e
==================================================================================
Random Seed: 1764569390

Will run 11 of 14 specs
------------------------------
[BeforeSuite] 
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/e2e_suite_test.go:90
[BeforeSuite] PASSED [0.002 seconds]
------------------------------
SSS
------------------------------
Sosreport Tools List Plugins should list all enabled plugins with command counts
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:43
  STEP: Calling sos-list-plugins @ 12/01/25 14:09:50.521
  STEP: Checking the result @ 12/01/25 14:09:51.6
• [1.080 seconds]
------------------------------
Sosreport Tools List Commands should list all commands for openvswitch plugin
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:71
  STEP: Calling sos-list-commands for openvswitch @ 12/01/25 14:09:51.601
  STEP: Checking the result @ 12/01/25 14:09:52.684
• [1.084 seconds]
------------------------------
Sosreport Tools List Commands should list all commands for networking plugin
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:97
  STEP: Calling sos-list-commands for networking @ 12/01/25 14:09:52.685
  STEP: Checking the result @ 12/01/25 14:09:53.855
• [1.171 seconds]
------------------------------
Sosreport Tools Search Commands should find commands matching ovs pattern
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:118
  STEP: Calling sos-search-commands with pattern 'ovs' @ 12/01/25 14:09:53.855
  STEP: Checking the result @ 12/01/25 14:09:54.905
• [1.049 seconds]
------------------------------
Sosreport Tools Search Commands should find commands matching ip pattern
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:141
  STEP: Calling sos-search-commands with pattern 'ip' @ 12/01/25 14:09:54.905
  STEP: Checking the result @ 12/01/25 14:09:56.045
• [1.141 seconds]
------------------------------
Sosreport Tools Get Command should get command output by filepath
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:162
  STEP: Calling sos-get-command for ovs-vsctl show @ 12/01/25 14:09:56.046
  STEP: Checking the result @ 12/01/25 14:09:57.098
• [1.052 seconds]
------------------------------
Sosreport Tools Get Command should get command output with pattern filter
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:181
  STEP: Calling sos-get-command with pattern filter @ 12/01/25 14:09:57.098
  STEP: Checking the result @ 12/01/25 14:09:58.145
• [1.048 seconds]
------------------------------
Sosreport Tools Get Command should get full ip addr show output without filter
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:206
  STEP: Calling sos-get-command without pattern @ 12/01/25 14:09:58.145
  STEP: Checking the result @ 12/01/25 14:09:59.236
• [1.091 seconds]
------------------------------
Sosreport Tools Search Pod Logs should search for ERROR pattern in pod logs
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:228
  STEP: Calling sos-search-pod-logs with ERROR pattern @ 12/01/25 14:09:59.237
  STEP: Checking the result @ 12/01/25 14:10:00.37
• [1.134 seconds]
------------------------------
Sosreport Tools Search Pod Logs should search pod logs with pod filter
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:247
  STEP: Calling sos-search-pod-logs with pod filter @ 12/01/25 14:10:00.37
  STEP: Checking the result @ 12/01/25 14:10:01.812
• [1.442 seconds]
------------------------------
Sosreport Tools Search Pod Logs should search for successful connection in pod logs
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/sosreport_test.go:266
  STEP: Calling sos-search-pod-logs for successful connection @ 12/01/25 14:10:01.812
  STEP: Checking the result @ 12/01/25 14:10:02.869
• [1.057 seconds]
------------------------------
[AfterSuite] 
/home/dev-scripts/push_code/ovn-kubernetes-mcp/test/e2e/e2e_suite_test.go:110
[AfterSuite] PASSED [0.000 seconds]
------------------------------

Ran 11 of 14 Specs in 12.351 seconds
SUCCESS! -- 11 Passed | 0 Failed | 0 Pending | 3 Skipped
--- PASS: TestE2e (12.35s)
PASS
ok  	github.com/ovn-kubernetes/ovn-kubernetes-mcp/test/e2e	12.376s

Summary by CodeRabbit

  • Tests

    • Added an end-to-end offline sosreport test suite covering plugin/command listings, pattern-based command search, command output retrieval (with optional pattern filtering), and pod log searches using bundled test data; tests can run in offline mode.
  • Chores

    • CI, Makefile, and run-script changes to support selectable offline vs live-cluster test modes via a matrix option, with conditional deploy/cleanup and mode-aware test selection.

@Meina-rh Meina-rh marked this pull request as ready for review December 1, 2025 06:10
@tssurya
Copy link
Contributor

tssurya commented Dec 18, 2025

@coderabbitai : please review

@coderabbitai
Copy link

coderabbitai bot commented Dec 18, 2025

@tssurya: I'll review the changes in this PR for you.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Dec 18, 2025

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.
  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds an offline-mode sosreport end-to-end test and propagates an MCP_MODE flag through CI, Makefile, run script, and test bootstrap. CI gains a matrix for live-cluster vs offline with conditional KIND and log steps; run-e2e and e2e suite branch behavior based on MCP_MODE.

Changes

Cohort / File(s) Summary
New E2E test
test/e2e/sosreport_test.go
Adds offline-mode sosreport e2e test exercising list-plugins/commands, search commands, get command output, and pod log searches against testdata sosreport.
E2E bootstrap
test/e2e/e2e_suite_test.go
Reads MCP_MODE; when offline, skips kubeconfig and MCP inspector live setup to enable offline tests.
CI workflow
.github/workflows/e2e.yml
Introduces matrix mode: [live-cluster, offline]; conditions KIND deploy/log/upload/cleanup on mode; sets JOB_NAME from matrix and passes MCP_MODE to test step.
Makefile runner
Makefile
Adds MCP_MODE ?= live-cluster; run-e2e forwards $(MCP_MODE) to ./hack/run-e2e.sh; gates deploy/undeploy targets on MCP_MODE=live-cluster.
E2E run script
hack/run-e2e.sh
Accepts and validates MCP_MODE; branches ginkgo invocation to run offline-focused tests when MCP_MODE=offline, otherwise runs live-cluster tests (skipping offline tests).

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions
    participant Runner as Job Runner
    participant KIND as KIND Cluster
    participant Script as run-e2e.sh
    participant Tests as Ginkgo E2E Tests
    participant MCP as MCPInspector / Testdata

    GH->>Runner: start job (matrix.mode)
    alt mode == live-cluster
        Runner->>KIND: deploy KIND cluster
    end
    Runner->>Script: invoke ./hack/run-e2e.sh (MCP_MODE)
    Script->>Tests: run ginkgo with MCP_MODE
    alt MCP_MODE == offline
        Tests->>MCP: initialize offline MCPInspector using testdata sosreport
        Tests->>MCP: run plugin/command/list/search/get and pod-log queries
    else MCP_MODE == live-cluster
        Tests->>KIND: use kubeconfig to interact with cluster
        Tests->>MCP: query live MCP resources
    end
    alt mode == live-cluster
        Runner->>GH: upload KIND logs and cleanup
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • arkadeepsen

Poem

🐰 I hopped through sosreport by lantern glow,

Offline traces where the test-data flow.
Plugins counted, command lines peeked,
Logs chased down the patterns we seeked,
A rabbit cheers — the test seeds grow.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add sosreport tools e2e test' accurately summarizes the main change—introducing end-to-end tests for sosreport tools as evidenced by the new test/e2e/sosreport_test.go file and supporting infrastructure changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
test/e2e/sosreport_test.go (2)

30-32: Consider using runtime.Caller for more robust testdata path resolution.

The relative path ../../pkg/sosreport/mcp/testdata/sosreport resolves against the current working directory. While go test typically runs from the package directory making this work, it can break if tests are invoked from a different directory (e.g., repo root with -v ./...).

🔎 Alternative approach using runtime.Caller:
+import "runtime"
+
+func getTestdataPath() string {
+    _, filename, _, _ := runtime.Caller(0)
+    return filepath.Join(filepath.Dir(filename), "../../pkg/sosreport/mcp/testdata/sosreport")
+}

Then in BeforeEach:

-       testdataSosreportPath, err = filepath.Abs("../../pkg/sosreport/mcp/testdata/sosreport")
-       Expect(err).NotTo(HaveOccurred())
+       testdataSosreportPath = getTestdataPath()

198-203: Clarify intent of pattern filter validation.

This assertion verifies that every line in the output either contains "eth0" or is empty, which validates strict pattern-only filtering. However, the nested condition logic is slightly convoluted.

🔎 Consider a clearer assertion:
-           // Verify lo interface is not in filtered output
-           lines := strings.Split(strings.TrimSpace(result.Output), "\n")
-           for _, line := range lines {
-               if !strings.Contains(line, "eth0") {
-                   Expect(line).To(BeEmpty())
-               }
-           }
+           // Verify all non-empty lines contain the filter pattern
+           lines := strings.Split(strings.TrimSpace(result.Output), "\n")
+           for _, line := range lines {
+               if line != "" {
+                   Expect(line).To(ContainSubstring("eth0"), "Expected filtered output to only contain lines matching 'eth0'")
+               }
+           }

Or more concisely with a negative assertion:

// Verify unrelated interfaces are not in filtered output
Expect(result.Output).NotTo(ContainSubstring("lo:"))
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ac385e and 8699b1b.

📒 Files selected for processing (1)
  • test/e2e/sosreport_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
test/e2e/sosreport_test.go (4)
test/e2e/inspector/mcp_inspector.go (2)
  • MCPInspector (15-21)
  • NewMCPInspector (23-25)
test/e2e/utils/utils.go (1)
  • UnmarshalCallToolResult (11-25)
pkg/sosreport/types/command.go (3)
  • ListPluginsResult (56-59)
  • ListCommandsResult (10-14)
  • GetCommandResult (51-53)
pkg/sosreport/types/logs.go (1)
  • SearchPodLogsResult (12-14)
🔇 Additional comments (4)
test/e2e/sosreport_test.go (4)

42-68: Well-structured test with clear assertions.

Good use of By steps for documentation and the map-based plugin validation approach makes the assertions readable and maintainable.


70-115: LGTM!

Both test cases follow a consistent pattern. The HaveLen assertion before direct index access on line 113 ensures safety.


227-281: Good test coverage for pod log search functionality.

The three test cases cover key scenarios: pattern matching, pod filtering, and specific log content search. The assertions appropriately validate expected output content.


117-139: No issues found. The SearchCommandsResult type is properly defined in pkg/sosreport/types/command.go with all required fields (Total and Matches), and the CommandMatch struct has the expected fields (Plugin, Exec, Filepath) that are correctly used in the test assertions.

@Meina-rh Meina-rh requested a review from a team January 21, 2026 07:05
@arkadeepsen
Copy link
Contributor

@Meina-rh I think it'd be better to create a separate e2e test suite for offline mode. Otherwise we'll just end up creating the kind cluster but will never use it. PLMK if you need help in how to go about it.

@Meina-rh
Copy link
Contributor Author

@arkadeepsen I've added mode=offline in CommandFlags. Can we configure the CI to avoid creating a kind cluster when running in offline mode?

@arkadeepsen
Copy link
Contributor

@arkadeepsen I've added mode=offline in CommandFlags. Can we configure the CI to avoid creating a kind cluster when running in offline mode?

@Meina-rh even if you use use mode=offline it just runs the server in offline mode, but the kind cluster will still be there. You are anyway creating a separate mcp inspector variable. It would make sense to create a separate test suite for offline mode. There can be different make targets related to offline e2es.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/e2e.yml:
- Around line 40-51: The workflow step "Install dependencies" writes the local
bin path to GITHUB_PATH without quoting which can cause word-splitting/globbing;
update the echo that appends the path so it quotes the variable expansion (use
"$GITHUB_PATH" when redirecting) to ensure the entire path is written safely and
robustly; locate the echo line that currently reads echo "$HOME/.local/bin" >>
$GITHUB_PATH and change the redirection target to the quoted variable name.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@test/e2e/e2e_suite_test.go`:
- Around line 94-110: Read kubeconfig from the KUBECONFIG env var or fall back
to k8se2eframework.TestContext.KubeConfig, always create mcpInspector via
inspector.NewMCPInspector().Command(mcpServerPath) and append the kubeconfig
CommandFlags only if a kubeconfig value exists; only attempt to build client
config and set kubeClient (using client.New) when a kubeconfig value is
available, and ensure k8se2eframework.TestContext.KubeConfig is populated from
the resolved kubeconfig variable so tests that rely on the flag path work.
🧹 Nitpick comments (1)
hack/run-e2e.sh (1)

44-49: Normalize MCP_MODE to handle variant formats safely.

Currently the script only matches the exact string "Offline Mode", but callers could pass "offline-mode" (from matrix definitions) or other casings, causing the condition to silently fall through to online tests. Normalizing once prevents this failure mode.

♻️ Suggested change
+MCP_MODE_NORMALIZED=$(echo "${MCP_MODE}" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')
-if [[ "${MCP_MODE}" == "Offline Mode" ]]; then
+if [[ "${MCP_MODE_NORMALIZED}" == "offline-mode" ]]; then
     echo "Running offline mode tests (sosreport and must-gather)"
     ginkgo -vv --focus="Sosreport Tools" test/e2e
 else
     echo "Running online mode tests (excluding offline tests)"
     ginkgo -vv --skip="Sosreport Tools" test/e2e
 fi

Comment on lines 94 to 110
kubeconfig := os.Getenv(kubeconfigEnvVar)
// Only setup kubeClient and mcpInspector if KUBECONFIG is provided
// This allows offline mode e2e tests to run without a cluster
if kubeconfig != "" {
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
Expect(err).NotTo(HaveOccurred())
kubeClient, err = client.New(config, client.Options{Scheme: s})
Expect(err).NotTo(HaveOccurred())

k8se2eframework.TestContext.KubeConfig = kubeconfig

mcpInspector = inspector.NewMCPInspector().
Command(mcpServerPath).
CommandFlags(map[string]string{
"kubeconfig": kubeconfig,
})
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, examine the exact lines 94-110 in the file mentioned
cat -n test/e2e/e2e_suite_test.go | sed -n '90,115p'

Repository: ovn-kubernetes/ovn-kubernetes-mcp

Length of output: 1009


🏁 Script executed:

# Search for all mcpInspector usages and their context
rg -n --type=go -B3 -A3 'mcpInspector'

Repository: ovn-kubernetes/ovn-kubernetes-mcp

Length of output: 3397


🏁 Script executed:

# Search for TestContext.KubeConfig usages
rg -n --type=go -B2 -A2 'TestContext\.KubeConfig'

Repository: ovn-kubernetes/ovn-kubernetes-mcp

Length of output: 2831


🏁 Script executed:

# Search for KUBECONFIG handling
rg -n --type=go -B2 -A2 'kubeconfigEnvVar|KUBECONFIG'

Repository: ovn-kubernetes/ovn-kubernetes-mcp

Length of output: 2973


Always initialize mcpInspector and fall back to flag-based kubeconfig.

Line 94 reads kubeconfig only from the KUBECONFIG env var, ignoring the --kubeconfig command-line flag (available via TestContext.KubeConfig). More critically, mcpInspector is left nil if the env var is empty, but tests in ovn_test.go (lines 55, 82) and kubernetes_test.go (lines 41, 89, 133) call mcpInspector.MethodCall() unconditionally without nil checks, risking nil dereference. Restructure to fall back to TestContext.KubeConfig when the env var is unset, and always create the inspector, only adding the kubeconfig flag when present.

🐛 Suggested fix
-	kubeconfig := os.Getenv(kubeconfigEnvVar)
+	kubeconfig := os.Getenv(kubeconfigEnvVar)
+	if kubeconfig == "" {
+		kubeconfig = k8se2eframework.TestContext.KubeConfig
+	}
 	// Only setup kubeClient and mcpInspector if KUBECONFIG is provided
 	// This allows offline mode e2e tests to run without a cluster
 	if kubeconfig != "" {
 		config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
 		Expect(err).NotTo(HaveOccurred())
 		kubeClient, err = client.New(config, client.Options{Scheme: s})
 		Expect(err).NotTo(HaveOccurred())

 		k8se2eframework.TestContext.KubeConfig = kubeconfig
-
-		mcpInspector = inspector.NewMCPInspector().
-			Command(mcpServerPath).
-			CommandFlags(map[string]string{
-				"kubeconfig": kubeconfig,
-			})
 	}
+	mcpInspector = inspector.NewMCPInspector().Command(mcpServerPath)
+	if kubeconfig != "" {
+		mcpInspector.CommandFlags(map[string]string{
+			"kubeconfig": kubeconfig,
+		})
+	}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
kubeconfig := os.Getenv(kubeconfigEnvVar)
// Only setup kubeClient and mcpInspector if KUBECONFIG is provided
// This allows offline mode e2e tests to run without a cluster
if kubeconfig != "" {
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
Expect(err).NotTo(HaveOccurred())
kubeClient, err = client.New(config, client.Options{Scheme: s})
Expect(err).NotTo(HaveOccurred())
k8se2eframework.TestContext.KubeConfig = kubeconfig
mcpInspector = inspector.NewMCPInspector().
Command(mcpServerPath).
CommandFlags(map[string]string{
"kubeconfig": kubeconfig,
})
}
kubeconfig := os.Getenv(kubeconfigEnvVar)
if kubeconfig == "" {
kubeconfig = k8se2eframework.TestContext.KubeConfig
}
// Only setup kubeClient and mcpInspector if KUBECONFIG is provided
// This allows offline mode e2e tests to run without a cluster
if kubeconfig != "" {
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
Expect(err).NotTo(HaveOccurred())
kubeClient, err = client.New(config, client.Options{Scheme: s})
Expect(err).NotTo(HaveOccurred())
k8se2eframework.TestContext.KubeConfig = kubeconfig
}
mcpInspector = inspector.NewMCPInspector().Command(mcpServerPath)
if kubeconfig != "" {
mcpInspector.CommandFlags(map[string]string{
"kubeconfig": kubeconfig,
})
}
🤖 Prompt for AI Agents
In `@test/e2e/e2e_suite_test.go` around lines 94 - 110, Read kubeconfig from the
KUBECONFIG env var or fall back to k8se2eframework.TestContext.KubeConfig,
always create mcpInspector via
inspector.NewMCPInspector().Command(mcpServerPath) and append the kubeconfig
CommandFlags only if a kubeconfig value exists; only attempt to build client
config and set kubeClient (using client.New) when a kubeconfig value is
available, and ensure k8se2eframework.TestContext.KubeConfig is populated from
the resolved kubeconfig variable so tests that rely on the flag path work.

@Meina-rh
Copy link
Contributor Author

@arkadeepsen I try to create a separate test suite for offline mode following by jamo's PR. is this what you mean?

@arkadeepsen
Copy link
Contributor

@arkadeepsen I try to create a separate test suite for offline mode following by jamo's PR. is this what you mean?

Yes somewhat similar to this. I'll take a look at this. But since you are using Jamo's commit, it would be better we first merge his PR first.

@Meina-rh Meina-rh force-pushed the sosreport_e2e branch 2 times, most recently from 0d71e54 to 339eaf8 Compare January 30, 2026 08:09
Copy link
Contributor

@arkadeepsen arkadeepsen left a comment

Choose a reason for hiding this comment

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

Let's separate out the addition of the new CI lane into another commit. I'll review the actual e2e test post that.

mcpMode := os.Getenv(mcpModeEnvVar)
// Skip kubeconfig setup for offline mode tests
// Offline tests (sosreport, must-gather) don't need a running cluster
if mcpMode == "Offline Mode" {
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's introduce a const with the value offline instead of directly matching with string.

hack/run-e2e.sh Outdated
Comment on lines 47 to 50
ginkgo -vv --focus="Sosreport Tools" test/e2e
else
echo "Running online mode tests (excluding offline tests)"
ginkgo -vv --skip="Sosreport Tools" test/e2e
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be made more generic? If we add more layers to the offline mode, then we'd have to update this everytime.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I update with [offline] label in sosreport Describe and filter this label

@Meina-rh Meina-rh force-pushed the sosreport_e2e branch 6 times, most recently from 0d085a6 to ec2faf8 Compare February 2, 2026 10:07
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@test/e2e/sosreport_test.go`:
- Around line 16-33: The test currently computes testdataSosreportPath with
filepath.Abs("../../pkg/sosreport/mcp/testdata/sosreport") which depends on the
working directory; update the BeforeEach in this test to derive the
repository-relative path using the file location: call runtime.Caller(0) inside
the BeforeEach to get this test file's directory (use filepath.Dir on the
returned filename) and then filepath.Join that directory with the relative path
" ../../pkg/sosreport/mcp/testdata/sosreport" (or better, the path segments
"pkg","sosreport","mcp","testdata","sosreport") to produce
testdataSosreportPath; keep the variable name testdataSosreportPath and the
Expect(err).NotTo(HaveOccurred()) check for any errors from runtime.Caller or
path operations.

Copy link
Contributor

@arkadeepsen arkadeepsen left a comment

Choose a reason for hiding this comment

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

@Meina-rh Great effort to add the 2 CI lanes and sosreport e2e tests. Let's add some failure test scenarios as well where some of the commands are expected to fail.

Comment on lines 17 to 28
var sosreportInspector *inspector.MCPInspector
var testdataSosreportPath string

BeforeEach(func() {
mcpServerPath := os.Getenv(mcpServerPathEnvVar)
Expect(mcpServerPath).NotTo(BeEmpty())

sosreportInspector = inspector.NewMCPInspector().
Command(mcpServerPath).
CommandFlags(map[string]string{
"mode": "offline",
})
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we should reuse the same mcpInspector global variable instead of introducing sosreportInspector. Since we are not going to run live-cluster and offline tests together, it shouldn't be a problem. No need to intialize the mcpServerPath and mcpInspector everytime before run each test.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yep, I update mcpInpsector for offline mode in e2e_suite_test.go.

Expect(result.Plugin).To(Equal("networking"))
Expect(result.CommandCount).To(Equal(1))
Expect(result.Commands).To(HaveLen(1))
Expect(result.Commands[0].Exec).To(Equal("ip addr show"))
Copy link
Contributor

Choose a reason for hiding this comment

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

We can add the command path check for networking plugin as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ok. I also update some tests using ginkgo.DescribeTable

// Verify output contains expected content
Expect(result.Output).To(ContainSubstring("Bridge br-int"))
Expect(result.Output).To(ContainSubstring("ovn-k8s-mp0"))
Expect(result.Output).To(ContainSubstring("ovs_version: \"2.17.0\""))
Copy link
Contributor

Choose a reason for hiding this comment

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

We can probably remove the ovs version check. This is very specific to the testdata and may cause an issue when the testdata is updated in the future.

Comment on lines 198 to 203
lines := strings.Split(strings.TrimSpace(result.Output), "\n")
for _, line := range lines {
if !strings.Contains(line, "eth0") {
Expect(line).To(BeEmpty())
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
lines := strings.Split(strings.TrimSpace(result.Output), "\n")
for _, line := range lines {
if !strings.Contains(line, "eth0") {
Expect(line).To(BeEmpty())
}
}
iter := strings.SplitSeq(strings.TrimSpace(result.Output), "\n")
for line := range iter {
if !strings.Contains(line, "eth0") {
Expect(line).To(BeEmpty())
}
}

SplitSeq can be used here instead since we are not using the split slice here.

Additionally, shouldn't the check be that if eth0 is not contained in a line, the test fails? Meaning each line should consist of eth0.

.PHONY: run-e2e
run-e2e:
./hack/run-e2e.sh $(NVM_VERSION) $(NODE_VERSION) $(NPM_VERSION)
./hack/run-e2e.sh $(NVM_VERSION) $(NODE_VERSION) $(NPM_VERSION) "$(MCP_MODE)"
Copy link
Contributor

Choose a reason for hiding this comment

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

Let's add a default value for MCP_MODE here in the makefile. I think default value should be live-cluster here so that the current behavior doesn't break.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also add similar conditional kind deployment for test-e2e make target, like you've done in the e2e.yml file.

Copy link
Contributor

@arkadeepsen arkadeepsen left a comment

Choose a reason for hiding this comment

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

Let's add some failure test scenarios as well where some of the commands are expected to fail.

I think the failure test scenarios are not added in the last commit. Apart from that looks good.

Makefile Outdated
Comment on lines 53 to 59
ifeq ($(MCP_MODE),live-cluster)
$(MAKE) deploy-kind-ovnk
endif
$(MAKE) run-e2e || EXIT_CODE=$$?; \
ifeq ($(MCP_MODE),live-cluster)
$(MAKE) undeploy-kind-ovnk; \
endif
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
ifeq ($(MCP_MODE),live-cluster)
$(MAKE) deploy-kind-ovnk
endif
$(MAKE) run-e2e || EXIT_CODE=$$?; \
ifeq ($(MCP_MODE),live-cluster)
$(MAKE) undeploy-kind-ovnk; \
endif
if [ "$(MCP_MODE)" = "live-cluster" ]; then $(MAKE) deploy-kind-ovnk; fi; \
$(MAKE) run-e2e || EXIT_CODE=$$?; \
if [ "$(MCP_MODE)" = "live-cluster" ]; then $(MAKE) undeploy-kind-ovnk; fi; \

Ran it locally and the second ifeq wasn't working as expected. Better to use shell if here.

@Meina-rh Meina-rh force-pushed the sosreport_e2e branch 6 times, most recently from e7dadbb to 6bc6027 Compare February 9, 2026 08:14
Signed-off-by: Meina-rh <meinli@redhat.com>
@Meina-rh
Copy link
Contributor Author

Meina-rh commented Feb 9, 2026

@arkadeepsen I added some failed tests. And I found a issue on sos-search-commands: when output is empty, it will report error

s: "command failed: exit status 1, stderr: Failed to call tool sos-search-commands: MCP error 0: validating tool output: validating root: validating /properties/matches: type: has type "null", want "array"\n\nFailed with exit code: 1\n",

Here is fix commit: 004267f. PTAL, thanks

- {mode: "live-cluster"}
- {mode: "offline"}
env:
JOB_NAME: "${{ matrix.mode }}"
Copy link
Contributor

Choose a reason for hiding this comment

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

This env var is not being used.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

does github CI job name use this env var?

Copy link
Contributor

Choose a reason for hiding this comment

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

So let's use it if we are keeping it. We can use it here to name the artifacts uploaded: https://github.com/ovn-kubernetes/ovn-kubernetes-mcp/pull/16/changes#diff-3e103440521ada06efd263ae09b259e5507e4b8f7408308dc227621ad9efa31eR92

-           name: kind-logs-e2e-${{ github.run_id }}
+           name: kind-logs-e2e-${{ matrix.mode }}-${{ github.run_id }}


By("Checking the result")
result := utils.UnmarshalCallToolResult[sostypes.ListPluginsResult](output)
Expect(result.Plugins).To(HaveLen(expectedPluginCount))
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is only plugin count parameterized but the other values are hardoced in the test? Best to follow one approach rather than mixing them.

Signed-off-by: Meina-rh <meinli@redhat.com>
when output is empty, the Matches slice in SearchCommandsResult was nil.
When marshaled and returned via MCP, this resulted in "matches": null
in the JSON output, causing schema validation failures.

This fix ensures that even when no commands are found, the JSON output
always contains "matches": [] and conforms to the MCP tool schema.

Signed-off-by: Meina-rh <meinli@redhat.com>
Copy link
Contributor

@arkadeepsen arkadeepsen left a comment

Choose a reason for hiding this comment

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

Thanks for the PR.

@arkadeepsen arkadeepsen merged commit e2920ed into ovn-kubernetes:main Feb 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants