Skip to content

CNTRLPLANE-3174: Add unit tests for v2 CPO controller packages#8215

Merged
openshift-merge-bot[bot] merged 7 commits intoopenshift:mainfrom
bryan-cox:improve-ut-coverage
Apr 15, 2026
Merged

CNTRLPLANE-3174: Add unit tests for v2 CPO controller packages#8215
openshift-merge-bot[bot] merged 7 commits intoopenshift:mainfrom
bryan-cox:improve-ut-coverage

Conversation

@bryan-cox
Copy link
Copy Markdown
Member

@bryan-cox bryan-cox commented Apr 13, 2026

What this PR does / why we need it:

Adds behavior-driven unit tests for 22 previously untested v2 control-plane-operator controller packages, covering ~9,200 lines of new test code across 51 test files. All packages were at 0% coverage before this PR.

Packages covered

Commit Area Packages
1 CAPI v2/capi_manager, v2/capi_provider
2 Cloud providers v2/cloud_controller_manager/powervs, v2/cloud_credential_operator
3 Core controllers v2/kcm, konnectivity, v2/konnectivity_agent, v2/machine_approver, v2/pkioperator
4 Networking v2/dnsoperator, v2/ignitionserver_proxy
5 Workload v2/nto, v2/oauth_apiserver, v2/karpenteroperator
6 OLM v2/olm, v2/olm/catalog_operator, v2/olm/catalogs, v2/olm/collect_profiles, v2/olm/olm_operator, v2/olm/packageserver
7 Infrastructure v2/assets, v2/fg

Testing approach

Tests follow the behavior-driven-testing skill conventions:

  • Gherkin-style test names: "When <condition>, it should <behavior>"
  • gomega assertions with NewWithT(t) per subtest
  • t.Parallel() at both test function and subtest levels (except where t.Setenv is used)
  • Table-driven tests with validate func fields
  • Focus on testable behaviors (predicates, config builders, deployment adapters) — boilerplate wiring (NewComponent) is intentionally excluded

Which issue(s) this PR fixes:

Fixes https://issues.redhat.com/browse/CNTRLPLANE-3174

Special notes for your reviewer:

All 22 packages were previously at 0% unit test coverage. Tests cover predicates, deployment/config adapters, secret generation, service monitor configuration, and component options — the functions with real conditional logic. Pure boilerplate (NewComponent wiring) is intentionally excluded.

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
    • Added extensive unit tests across control-plane components (CAPI, CCMs, CCO, KCM, konnectivity, PKI, OLM, Karpenter, DNS, ignition server, machine approver, NTO, feature-gates, etc.). Tests validate manifest loading, deployment/config adaptations, service/monitor/cronjob behavior, TLS/secret handling, kubeconfig and kube-controller-manager logic, proxy/env propagation, and platform-specific scenarios to improve correctness and reliability.

@openshift-merge-bot
Copy link
Copy Markdown
Contributor

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: LGTM mode

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Apr 13, 2026
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 13, 2026

@bryan-cox: This pull request references CNTRLPLANE-3174 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

Summary

Adds behavior-driven unit tests for 22 previously untested v2 control-plane-operator controller packages, covering ~9,200 lines of new test code across 51 test files.

Packages covered

Commit Area Packages
1 CAPI v2/capi_manager, v2/capi_provider
2 Cloud providers v2/cloud_controller_manager/powervs, v2/cloud_credential_operator
3 Core controllers v2/kcm, konnectivity, v2/konnectivity_agent, v2/machine_approver, v2/pkioperator
4 Networking v2/dnsoperator, v2/ignitionserver_proxy
5 Workload v2/nto, v2/oauth_apiserver, v2/karpenteroperator
6 OLM v2/olm, v2/olm/catalog_operator, v2/olm/catalogs, v2/olm/collect_profiles, v2/olm/olm_operator, v2/olm/packageserver
7 Infrastructure v2/assets, v2/fg

Testing approach

Tests follow the behavior-driven-testing skill conventions:

  • Gherkin-style test names: "When <condition>, it should <behavior>"
  • gomega assertions with NewWithT(t) per subtest
  • t.Parallel() at both test function and subtest levels (except where t.Setenv is used)
  • Table-driven tests with validate func fields
  • Focus on testable behaviors (predicates, config builders, deployment adapters) — boilerplate wiring (NewComponent) is intentionally excluded

Jira

https://issues.redhat.com/browse/CNTRLPLANE-3174

🤖 Generated with Claude Code

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 openshift-eng/jira-lifecycle-plugin repository.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 13, 2026

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.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a large suite of unit tests across the hosted control plane operator. New table-driven, parallelized tests (using Gomega) were added for many packages and components (konnectivity, konnectivity_agent, CAPI manager/provider, cloud-controller-managers, cloud-credential-operator, dns-operator, feature-gate, ignitionserver proxy, Karpenter, kube-controller-manager, machine approver, node-tuning, oauth-apiserver, OLM components, PKI operator, and others). Tests cover predicates, component option methods, and adaptation logic for Deployments, Services, Secrets, ConfigMaps, Jobs, CronJobs, ServiceMonitors, manifest-loading helpers, and related helpers. No production code or exported/public API declarations were changed.


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Stable And Deterministic Test Names ❌ Error Test file service_test.go:344 uses dynamic test name with fmt.Sprintf and variable strategyType, violating deterministic naming requirement. Replace fmt.Sprintf dynamic test name with static string in test table like other 50+ test files in PR.
Docstring Coverage ⚠️ Warning Docstring coverage is 2.36% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test Structure And Quality ❓ Inconclusive Test files use standard Go testing.T with table-driven subtests and Gomega assertions, not Ginkgo framework as referenced in check requirements. Clarify whether check applies to standard Go testing.T or Ginkgo tests, then adapt requirements accordingly for proper assessment.
✅ Passed checks (7 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: adding unit tests for v2 CPO controller packages, with a Jira reference (CNTRLPLANE-3174) for context.
Microshift Test Compatibility ✅ Passed The custom check applies only to Ginkgo e2e tests, but this PR contains standard Go unit tests with func TestXXX(t *testing.T) patterns and Gomega assertions, not Ginkgo tests.
Single Node Openshift (Sno) Test Compatibility ✅ Passed PR adds unit tests using Go's standard testing package with table-driven patterns, not Ginkgo e2e tests. Tests validate internal logic with mocked dependencies in sandbox environment.
Topology-Aware Scheduling Compatibility ✅ Passed PR adds only test files (51 *_test.go files); no production code or deployment manifests modified; no new scheduling constraints introduced.
Ote Binary Stdout Contract ✅ Passed The added test code fully maintains the OTE binary stdout contract with no executable code or logging at module level that could emit non-JSON output.
Ipv6 And Disconnected Network Test Compatibility ✅ Passed PR adds standard Go unit tests with testing.T framework, not Ginkgo e2e tests. No Ginkgo imports found; uses only testing.T patterns.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 13, 2026

@bryan-cox: This pull request references CNTRLPLANE-3174 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

Summary

Adds behavior-driven unit tests for 22 previously untested v2 control-plane-operator controller packages, covering ~9,200 lines of new test code across 51 test files.

Packages covered

Commit Area Packages
1 CAPI v2/capi_manager, v2/capi_provider
2 Cloud providers v2/cloud_controller_manager/powervs, v2/cloud_credential_operator
3 Core controllers v2/kcm, konnectivity, v2/konnectivity_agent, v2/machine_approver, v2/pkioperator
4 Networking v2/dnsoperator, v2/ignitionserver_proxy
5 Workload v2/nto, v2/oauth_apiserver, v2/karpenteroperator
6 OLM v2/olm, v2/olm/catalog_operator, v2/olm/catalogs, v2/olm/collect_profiles, v2/olm/olm_operator, v2/olm/packageserver
7 Infrastructure v2/assets, v2/fg

Testing approach

Tests follow the behavior-driven-testing skill conventions:

  • Gherkin-style test names: "When <condition>, it should <behavior>"
  • gomega assertions with NewWithT(t) per subtest
  • t.Parallel() at both test function and subtest levels (except where t.Setenv is used)
  • Table-driven tests with validate func fields
  • Focus on testable behaviors (predicates, config builders, deployment adapters) — boilerplate wiring (NewComponent) is intentionally excluded

Jira

https://issues.redhat.com/browse/CNTRLPLANE-3174

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
  • Added comprehensive unit test coverage for multiple control-plane components including konnectivity, CAPI manager/provider, cloud controllers, DNS operator, feature gates, ignition server proxy, karpenter, KCM, node tuning, OAuth API server, OLM catalogs, and PKI operator.
  • Tests validate component options, predicate logic, deployment adaptation, configuration handling, and resource mutation behaviors.

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 openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot requested review from devguyio and jparrill April 13, 2026 12:38
@openshift-ci openshift-ci bot added area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/platform/powervs PR/issue for PowerVS (PowerVSPlatform) platform approved Indicates a PR has been approved by an approver from all required OWNERS files. and removed do-not-merge/needs-area labels Apr 13, 2026
@bryan-cox bryan-cox force-pushed the improve-ut-coverage branch from f4b530e to c6339f1 Compare April 13, 2026 12:40
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 13, 2026

@bryan-cox: This pull request references CNTRLPLANE-3174 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

Adds behavior-driven unit tests for 22 previously untested v2 control-plane-operator controller packages, covering ~9,200 lines of new test code across 51 test files. All packages were at 0% coverage before this PR.

Packages covered

Commit Area Packages
1 CAPI v2/capi_manager, v2/capi_provider
2 Cloud providers v2/cloud_controller_manager/powervs, v2/cloud_credential_operator
3 Core controllers v2/kcm, konnectivity, v2/konnectivity_agent, v2/machine_approver, v2/pkioperator
4 Networking v2/dnsoperator, v2/ignitionserver_proxy
5 Workload v2/nto, v2/oauth_apiserver, v2/karpenteroperator
6 OLM v2/olm, v2/olm/catalog_operator, v2/olm/catalogs, v2/olm/collect_profiles, v2/olm/olm_operator, v2/olm/packageserver
7 Infrastructure v2/assets, v2/fg

Testing approach

Tests follow the behavior-driven-testing skill conventions:

  • Gherkin-style test names: "When <condition>, it should <behavior>"
  • gomega assertions with NewWithT(t) per subtest
  • t.Parallel() at both test function and subtest levels (except where t.Setenv is used)
  • Table-driven tests with validate func fields
  • Focus on testable behaviors (predicates, config builders, deployment adapters) — boilerplate wiring (NewComponent) is intentionally excluded

Which issue(s) this PR fixes:

Fixes https://issues.redhat.com/browse/CNTRLPLANE-3174

Special notes for your reviewer:

All 22 packages were previously at 0% unit test coverage. Tests cover predicates, deployment/config adapters, secret generation, service monitor configuration, and component options — the functions with real conditional logic. Pure boilerplate (NewComponent wiring) is intentionally excluded.

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

🤖 Generated with Claude Code

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 openshift-eng/jira-lifecycle-plugin repository.

Copy link
Copy Markdown
Contributor

@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: 8

🧹 Nitpick comments (9)
control-plane-operator/controllers/hostedcontrolplane/konnectivity/params_test.go (1)

40-50: Consider validating the Reference field in the second test case.

The second test case validates that params and params.OwnerRef are not nil, but doesn't check the Reference field like the first test case does. Consider adding validation for the Reference field to ensure it handles empty metadata correctly (e.g., checking if Reference.Name is empty when ObjectMeta is empty).

💡 Suggested enhancement
 validate: func(t *testing.T, params *KonnectivityServiceParams) {
 	g := NewWithT(t)
 	g.Expect(params).ToNot(BeNil())
 	g.Expect(params.OwnerRef).ToNot(BeNil())
+	g.Expect(params.OwnerRef.Reference).ToNot(BeNil())
+	g.Expect(params.OwnerRef.Reference.Name).To(BeEmpty())
 },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/konnectivity/params_test.go`
around lines 40 - 50, The second test case for KonnectivityServiceParams (the
table entry named "When HCP has empty metadata it should still create params")
currently only asserts params and params.OwnerRef are non-nil; update its
validate function to also assert the params.Reference exists and that
params.Reference.Name is empty (or matches the expected empty-name behavior) to
mirror the first test's Reference validation and ensure empty
HostedControlPlane.ObjectMeta is handled correctly.
control-plane-operator/controllers/hostedcontrolplane/v2/kcm/deployment_test.go (1)

462-487: Stabilize parallel subtests by avoiding in-place mutation of shared test case state.

The test runs subtests in parallel (line 464: t.Parallel()) within an outer parallel test (line 30), creating a data race when multiple subtests concurrently modify the shared tc.existingObjects slice (line 478). Each subtest should work with its own copy to remain independent.

Create a local copy and use it instead:

Proposed refactor
 for _, tc := range tests {
+	tc := tc
 	t.Run(tc.name, func(t *testing.T) {
 		t.Parallel()
 
 		scheme := runtime.NewScheme()
 		_ = corev1.AddToScheme(scheme)
 
+		existingObjects := append([]client.Object(nil), tc.existingObjects...)
 		// Add feature-gate configmap if not already in existingObjects
 		hasFeatureGateConfigMap := false
-		for _, obj := range tc.existingObjects {
+		for _, obj := range existingObjects {
 			if cm, ok := obj.(*corev1.ConfigMap); ok && cm.Name == "feature-gate" {
 				hasFeatureGateConfigMap = true
 				break
 			}
 		}
 		if !hasFeatureGateConfigMap {
-			tc.existingObjects = append(tc.existingObjects, &corev1.ConfigMap{
+			existingObjects = append(existingObjects, &corev1.ConfigMap{
 				ObjectMeta: metav1.ObjectMeta{
 					Name:      "feature-gate",
 					Namespace: tc.hcp.Namespace,
 				},
 				Data: map[string]string{
 					"feature-gate.yaml": `{"apiVersion":"config.openshift.io/v1","kind":"FeatureGate","spec":{},"status":{"featureGates":[]}}`,
 				},
 			})
 		}
 
-		fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(tc.existingObjects...).Build()
+		fakeClient := fake.NewClientBuilder().WithScheme(scheme).WithObjects(existingObjects...).Build()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/kcm/deployment_test.go`
around lines 462 - 487, The subtests call t.Parallel() but mutate the shared
tc.existingObjects in-place when appending the "feature-gate" ConfigMap, causing
a data race; make a local copy of tc.existingObjects at the start of the subtest
(e.g., localExisting := append([]runtime.Object(nil), tc.existingObjects...))
and operate on that copy when checking/adding the ConfigMap so the test uses
localExisting instead of mutating tc.existingObjects; update any subsequent
references in the subtest to use the local copy (references: tc.existingObjects,
t.Parallel(), feature-gate ConfigMap creation).
control-plane-operator/controllers/hostedcontrolplane/v2/kcm/config_test.go (1)

88-90: The explicit tc := tc shadowing is optional and not required in Go 1.22+.

While the pattern can improve code clarity, it is not necessary for deterministic behavior with Go 1.25.3. Go 1.22 (released February 2024) fixed range-loop variable scoping semantics, ensuring variables are properly scoped per iteration. Additionally, the project convention shows this pattern is not used elsewhere in the codebase—other parallel table-driven tests like those in token-minter/tokenminter_test.go follow the same structure without shadowing. You may add it for explicit clarity if preferred, but it is not a correctness issue.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@control-plane-operator/controllers/hostedcontrolplane/v2/kcm/config_test.go`
around lines 88 - 90, The explicit per-iteration shadowing (tc := tc) in the
table-driven test loop is unnecessary with Go 1.22+ and inconsistent with
project convention; remove the redundant "tc := tc" from the test body around
t.Run so the loop uses the loop variable directly (the surrounding code to
change is the table loop over tests and the t.Run/t.Parallel block).
control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/deployment_test.go (1)

108-119: Tighten NO_PROXY assertions to exact host set.

Validating only host substrings can miss extra or malformed entries. Exact token comparison would make these cases more robust.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/deployment_test.go`
around lines 108 - 119, The test currently checks NO_PROXY by substring
containment; instead parse the found noProxyEnv.Value into comma-separated
tokens, trim whitespace and drop empty entries, then assert the token set
exactly matches tc.expectedNoProxyHosts (use a set-aware matcher such as
Gomega's ConsistOf or compare sorted slices) so extra or malformed entries are
detected; locate the logic around olmOperatorContainer.Env, noProxyEnv and
tc.expectedNoProxyHosts in deployment_test.go and replace the per-host
ContainSubstring loop with the exact-token comparison described.
control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go (1)

144-155: Prefer exact NO_PROXY token validation over substring checks.

Current ContainSubstring checks can pass even with malformed values or unexpected extra hosts. Consider asserting exact comma-token contents for stronger behavior verification.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go`
around lines 144 - 155, Replace the fragile substring assertions for the
NO_PROXY env var in deployment_test.go with exact token validation: locate the
NO_PROXY env var in packageServerContainer.Env, read noProxyEnv.Value, split by
commas, trim whitespace from each token, and compare the resulting slice/set to
tc.expectedNoProxyHosts using an equality or set-equality assertion (e.g.,
comparing sorted slices or using Gomega's ConsistOf) so the test verifies exact
comma-separated hosts regardless of order or extra spaces.
control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/powervs/deployment_test.go (1)

140-143: Prefer name-based volume assertions over index-based checks.

Line [140]-Line [143] depends on volume ordering, which makes the test fragile to harmless manifest reorderings.

Refactor idea
-		g.Expect(deployment.Spec.Template.Spec.Volumes).To(HaveLen(3))
-		g.Expect(deployment.Spec.Template.Spec.Volumes[0].Secret.SecretName).To(Equal("other-secret"))
-		g.Expect(deployment.Spec.Template.Spec.Volumes[1].Secret.SecretName).To(Equal("updated-creds"))
-		g.Expect(deployment.Spec.Template.Spec.Volumes[2].ConfigMap.Name).To(Equal("some-configmap"))
+		vols := map[string]corev1.Volume{}
+		for _, v := range deployment.Spec.Template.Spec.Volumes {
+			vols[v.Name] = v
+		}
+		g.Expect(vols).To(HaveLen(3))
+		g.Expect(vols["other-volume"].Secret.SecretName).To(Equal("other-secret"))
+		g.Expect(vols[cloudCredsVolumeName].Secret.SecretName).To(Equal("updated-creds"))
+		g.Expect(vols["yet-another-volume"].ConfigMap.Name).To(Equal("some-configmap"))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/powervs/deployment_test.go`
around lines 140 - 143, The test is fragile because it asserts volumes by index
on deployment.Spec.Template.Spec.Volumes; replace index-based checks with
name-based assertions that locate volumes by their volume.Name (or by matching
Secret.SecretName/ConfigMap.Name) and then assert their contents. Update the
assertions in deployment_test.go to either use a helper like
findVolumeByName(deployment.Spec.Template.Spec.Volumes, "volume-name") and then
check the returned volume's Secret.SecretName/ConfigMap.Name, or use Gomega's
ContainElement with a matcher that checks volume.Name and the nested
Secret/ConfigMap fields for "other-secret", "updated-creds", and
"some-configmap" so ordering no longer matters.
control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/deployment_test.go (1)

63-64: Select containers by name instead of fixed index.

Using Containers[0] makes these tests order-dependent and can validate the wrong container if manifest ordering changes.

♻️ Suggested refactor
- container := deploymentObj.Spec.Template.Spec.Containers[0]
+ var container *corev1.Container
+ for i := range deploymentObj.Spec.Template.Spec.Containers {
+ 	if deploymentObj.Spec.Template.Spec.Containers[i].Name == ComponentName {
+ 		container = &deploymentObj.Spec.Template.Spec.Containers[i]
+ 		break
+ 	}
+ }
+ g.Expect(container).ToNot(BeNil())

Also applies to: 112-113, 131-132, 155-156, 189-190

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/deployment_test.go`
around lines 63 - 64, Tests currently index into
deploymentObj.Spec.Template.Spec.Containers by position (Containers[0]) which is
order-dependent; change each assertion to locate the container by its Name field
(e.g., find the container where c.Name == "<expected-container-name>") and fail
the test if not found, then assert on c.Image (and other fields) for that named
container. Update all occurrences in deployment_test.go that reference
Containers[0] (including the other similar assertions) to use this name-based
lookup (or a small helper function like findContainerByName(deploymentObj,
name)) so the tests validate the intended container regardless of ordering.
control-plane-operator/controllers/hostedcontrolplane/v2/capi_provider/deployment_test.go (1)

174-177: Assert concrete proxy env vars, not just non-empty env list.

Current check can pass for unrelated env entries and miss proxy injection regressions.

🔍 Suggested assertion upgrade
 	// Check that proxy env vars are set on the container
 	container := deployment.Spec.Template.Spec.Containers[0]
-	g.Expect(len(container.Env)).To(BeNumerically(">", 0))
+	var hasHTTP, hasHTTPS, hasNO bool
+	for _, e := range container.Env {
+		switch e.Name {
+		case "HTTP_PROXY":
+			hasHTTP = true
+		case "HTTPS_PROXY":
+			hasHTTPS = true
+		case "NO_PROXY":
+			hasNO = true
+		}
+	}
+	g.Expect(hasHTTP).To(BeTrue())
+	g.Expect(hasHTTPS).To(BeTrue())
+	g.Expect(hasNO).To(BeTrue())
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/capi_provider/deployment_test.go`
around lines 174 - 177, The test currently only asserts container.Env is
non-empty; change it to assert for specific proxy env vars on the container
(inspect deployment.Spec.Template.Spec.Containers[0] -> container and its
container.Env slice) by checking that entries with Name "HTTP_PROXY",
"HTTPS_PROXY" and "NO_PROXY" (and their lowercase variants "http_proxy",
"https_proxy", "no_proxy" if you expect both) exist and have the expected
values; implement this by iterating container.Env or using the test helpers to
assert the presence of Env entries with those Name fields (and assert their
Value equals the expected proxy string if available) instead of the
len(container.Env) > 0 check.
control-plane-operator/controllers/hostedcontrolplane/v2/ignitionserver_proxy/service_test.go (1)

160-163: Strengthen the zero-NodePort assertion for the no-port case.

When expectedPort == 0, the test currently skips port assertion; asserting svc.Spec.Ports[0].NodePort == 0 would harden the intended behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/ignitionserver_proxy/service_test.go`
around lines 160 - 163, The test currently only asserts NodePort when
tc.expectedPort > 0; update the assertion logic around svc.Spec.Ports to
explicitly check the no-port case by asserting svc.Spec.Ports has length 1 and
that svc.Spec.Ports[0].NodePort == 0 when tc.expectedPort == 0, while keeping
the existing equality assertion when tc.expectedPort > 0 (referencing
tc.expectedPort and svc.Spec.Ports[0].NodePort).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@control-plane-operator/controllers/hostedcontrolplane/v2/capi_manager/deployment_test.go`:
- Around line 70-73: The test for version "4.18.0" currently only validates
presence of expectedArgs and misses asserting the absence of the
MachineSetPreflightChecks feature-gate; update the test in deployment_test.go
(the case with version "4.18.0" and expectedArgs == []string{}) to explicitly
assert that none of the actual container args contain
"--feature-gates=MachineSetPreflightChecks=false" (i.e., after the existing
positive checks, add a negative check that scans the actual args and fails if
any arg contains "MachineSetPreflightChecks=false"); reference the test case's
expectedArgs variable and the MachineSetPreflightChecks flag when adding this
assertion.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/cloud_credential_operator/deployment_test.go`:
- Around line 92-101: Test environment leaks because the test only sets
HTTP_PROXY/HTTPS_PROXY/NO_PROXY when tc.httpProxy, tc.httpsProxy, tc.noProxy are
non-empty, allowing host runner values to bleed into "no proxy" cases; update
the test setup in deployment_test.go to explicitly clear/unset these proxy env
vars when the test case value is empty (use t.Setenv("HTTP_PROXY", tc.httpProxy)
etc. with empty string for unset or call os.Unsetenv when tc.* is empty) so
every test case deterministically controls HTTP_PROXY, HTTPS_PROXY and NO_PROXY
regardless of runner environment.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/ignitionserver_proxy/deployment_test.go`:
- Around line 89-104: The test only asserts the presence of the trust-bundle
mount when tc.expectTrustBundleMount is true; add the complementary negative
assertion when tc.expectTrustBundleMount is false by checking the same
container(s) for absence of a mount with name tc.expectedVolumeName (e.g.,
inspect deployment.Spec.Template.Spec.Containers[0].VolumeMounts or iterate
containers and their VolumeMounts) and assert foundMount is false with
g.Expect(foundMount).To(BeFalse()) so regressions that inadvertently add the
trusted-ca mount are caught.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/kcm/kubeconfig_test.go`:
- Around line 109-111: The call to corev1.AddToScheme(scheme) currently ignores
its error; update the test to capture and check that error (e.g., err :=
corev1.AddToScheme(scheme)) and fail the test if non-nil using the test helper
in this file (e.g., t.Fatalf or require.NoError) before creating fakeClient with
fake.NewClientBuilder().WithScheme(scheme).WithObjects(...).Build(); this
ensures scheme registration problems are surfaced immediately when running
kubeconfig_test.go.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalog_operator/deployment_test.go`:
- Around line 140-151: The Guest-path NO_PROXY assertions only check for
presence of expected hosts and miss verifying that management-only hosts are
excluded; update the test in deployment_test.go to, after locating noProxyEnv
via catalogOperatorContainer.Env and asserting it is not nil and contains all
tc.expectedNoProxyHosts, also assert that the NO_PROXY string does NOT contain
any management-only/catalog-excluded hosts (add assertions against the known
management host names used in other tests or a new tc.unexpectedNoProxyHosts
list) so the guest case fails if management hosts are mistakenly included.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalogs/deployment_test.go`:
- Around line 84-157: The test currently calls the helper
checkCatalogImageOverides directly (reference checkCatalogImageOverides) so it
never exercises getCatalogImagesOverrides; either change the test to call
getCatalogImagesOverrides (reference getCatalogImagesOverrides) and supply the
necessary test doubles (a fake client or a minimal object with annotations and
the capabilityImageStream flag / image metadata provider) so the
annotation-to-map wiring and capability-driven branches are executed, or rename
the test to reflect it only validates the helper (e.g.,
TestCheckCatalogImageOverides) and keep the existing assertions; update the test
setup to construct the inputs required by getCatalogImagesOverrides (annotations
map on the resource and any mocked dependencies) and adjust the validate
closures to assert the returned map/error from getCatalogImagesOverrides
accordingly.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go`:
- Around line 157-161: The test misses the "no replica override" assertion: when
tc.expectedReplicas is nil you should assert that deployment.Spec.Replicas is
nil (or not set) to cover the negative path. Update the assertions around
tc.expectedReplicas in deployment_test.go so the if/else covers both
branches—keep the existing if (tc.expectedReplicas != nil) checks that
*deployment.Spec.Replicas equals *tc.expectedReplicas, and add an else that
calls g.Expect(deployment.Spec.Replicas).To(BeNil()) for the "it should not
override replicas" case (referencing tc.expectedReplicas and
deployment.Spec.Replicas).

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/pkioperator/deployment_test.go`:
- Around line 132-140: The test currently only calls t.Setenv for proxy env vars
when tc.httpProxy/tc.httpsProxy/tc.noProxy are non-empty, letting parent process
env leak into the "no proxy" case; always call t.Setenv for each of
"HTTP_PROXY", "HTTPS_PROXY", and "NO_PROXY" with the corresponding tc.httpProxy,
tc.httpsProxy, tc.noProxy values (allowing empty string to clear the variable)
so the tests are deterministic; update the block around the t.Setenv calls in
deployment_test.go (where tc and t are used) to unconditionally set those three
env vars for every test case.

---

Nitpick comments:
In
`@control-plane-operator/controllers/hostedcontrolplane/konnectivity/params_test.go`:
- Around line 40-50: The second test case for KonnectivityServiceParams (the
table entry named "When HCP has empty metadata it should still create params")
currently only asserts params and params.OwnerRef are non-nil; update its
validate function to also assert the params.Reference exists and that
params.Reference.Name is empty (or matches the expected empty-name behavior) to
mirror the first test's Reference validation and ensure empty
HostedControlPlane.ObjectMeta is handled correctly.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/capi_provider/deployment_test.go`:
- Around line 174-177: The test currently only asserts container.Env is
non-empty; change it to assert for specific proxy env vars on the container
(inspect deployment.Spec.Template.Spec.Containers[0] -> container and its
container.Env slice) by checking that entries with Name "HTTP_PROXY",
"HTTPS_PROXY" and "NO_PROXY" (and their lowercase variants "http_proxy",
"https_proxy", "no_proxy" if you expect both) exist and have the expected
values; implement this by iterating container.Env or using the test helpers to
assert the presence of Env entries with those Name fields (and assert their
Value equals the expected proxy string if available) instead of the
len(container.Env) > 0 check.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/powervs/deployment_test.go`:
- Around line 140-143: The test is fragile because it asserts volumes by index
on deployment.Spec.Template.Spec.Volumes; replace index-based checks with
name-based assertions that locate volumes by their volume.Name (or by matching
Secret.SecretName/ConfigMap.Name) and then assert their contents. Update the
assertions in deployment_test.go to either use a helper like
findVolumeByName(deployment.Spec.Template.Spec.Volumes, "volume-name") and then
check the returned volume's Secret.SecretName/ConfigMap.Name, or use Gomega's
ContainElement with a matcher that checks volume.Name and the nested
Secret/ConfigMap fields for "other-secret", "updated-creds", and
"some-configmap" so ordering no longer matters.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/ignitionserver_proxy/service_test.go`:
- Around line 160-163: The test currently only asserts NodePort when
tc.expectedPort > 0; update the assertion logic around svc.Spec.Ports to
explicitly check the no-port case by asserting svc.Spec.Ports has length 1 and
that svc.Spec.Ports[0].NodePort == 0 when tc.expectedPort == 0, while keeping
the existing equality assertion when tc.expectedPort > 0 (referencing
tc.expectedPort and svc.Spec.Ports[0].NodePort).

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/deployment_test.go`:
- Around line 63-64: Tests currently index into
deploymentObj.Spec.Template.Spec.Containers by position (Containers[0]) which is
order-dependent; change each assertion to locate the container by its Name field
(e.g., find the container where c.Name == "<expected-container-name>") and fail
the test if not found, then assert on c.Image (and other fields) for that named
container. Update all occurrences in deployment_test.go that reference
Containers[0] (including the other similar assertions) to use this name-based
lookup (or a small helper function like findContainerByName(deploymentObj,
name)) so the tests validate the intended container regardless of ordering.

In `@control-plane-operator/controllers/hostedcontrolplane/v2/kcm/config_test.go`:
- Around line 88-90: The explicit per-iteration shadowing (tc := tc) in the
table-driven test loop is unnecessary with Go 1.22+ and inconsistent with
project convention; remove the redundant "tc := tc" from the test body around
t.Run so the loop uses the loop variable directly (the surrounding code to
change is the table loop over tests and the t.Run/t.Parallel block).

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/kcm/deployment_test.go`:
- Around line 462-487: The subtests call t.Parallel() but mutate the shared
tc.existingObjects in-place when appending the "feature-gate" ConfigMap, causing
a data race; make a local copy of tc.existingObjects at the start of the subtest
(e.g., localExisting := append([]runtime.Object(nil), tc.existingObjects...))
and operate on that copy when checking/adding the ConfigMap so the test uses
localExisting instead of mutating tc.existingObjects; update any subsequent
references in the subtest to use the local copy (references: tc.existingObjects,
t.Parallel(), feature-gate ConfigMap creation).

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/deployment_test.go`:
- Around line 108-119: The test currently checks NO_PROXY by substring
containment; instead parse the found noProxyEnv.Value into comma-separated
tokens, trim whitespace and drop empty entries, then assert the token set
exactly matches tc.expectedNoProxyHosts (use a set-aware matcher such as
Gomega's ConsistOf or compare sorted slices) so extra or malformed entries are
detected; locate the logic around olmOperatorContainer.Env, noProxyEnv and
tc.expectedNoProxyHosts in deployment_test.go and replace the per-host
ContainSubstring loop with the exact-token comparison described.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go`:
- Around line 144-155: Replace the fragile substring assertions for the NO_PROXY
env var in deployment_test.go with exact token validation: locate the NO_PROXY
env var in packageServerContainer.Env, read noProxyEnv.Value, split by commas,
trim whitespace from each token, and compare the resulting slice/set to
tc.expectedNoProxyHosts using an equality or set-equality assertion (e.g.,
comparing sorted slices or using Gomega's ConsistOf) so the test verifies exact
comma-separated hosts regardless of order or extra spaces.
🪄 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: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1fac2b93-da00-4fa3-80a6-8104c1932bb5

📥 Commits

Reviewing files that changed from the base of the PR and between 783f795 and f4b530e.

⛔ Files ignored due to path filters (1)
  • control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/powervs/testdata/zz_fixture_TestAdaptConfig.yaml is excluded by !**/testdata/**
📒 Files selected for processing (50)
  • control-plane-operator/controllers/hostedcontrolplane/konnectivity/params_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/assets/assets_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/capi_manager/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/capi_manager/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/capi_manager/secret_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/capi_provider/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/capi_provider/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/capi_provider/role_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/powervs/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/powervs/config_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/cloud_controller_manager/powervs/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/cloud_credential_operator/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/cloud_credential_operator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/dnsoperator/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/dnsoperator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/fg/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/fg/job_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/ignitionserver_proxy/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/ignitionserver_proxy/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/ignitionserver_proxy/service_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/podmonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/secret_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/kcm/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/kcm/config_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/kcm/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/kcm/kubeconfig_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/kcm/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/konnectivity_agent/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/konnectivity_agent/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/machine_approver/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/machine_approver/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/nto/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/nto/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/nto/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalog_operator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalog_operator/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalogs/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalogs/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/collect_profiles/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/collect_profiles/cronjob_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/pkioperator/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/pkioperator/deployment_test.go

@bryan-cox bryan-cox force-pushed the improve-ut-coverage branch from c6339f1 to c832a62 Compare April 13, 2026 12:47
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 13, 2026

@bryan-cox: This pull request references CNTRLPLANE-3174 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

Adds behavior-driven unit tests for 22 previously untested v2 control-plane-operator controller packages, covering ~9,200 lines of new test code across 51 test files. All packages were at 0% coverage before this PR.

Packages covered

Commit Area Packages
1 CAPI v2/capi_manager, v2/capi_provider
2 Cloud providers v2/cloud_controller_manager/powervs, v2/cloud_credential_operator
3 Core controllers v2/kcm, konnectivity, v2/konnectivity_agent, v2/machine_approver, v2/pkioperator
4 Networking v2/dnsoperator, v2/ignitionserver_proxy
5 Workload v2/nto, v2/oauth_apiserver, v2/karpenteroperator
6 OLM v2/olm, v2/olm/catalog_operator, v2/olm/catalogs, v2/olm/collect_profiles, v2/olm/olm_operator, v2/olm/packageserver
7 Infrastructure v2/assets, v2/fg

Testing approach

Tests follow the behavior-driven-testing skill conventions:

  • Gherkin-style test names: "When <condition>, it should <behavior>"
  • gomega assertions with NewWithT(t) per subtest
  • t.Parallel() at both test function and subtest levels (except where t.Setenv is used)
  • Table-driven tests with validate func fields
  • Focus on testable behaviors (predicates, config builders, deployment adapters) — boilerplate wiring (NewComponent) is intentionally excluded

Which issue(s) this PR fixes:

Fixes https://issues.redhat.com/browse/CNTRLPLANE-3174

Special notes for your reviewer:

All 22 packages were previously at 0% unit test coverage. Tests cover predicates, deployment/config adapters, secret generation, service monitor configuration, and component options — the functions with real conditional logic. Pure boilerplate (NewComponent wiring) is intentionally excluded.

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
  • Expanded comprehensive unit test coverage across hosted control plane components (konnectivity, CAPI manager/provider, cloud controllers, DNS, feature gates, ignition proxy, karpenter, KCM, node tuning, OAuth APIServer, OLM, PKI, machine approver, NTO, etc.).
  • Tests validate component options/predicates, deployment/adaptation, config/template handling, secrets/manifests, service/PodMonitor/ServiceMonitor behaviors, cronjob scheduling, and error cases.

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 openshift-eng/jira-lifecycle-plugin repository.

Copy link
Copy Markdown
Contributor

@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: 3

♻️ Duplicate comments (1)
control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go (1)

123-127: ⚠️ Potential issue | 🟡 Minor

Missing assertion for the “no replica override” path.

At Line 157-Line 161, tests only assert the override path. The expectedReplicas == nil branch still doesn't verify the deployment replicas remained unchanged.

Suggested fix
 			deployment, err := assets.LoadDeploymentManifest(ComponentName)
 			g.Expect(err).ToNot(HaveOccurred())
+			var originalReplicas *int32
+			if deployment.Spec.Replicas != nil {
+				v := *deployment.Spec.Replicas
+				originalReplicas = &v
+			}
@@
 			if tc.expectedReplicas != nil {
 				g.Expect(deployment.Spec.Replicas).ToNot(BeNil())
 				g.Expect(*deployment.Spec.Replicas).To(Equal(*tc.expectedReplicas))
+			} else {
+				g.Expect(deployment.Spec.Replicas).To(Equal(originalReplicas))
 			}

Also applies to: 157-161

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go`
around lines 123 - 127, The test currently only asserts the replica-override
branch; add an assertion for the "no replica override" path so that when
expectedReplicas == nil the deployment's replica count is unchanged after
calling adaptDeployment. Locate the test that calls
assets.LoadDeploymentManifest(ComponentName) and adaptDeployment(cpContext,
deployment) and add a check comparing deployment.Spec.Replicas (or the pointer
value) to the original value saved before adaptDeployment when expectedReplicas
is nil; ensure you reference the deployment variable, adaptDeployment function,
and expectedReplicas in the assertion.
🧹 Nitpick comments (7)
control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/component_test.go (1)

32-42: Extract the repeated Karpenter AutoNode fixture for maintainability.

The same enabled-Karpenter object literal is repeated in multiple cases. A small helper would reduce duplication and make future updates safer.

♻️ Proposed refactor
+func enabledKarpenterAutoNode() *hyperv1.AutoNode {
+	return &hyperv1.AutoNode{
+		Provisioner: hyperv1.ProvisionerConfig{
+			Name: hyperv1.ProvisionerKarpenter,
+			Karpenter: &hyperv1.KarpenterConfig{
+				Platform: hyperv1.AWSPlatform,
+				AWS: &hyperv1.KarpenterAWSConfig{
+					RoleARN: "arn:aws:iam::123456789012:role/karpenter",
+				},
+			},
+		},
+	}
+}
...
- autoNode: &hyperv1.AutoNode{ ... },
+ autoNode: enabledKarpenterAutoNode(),

Also applies to: 72-82, 89-99

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/component_test.go`
around lines 32 - 42, Extract the repeated Karpenter AutoNode literal into a
small test helper (e.g., makeKarpenterAutoNode or newKarpenterAutoNode) that
returns *hyperv1.AutoNode populated with Provisioner:
hyperv1.ProvisionerConfig{Name: hyperv1.ProvisionerKarpenter, Karpenter:
&hyperv1.KarpenterConfig{Platform: hyperv1.AWSPlatform, AWS:
&hyperv1.KarpenterAWSConfig{RoleARN:
"arn:aws:iam::123456789012:role/karpenter"}}}; replace the inline literals in
the component_test.go cases that construct AutoNode (the instances using
AutoNode, Provisioner, KarpenterConfig, KarpenterAWSConfig) with calls to this
helper to remove duplication and reuse across other test cases.
control-plane-operator/controllers/hostedcontrolplane/v2/nto/deployment_test.go (2)

137-162: Tighten the fake provider to validate component-key usage.

Because GetImage ignores componentName, the test can’t catch wrong component lookups. Make the fake key-aware so incorrect keys fail assertions.

🧪 Suggested stricter fake
 type fakeReleaseImageProvider struct {
 	version string
-	image   string
+	images  map[string]string
 }
@@
 func (f *fakeReleaseImageProvider) GetImage(componentName string) string {
-	return f.image
+	return f.images[componentName]
 }
 
 func (f *fakeReleaseImageProvider) ImageExist(name string) (string, bool) {
-	return f.image, true
+	image, ok := f.images[name]
+	return image, ok
 }
@@
 func (f *fakeReleaseImageProvider) ComponentImages() map[string]string {
-	return map[string]string{
-		ComponentName: f.image,
-	}
+	return f.images
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/nto/deployment_test.go`
around lines 137 - 162, The fakeReleaseImageProvider currently ignores the
componentName argument so tests can't detect wrong lookups; update
fakeReleaseImageProvider to be key-aware by storing a map[string]string (or the
expected key) and have GetImage(componentName string), ImageExist(name string)
and ComponentImages() validate the provided componentName against that map
(returning the matching image when present and an empty string/false when
absent, or fail the test/assert/panic on unexpected keys) so incorrect component
keys cause test failures; ensure references to ComponentName in ComponentImages
still return the correct image from the new map.

107-116: Make the “updates existing env vars” case deterministic.

This test currently depends on manifest internals. Seed the env vars explicitly before calling adaptDeployment, and guard Containers before indexing so failures are clearer.

♻️ Suggested test hardening
 deployment, err := assets.LoadDeploymentManifest(ComponentName)
 g.Expect(err).ToNot(HaveOccurred())
+g.Expect(deployment.Spec.Template.Spec.Containers).ToNot(BeEmpty())
+container := &deployment.Spec.Template.Spec.Containers[0]
+container.Env = []corev1.EnvVar{
+	{Name: "RELEASE_VERSION", Value: "old-version"},
+	{Name: "CLUSTER_NODE_TUNED_IMAGE", Value: "old-image"},
+	{Name: "UNCHANGED_ENV", Value: "keep"},
+}
 
 // The deployment manifest already has these env vars with empty values,
 // so adaptDeployment should update them
 err = adaptDeployment(cpContext, deployment)
 g.Expect(err).ToNot(HaveOccurred())
 
-container := deployment.Spec.Template.Spec.Containers[0]
+updatedContainer := deployment.Spec.Template.Spec.Containers[0]
@@
-for _, env := range container.Env {
+for _, env := range updatedContainer.Env {

Also applies to: 110-113

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/nto/deployment_test.go`
around lines 107 - 116, The test relies on manifest internals; make it
deterministic by explicitly setting the container and its env vars on the loaded
deployment before calling adaptDeployment and checking results: after loading
deployment via assets.LoadDeploymentManifest(ComponentName) set
deployment.Spec.Template.Spec.Containers to contain at least one core container
(e.g., ensure a container exists and set container.Env entries for the keys the
test expects), then call adaptDeployment(cpContext, deployment); also add a
guard that deployment.Spec.Template.Spec.Containers has length > 0 before
indexing into Containers[0] so failures are clearer (reference: deployment,
adaptDeployment, Containers, Env).
control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/secret_test.go (1)

20-24: Remove redundant expectedRoleARN from test cases.

expectedRoleARN mirrors roleARN in every case, so it adds noise without extra validation value.

♻️ Suggested simplification
 	testCases := []struct {
 		name                string
 		roleARN             string
-		expectedRoleARN     string
 		validateCredentials func(t *testing.T, g Gomega, credentials string)
 	}{
 		{
 			name:            "When AWS role ARN is provided, it should generate correct credentials format",
 			roleARN:         "arn:aws:iam::123456789012:role/karpenter-role",
-			expectedRoleARN: "arn:aws:iam::123456789012:role/karpenter-role",
 			validateCredentials: func(t *testing.T, g Gomega, credentials string) {
@@
 		{
 			name:            "When different role ARN format is provided, it should be included correctly",
 			roleARN:         "arn:aws:iam::999999999999:role/my-custom-karpenter-role",
-			expectedRoleARN: "arn:aws:iam::999999999999:role/my-custom-karpenter-role",
 			validateCredentials: func(t *testing.T, g Gomega, credentials string) {
@@
 		{
 			name:            "When role ARN has path component, it should be preserved",
 			roleARN:         "arn:aws:iam::111111111111:role/path/to/role/karpenter",
-			expectedRoleARN: "arn:aws:iam::111111111111:role/path/to/role/karpenter",
 			validateCredentials: func(t *testing.T, g Gomega, credentials string) {
@@
-			g.Expect(credentials).To(ContainSubstring(tc.expectedRoleARN))
+			g.Expect(credentials).To(ContainSubstring(tc.roleARN))

Also applies to: 27-30, 39-42, 48-51, 109-110

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/secret_test.go`
around lines 20 - 24, Remove the redundant expectedRoleARN field from the test
case structs and all references to it in the tests: simplify the testCases
declaration by keeping only name and roleARN (and validateCredentials), update
any table-driven test iterations to assert against roleARN directly (or remove
assertions that compared expectedRoleARN to roleARN), and delete the now-unused
expectedRoleARN variable occurrences; specifically update the testCases variable
and any uses in the test helper logic that referenced expectedRoleARN so tests
still validate credentials using roleARN only.
control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/deployment_test.go (1)

3-14: Strengthen NO_PROXY assertion to avoid false positives.

At Line 117-Line 119, ContainSubstring only proves inclusion, not correctness of the full host set. This can miss regressions where unexpected hosts are added.

Suggested test hardening
 import (
+	"strings"
 	"testing"
@@
 			g.Expect(noProxyEnv).ToNot(BeNil())
-			for _, host := range tc.expectedNoProxyHosts {
-				g.Expect(noProxyEnv.Value).To(ContainSubstring(host))
-			}
+			actualNoProxyHosts := strings.Split(noProxyEnv.Value, ",")
+			g.Expect(actualNoProxyHosts).To(ConsistOf(tc.expectedNoProxyHosts))
 		})
 	}
 }

Also applies to: 109-119

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/deployment_test.go`
around lines 3 - 14, The test currently uses ContainSubstring against the
NO_PROXY env var which can yield false positives; update the assertion that
inspects the env var named "NO_PROXY" (the test that retrieves env :=
findEnvVar(envs, "NO_PROXY") or similar) to assert the full exact value instead
of a substring (e.g., Expect(env.Value).To(Equal(expectedNoProxy)) or use a
strict regex) and construct expectedNoProxy from the exact host list used by the
deployment (join the known hosts into the exact string you expect) so the test
fails when extra/unexpected hosts are present.
control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go (1)

3-14: Use exact host-set matching for NO_PROXY expectations.

At Line 153-Line 155, substring matching is permissive and can hide extra/unexpected entries in NO_PROXY.

Suggested test hardening
 import (
+	"strings"
 	"testing"
@@
 			g.Expect(noProxyEnv).ToNot(BeNil())
-			for _, host := range tc.expectedNoProxyHosts {
-				g.Expect(noProxyEnv.Value).To(ContainSubstring(host))
-			}
+			actualNoProxyHosts := strings.Split(noProxyEnv.Value, ",")
+			g.Expect(actualNoProxyHosts).To(ConsistOf(tc.expectedNoProxyHosts))

Also applies to: 145-155

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go`
around lines 3 - 14, The test currently uses permissive substring matching to
assert the container env var "NO_PROXY"; change the assertion in
deployment_test.go to parse the NO_PROXY value by splitting on commas, trimming
whitespace, and compare the resulting host set exactly against the expected host
set (order-insensitive) instead of using substring/Contains checks so
extra/unexpected entries are detected; update the assertion logic where the test
inspects the container env var named "NO_PROXY" to perform this exact set
comparison.
control-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/deployment_test.go (1)

25-28: Drop the unused err parameter from validate.

Every subtest passes nil here, so the leading Expect(err).ToNot(HaveOccurred()) checks in each validator never verify anything. Removing that parameter will make the table setup a lot clearer.

Also applies to: 494-500

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/deployment_test.go`
around lines 25 - 28, The table-driven tests define validate as func(*testing.T,
*GomegaWithT, *hyperv1.HostedControlPlane, error) but always pass nil for the
error; remove the unused err parameter by changing the validate signature to
func(*testing.T, *GomegaWithT, *hyperv1.HostedControlPlane) for the testCases in
deployment_test.go (and the duplicate occurrence around the 494-500 region),
then update all validate call sites in the subtest loop to stop passing nil and
remove any Expect(err).ToNot(HaveOccurred()) checks inside the individual
validator functions so they only accept (*testing.T, *GomegaWithT,
*hyperv1.HostedControlPlane); ensure references to validate, testCases,
GomegaWithT, HostedControlPlane, and Expect(err) are updated accordingly to keep
compilation passing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/secret_test.go`:
- Around line 157-178: The test currently claims to verify the "exact format"
but uses normalizeWhitespace; remove that normalization and assert the raw
credentials string equals the expected string instead: use
g.Expect(credentials).To(Equal(expected)) and keep expectedTemplate/expected
as-is (ensure expected includes the exact final newline and spacing you expect),
so the comparison uses the actual credentials value and will catch
whitespace/formatting regressions; update or remove the normalizeWhitespace
function and adjust the test comment to reflect it now enforces exact match.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/deployment_test.go`:
- Around line 362-377: The test must assert the precondition that the base
deployment contains the "audit-logs" container before calling adaptDeployment;
locate the container with findContainer("audit-logs",
deployment.Spec.Template.Spec.Containers) immediately after loading the manifest
and use g.Expect(container).ToNot(BeNil()) to ensure it exists, then call
adaptDeployment(cpContext, deployment) and finally assert the container was
removed with g.Expect(findContainer("audit-logs",
deployment.Spec.Template.Spec.Containers)).To(BeNil()); this uses the existing
symbols deployment, findContainer, adaptDeployment, cpContext and the Gomega
g.Expect assertions.

---

Duplicate comments:
In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go`:
- Around line 123-127: The test currently only asserts the replica-override
branch; add an assertion for the "no replica override" path so that when
expectedReplicas == nil the deployment's replica count is unchanged after
calling adaptDeployment. Locate the test that calls
assets.LoadDeploymentManifest(ComponentName) and adaptDeployment(cpContext,
deployment) and add a check comparing deployment.Spec.Replicas (or the pointer
value) to the original value saved before adaptDeployment when expectedReplicas
is nil; ensure you reference the deployment variable, adaptDeployment function,
and expectedReplicas in the assertion.

---

Nitpick comments:
In
`@control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/component_test.go`:
- Around line 32-42: Extract the repeated Karpenter AutoNode literal into a
small test helper (e.g., makeKarpenterAutoNode or newKarpenterAutoNode) that
returns *hyperv1.AutoNode populated with Provisioner:
hyperv1.ProvisionerConfig{Name: hyperv1.ProvisionerKarpenter, Karpenter:
&hyperv1.KarpenterConfig{Platform: hyperv1.AWSPlatform, AWS:
&hyperv1.KarpenterAWSConfig{RoleARN:
"arn:aws:iam::123456789012:role/karpenter"}}}; replace the inline literals in
the component_test.go cases that construct AutoNode (the instances using
AutoNode, Provisioner, KarpenterConfig, KarpenterAWSConfig) with calls to this
helper to remove duplication and reuse across other test cases.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/secret_test.go`:
- Around line 20-24: Remove the redundant expectedRoleARN field from the test
case structs and all references to it in the tests: simplify the testCases
declaration by keeping only name and roleARN (and validateCredentials), update
any table-driven test iterations to assert against roleARN directly (or remove
assertions that compared expectedRoleARN to roleARN), and delete the now-unused
expectedRoleARN variable occurrences; specifically update the testCases variable
and any uses in the test helper logic that referenced expectedRoleARN so tests
still validate credentials using roleARN only.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/nto/deployment_test.go`:
- Around line 137-162: The fakeReleaseImageProvider currently ignores the
componentName argument so tests can't detect wrong lookups; update
fakeReleaseImageProvider to be key-aware by storing a map[string]string (or the
expected key) and have GetImage(componentName string), ImageExist(name string)
and ComponentImages() validate the provided componentName against that map
(returning the matching image when present and an empty string/false when
absent, or fail the test/assert/panic on unexpected keys) so incorrect component
keys cause test failures; ensure references to ComponentName in ComponentImages
still return the correct image from the new map.
- Around line 107-116: The test relies on manifest internals; make it
deterministic by explicitly setting the container and its env vars on the loaded
deployment before calling adaptDeployment and checking results: after loading
deployment via assets.LoadDeploymentManifest(ComponentName) set
deployment.Spec.Template.Spec.Containers to contain at least one core container
(e.g., ensure a container exists and set container.Env entries for the keys the
test expects), then call adaptDeployment(cpContext, deployment); also add a
guard that deployment.Spec.Template.Spec.Containers has length > 0 before
indexing into Containers[0] so failures are clearer (reference: deployment,
adaptDeployment, Containers, Env).

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/deployment_test.go`:
- Around line 25-28: The table-driven tests define validate as func(*testing.T,
*GomegaWithT, *hyperv1.HostedControlPlane, error) but always pass nil for the
error; remove the unused err parameter by changing the validate signature to
func(*testing.T, *GomegaWithT, *hyperv1.HostedControlPlane) for the testCases in
deployment_test.go (and the duplicate occurrence around the 494-500 region),
then update all validate call sites in the subtest loop to stop passing nil and
remove any Expect(err).ToNot(HaveOccurred()) checks inside the individual
validator functions so they only accept (*testing.T, *GomegaWithT,
*hyperv1.HostedControlPlane); ensure references to validate, testCases,
GomegaWithT, HostedControlPlane, and Expect(err) are updated accordingly to keep
compilation passing.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/deployment_test.go`:
- Around line 3-14: The test currently uses ContainSubstring against the
NO_PROXY env var which can yield false positives; update the assertion that
inspects the env var named "NO_PROXY" (the test that retrieves env :=
findEnvVar(envs, "NO_PROXY") or similar) to assert the full exact value instead
of a substring (e.g., Expect(env.Value).To(Equal(expectedNoProxy)) or use a
strict regex) and construct expectedNoProxy from the exact host list used by the
deployment (join the known hosts into the exact string you expect) so the test
fails when extra/unexpected hosts are present.

In
`@control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go`:
- Around line 3-14: The test currently uses permissive substring matching to
assert the container env var "NO_PROXY"; change the assertion in
deployment_test.go to parse the NO_PROXY value by splitting on commas, trimming
whitespace, and compare the resulting host set exactly against the expected host
set (order-insensitive) instead of using substring/Contains checks so
extra/unexpected entries are detected; update the assertion logic where the test
inspects the container env var named "NO_PROXY" to perform this exact set
comparison.
🪄 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: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 8606e8ef-9f91-4570-916b-53af43f3642b

📥 Commits

Reviewing files that changed from the base of the PR and between f4b530e and c832a62.

📒 Files selected for processing (22)
  • control-plane-operator/controllers/hostedcontrolplane/v2/assets/assets_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/fg/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/fg/job_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/podmonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/secret_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/nto/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/nto/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/nto/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalog_operator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalog_operator/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalogs/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalogs/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/collect_profiles/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/collect_profiles/cronjob_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/packageserver/deployment_test.go
✅ Files skipped from review due to trivial changes (10)
  • control-plane-operator/controllers/hostedcontrolplane/v2/fg/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/nto/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/collect_profiles/cronjob_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/oauth_apiserver/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalogs/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalog_operator/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/podmonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/fg/job_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalogs/deployment_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/karpenteroperator/deployment_test.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/olm_operator/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/collect_profiles/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/component_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/nto/servicemonitor_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/assets/assets_test.go
  • control-plane-operator/controllers/hostedcontrolplane/v2/olm/catalog_operator/deployment_test.go

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 13, 2026

Codecov Report

❌ Patch coverage is 38.29787% with 29 lines in your changes missing coverage. Please review.
✅ Project coverage is 35.61%. Comparing base (916b455) to head (5b7f608).
⚠️ Report is 29 commits behind head on main.

Files with missing lines Patch % Lines
support/testutil/fake.go 0.00% 29 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8215      +/-   ##
==========================================
+ Coverage   34.65%   35.61%   +0.96%     
==========================================
  Files         767      767              
  Lines       93263    93306      +43     
==========================================
+ Hits        32318    33231     +913     
+ Misses      58266    57388     -878     
- Partials     2679     2687       +8     
Files with missing lines Coverage Δ
support/util/containers.go 36.18% <100.00%> (+13.04%) ⬆️
support/testutil/fake.go 0.00% <0.00%> (ø)

... and 51 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@bryan-cox bryan-cox force-pushed the improve-ut-coverage branch from c832a62 to ccae78e Compare April 13, 2026 13:04
@openshift-ci-robot
Copy link
Copy Markdown

openshift-ci-robot commented Apr 13, 2026

@bryan-cox: This pull request references CNTRLPLANE-3174 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "4.22.0" version, but no target version was set.

Details

In response to this:

What this PR does / why we need it:

Adds behavior-driven unit tests for 22 previously untested v2 control-plane-operator controller packages, covering ~9,200 lines of new test code across 51 test files. All packages were at 0% coverage before this PR.

Packages covered

Commit Area Packages
1 CAPI v2/capi_manager, v2/capi_provider
2 Cloud providers v2/cloud_controller_manager/powervs, v2/cloud_credential_operator
3 Core controllers v2/kcm, konnectivity, v2/konnectivity_agent, v2/machine_approver, v2/pkioperator
4 Networking v2/dnsoperator, v2/ignitionserver_proxy
5 Workload v2/nto, v2/oauth_apiserver, v2/karpenteroperator
6 OLM v2/olm, v2/olm/catalog_operator, v2/olm/catalogs, v2/olm/collect_profiles, v2/olm/olm_operator, v2/olm/packageserver
7 Infrastructure v2/assets, v2/fg

Testing approach

Tests follow the behavior-driven-testing skill conventions:

  • Gherkin-style test names: "When <condition>, it should <behavior>"
  • gomega assertions with NewWithT(t) per subtest
  • t.Parallel() at both test function and subtest levels (except where t.Setenv is used)
  • Table-driven tests with validate func fields
  • Focus on testable behaviors (predicates, config builders, deployment adapters) — boilerplate wiring (NewComponent) is intentionally excluded

Which issue(s) this PR fixes:

Fixes https://issues.redhat.com/browse/CNTRLPLANE-3174

Special notes for your reviewer:

All 22 packages were previously at 0% unit test coverage. Tests cover predicates, deployment/config adapters, secret generation, service monitor configuration, and component options — the functions with real conditional logic. Pure boilerplate (NewComponent wiring) is intentionally excluded.

Checklist:

  • Subject and description added to both, commit and PR.
  • Relevant issues have been referenced.
  • This change includes docs.
  • This change includes unit tests.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests
  • Vastly expanded unit and integration test coverage across hosted control plane components and cloud providers, covering predicates/options, deployment/adaptation, config/template generation, secrets/credentials, service/monitoring manifests, cronjobs/schedules, env/proxy handling, IAM/Route53/KMS workflows, snapshot/etcd restore logic, metrics reporting, and error paths.

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 openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot added area/api Indicates the PR includes changes for the API area/cli Indicates the PR includes changes for CLI area/documentation Indicates the PR includes changes for documentation area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release area/platform/aws PR/issue for AWS (AWSPlatform) platform area/platform/kubevirt PR/issue for KubeVirt (KubevirtPlatform) platform and removed approved Indicates a PR has been approved by an approver from all required OWNERS files. labels Apr 13, 2026
@bryan-cox bryan-cox force-pushed the improve-ut-coverage branch from ccae78e to a422450 Compare April 13, 2026 13:05
@openshift-ci openshift-ci bot added the area/testing Indicates the PR includes changes for e2e testing label Apr 13, 2026
@openshift-ci-robot
Copy link
Copy Markdown

@jparrill: This PR has been marked as verified by UnitTests.

Details

In response to this:

/verified by UnitTests

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 openshift-eng/jira-lifecycle-plugin repository.

@bryan-cox
Copy link
Copy Markdown
Member Author

/verified by ut

@openshift-ci-robot
Copy link
Copy Markdown

@bryan-cox: This PR has been marked as verified by ut.

Details

In response to this:

/verified by ut

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 openshift-eng/jira-lifecycle-plugin repository.

bryan-cox and others added 5 commits April 15, 2026 09:45
Add behavior-driven unit tests for KCM, konnectivity, machine approver,
and PKI operator v2 controller packages covering config adaptation,
deployment adaptation, predicates, and kubeconfig generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add behavior-driven unit tests for the DNS operator and ignition server
proxy v2 controller packages covering deployment adaptation, service
configuration, and component predicates.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add behavior-driven unit tests for the NTO, OAuth API server, and
Karpenter operator v2 controller packages covering deployment adaptation,
service monitor configuration, predicates, and secret generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add behavior-driven unit tests for all OLM v2 controller sub-packages
including catalog operator, catalogs, collect profiles, OLM operator,
and packageserver covering deployment adaptation, service monitors,
predicates, and cron schedule generation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add behavior-driven unit tests for the assets and feature gate v2
controller packages covering manifest loading, deserialization,
iteration, and feature gate job adaptation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bryan-cox bryan-cox force-pushed the improve-ut-coverage branch from 3f05aa5 to 5b7f608 Compare April 15, 2026 13:45
@openshift-ci-robot openshift-ci-robot removed the verified Signifies that the PR passed pre-merge verification criteria label Apr 15, 2026
@openshift-ci openshift-ci bot removed the lgtm Indicates that a PR is ready to be merged. label Apr 15, 2026
@jparrill
Copy link
Copy Markdown
Contributor

/lgtm

@jparrill
Copy link
Copy Markdown
Contributor

/verified by UnitTests

@openshift-ci-robot openshift-ci-robot added the verified Signifies that the PR passed pre-merge verification criteria label Apr 15, 2026
@openshift-ci-robot
Copy link
Copy Markdown

@jparrill: This PR has been marked as verified by UnitTests.

Details

In response to this:

/verified by UnitTests

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 openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci openshift-ci bot added the lgtm Indicates that a PR is ready to be merged. label Apr 15, 2026
@openshift-merge-bot
Copy link
Copy Markdown
Contributor

Scheduling tests matching the pipeline_run_if_changed or not excluded by pipeline_skip_if_only_changed parameters:
/test e2e-aks
/test e2e-aws
/test e2e-aws-upgrade-hypershift-operator
/test e2e-azure-self-managed
/test e2e-kubevirt-aws-ovn-reduced
/test e2e-v2-aws

@bryan-cox
Copy link
Copy Markdown
Member Author

/verified by ut

@openshift-ci-robot
Copy link
Copy Markdown

@bryan-cox: This PR has been marked as verified by ut.

Details

In response to this:

/verified by ut

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 openshift-eng/jira-lifecycle-plugin repository.

@hypershift-jira-solve-ci
Copy link
Copy Markdown

AI Test Failure Analysis

Job: pull-ci-openshift-hypershift-main-e2e-aks | Build: 2044422524602683392 | Cost: $1.91997075 | Failed step: hypershift-azure-run-e2e

View full analysis report


Generated by hypershift-analyze-e2e-failure post-step using Claude claude-opus-4-6

@hypershift-jira-solve-ci
Copy link
Copy Markdown

I now have all the evidence needed. Let me compile the complete analysis. The pattern is clear:

  1. ALL 7 tests that require External DNS to create DNS records for api-*.aks-e2e.hypershift.azure.devcluster.openshift.com failed identically — DNS lookups returned no such host
  2. TestHAEtcdChaos PASSED — it uses platform None and doesn't need External DNS
  3. TestCreateClusterDefaultSecurityContextUID PASSED — it only validates namespace UIDs, not hosted cluster connectivity
  4. The PR (CNTRLPLANE-3174: Add unit tests for v2 CPO controller packages #8215) modifies only unit test files (*_test.go) — zero production code changes
  5. The failure is an Azure External DNS infrastructure issue, not a code regression

Test Failure Analysis Complete

Job Information

Test Failure Analysis

Error

dial tcp: lookup api-*.aks-e2e.hypershift.azure.devcluster.openshift.com on 10.0.0.10:53: no such host

KASLoadBalancerNotReachable / ExternalDNSHostNotReachable — all 7 hosted clusters
that depend on Azure External DNS failed to have their API DNS records created.
NoWorkerNodesAvailable — no worker nodes joined any of the 7 affected clusters.

Summary

All 7 Azure-platform hosted cluster tests (TestAutoscaling, TestCreateCluster, TestCreateClusterCustomConfig, TestNodePool/HostedCluster0, TestNodePool/HostedCluster2, TestAzureScheduler, TestUpgradeControlPlane) failed identically during ValidateHostedCluster because Azure External DNS never created DNS records for their API endpoints (api-*.aks-e2e.hypershift.azure.devcluster.openshift.com). This is an Azure DNS infrastructure issue — the PR only adds unit test files (*_test.go) and modifies zero production code. Tests that do not depend on External DNS (TestHAEtcdChaos using platform None, TestCreateClusterDefaultSecurityContextUID) passed successfully.

Root Cause

The root cause is an Azure External DNS infrastructure failure in the aks-e2e.hypershift.azure.devcluster.openshift.com DNS zone. This is external to the code under test.

Failure chain:

  1. Hosted clusters were successfully created (all 7 reported Successfully created hostedcluster within ~2m27s)
  2. Kubeconfig secrets were published successfully for all clusters (1m21s–2m3s)
  3. Immediately after kubeconfig publication, DNS lookups for api-*.aks-e2e.hypershift.azure.devcluster.openshift.com returned no such host — External DNS failed to create the required A/CNAME records in Azure DNS
  4. Without DNS resolution, the KAS load balancer was unreachable (KASLoadBalancerNotReachable)
  5. Without a reachable API server, no worker nodes could bootstrap (NoWorkerNodesAvailable)
  6. Without workers, cluster operators (console, dns, image-registry, ingress, insights, kube-storage-version-migrator, monitoring, node-tuning, openshift-samples, service-ca, storage) never became available
  7. All ValidateHostedCluster checks timed out after ~12 minutes

Key evidence this is infrastructure, not a code regression:

  • PR CNTRLPLANE-3174: Add unit tests for v2 CPO controller packages #8215 modifies only 30 unit test files (*_test.go) and zero production code, CI configs, or DNS-related logic
  • TestHAEtcdChaos passed because it uses platform None (no External DNS dependency)
  • TestCreateClusterDefaultSecurityContextUID passed (validates namespace UIDs, not cluster connectivity)
  • All 7 failures show the identical DNS resolution failure pattern across completely independent hosted clusters
Recommendations
  1. Retest the job — This is an infrastructure flake. Run /retest or /test e2e-aks on the PR to trigger a new run.
  2. No code changes needed — PR CNTRLPLANE-3174: Add unit tests for v2 CPO controller packages #8215 only adds unit tests for v2 CPO controller packages and cannot have caused this Azure DNS infrastructure failure.
  3. If the retest also fails, investigate the Azure External DNS operator deployment on the AKS management cluster and the aks-e2e.hypershift.azure.devcluster.openshift.com DNS zone in the Azure subscription to determine if there is a broader External DNS outage affecting the hypershift-aks CI profile.
Evidence
Evidence Detail
Failed Tests TestAutoscaling, TestCreateCluster, TestCreateClusterCustomConfig, TestNodePool (2 subtests), TestAzureScheduler, TestUpgradeControlPlane — all at ValidateHostedCluster
Passed Tests TestHAEtcdChaos (platform None), TestCreateClusterDefaultSecurityContextUID, 20 skipped
DNS Failure Count 65 occurrences of no such host in build log
KAS Unreachable Count 21 occurrences of KASLoadBalancerNotReachable
Affected DNS Zone aks-e2e.hypershift.azure.devcluster.openshift.com
DNS Servers 10.0.0.10:53 (AKS cluster DNS) and 172.30.0.10:53 (OpenShift cluster DNS)
Cluster Creation All 7 clusters created successfully in ~2m21s–2m27s
Kubeconfig Published All 7 kubeconfigs published successfully in ~1m21s–2m3s
PR Scope 30 files changed — ALL are *_test.go unit test files, zero production code
Failed Step e2e-aks-hypershift-azure-run-e2e after 26m17s
Worker Nodes NoWorkerNodesAvailable — no nodes joined any of the 7 affected clusters
Cluster Operators Down console, dns, image-registry, ingress, insights, kube-storage-version-migrator, monitoring, node-tuning, openshift-samples, service-ca, storage

@bryan-cox
Copy link
Copy Markdown
Member Author

/test e2e-aks

@hypershift-jira-solve-ci
Copy link
Copy Markdown

AI Test Failure Analysis

Job: pull-ci-openshift-hypershift-main-e2e-aws | Build: 2044424508265205760 | Cost: $1.7375026499999993 | Failed step: hypershift-aws-run-e2e-nested

View full analysis report


Generated by hypershift-analyze-e2e-failure post-step using Claude claude-opus-4-6

@bryan-cox
Copy link
Copy Markdown
Member Author

/test e2e-aws

@bryan-cox
Copy link
Copy Markdown
Member Author

Previous aws error seems like a flake

@hypershift-jira-solve-ci
Copy link
Copy Markdown

AI Test Failure Analysis

Job: pull-ci-openshift-hypershift-main-e2e-aws | Build: 2044478731879190528 | Cost: $1.95662175 | Failed step: hypershift-aws-run-e2e-nested

View full analysis report


Generated by hypershift-analyze-e2e-failure post-step using Claude claude-opus-4-6

@bryan-cox
Copy link
Copy Markdown
Member Author

/retest

This was a completely different error on aws than the last one

@openshift-ci
Copy link
Copy Markdown
Contributor

openshift-ci bot commented Apr 15, 2026

@bryan-cox: all tests passed!

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 7253de0 into openshift:main Apr 15, 2026
29 checks passed
@bryan-cox bryan-cox deleted the improve-ut-coverage branch April 15, 2026 22:53
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. area/api Indicates the PR includes changes for the API area/cli Indicates the PR includes changes for CLI area/control-plane-operator Indicates the PR includes changes for the control plane operator - in an OCP release area/documentation Indicates the PR includes changes for documentation area/hypershift-operator Indicates the PR includes changes for the hypershift operator and API - outside an OCP release area/platform/aws PR/issue for AWS (AWSPlatform) platform area/platform/kubevirt PR/issue for KubeVirt (KubevirtPlatform) platform area/platform/powervs PR/issue for PowerVS (PowerVSPlatform) platform area/testing Indicates the PR includes changes for e2e testing jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. lgtm Indicates that a PR is ready to be merged. verified Signifies that the PR passed pre-merge verification criteria

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants