Skip to content

[release-4.21] OCPBUGS-100540: e2e: fix broken checks and rework netqueue tests to avoid ARM ethtool blackout flakes - #1573

Open
openshift-cherrypick-robot wants to merge 5 commits into
openshift:release-4.21from
openshift-cherrypick-robot:cherry-pick-1568-to-release-4.21
Open

[release-4.21] OCPBUGS-100540: e2e: fix broken checks and rework netqueue tests to avoid ARM ethtool blackout flakes#1573
openshift-cherrypick-robot wants to merge 5 commits into
openshift:release-4.21from
openshift-cherrypick-robot:cherry-pick-1568-to-release-4.21

Conversation

@openshift-cherrypick-robot

Copy link
Copy Markdown

This is an automated cherry-pick of #1568

/assign oblau

oblau added 5 commits August 3, 2026 09:50
…n netqueue suite

strings.ContainsAny(s, chars) reports whether ANY character in chars
appears in s -- it does not check for a substring. Since device is a NIC
name like "enP2s2f0np0", this check was true for almost any tuned output
containing common letters, regardless of whether that specific device name
actually appeared in devices_udev_regex. Replace with strings.Contains in
the 4 tests that assert tuned picked up the configured device filter:
test_id 40543, 40545, 72051, 40668.

Every netqueue test body was wrapped in a guard like:
  if profile.Spec.Net.UserLevelNetworking != nil && *ULN && len(Devices) == 0 { ... }
This guard was true in the common case only because BeforeEach
unconditionally set Net whenever it was nil, and AfterEach unconditionally
reverted to the initial profile after every test. If the *initial* cluster
profile already had a non-nil Net with ULN=false or leftover Devices, the
guard evaluated false and the entire test body was skipped -- the test
reported PASS while verifying nothing. Guards removed from test_id 40308,
40543, 40545, 72051, and 40668.

Once the guard is gone, test_id 40308 and 40542 are identical bodies
(both call checkDeviceSetWithReservedCPU unconditionally). Dropping 40542
as a duplicate; 40308 covers the same case.

getReservedCPUSize re-parsed profile.Spec.CPU.Reserved into a cpuset on
every 5s poll, even though the value is static for the
whole test run. Compute it once as reservedCPUCount in the BeforeAll and
thread it through instead: checkDeviceSetWithReservedCPU's signature
changes from taking the whole *performancev2.PerformanceProfile to taking
reservedCPUCount int directly. getReservedCPUSize is removed.

AI Attribution: AIA Human-AI blend, Content edits, New content,
Human-initiated, Reviewed, opus 4.6 high v1.0
…BeforeAll/AfterAll pass

- BeforeEach (enable ULN) and AfterEach (revert to initial) never
  isolated tests: both call profiles.UpdateWithRetry with no wait
  after, so the next test's own update fires before tuned reconciles
  the previous one.

- Example: test A AfterEach reverts the profile, but test B
  immediately calls UpdateWithRetry with its own Devices before that
  revert lands -- B can still see A leftover devices_udev_regex
  even though "cleanup" ran in between.

- No test actually needs a clean starting profile: each one fully
  overwrites profile.Spec.Net itself or polls until its own expected
  state converges. The per-test revert bought nothing.

- Replaced with one BeforeAll (set baseline once) and one AfterAll
  (revert once, only if state changed). Side effect: total profile
  updates per run drop from 10-16 to 5-6.
…tead of per-test rediscovery

- checkDeviceSupport was called independently by every test, re-running
  ethtool discovery over the tuned pod each time. checkDeviceSetWithReservedCPU
  then polled that same rediscovery every 5s while waiting for convergence.
  A slow update and a broken feature produced the same timeout -> Skip.

- Split checkDeviceSupport into discoverMultiQueueNICs (per-node NIC
  enumeration, now via nodes.GetNodeInterfaces/node_inspector instead of
  tuned-pod exec) and getCombinedChannels (single NIC -> combined channel
  count). One does discovery, one does the ethtool read; each is reusable
  on its own.

- discoverMultiQueueNICs runs once in BeforeAll into baselineMultiQueueNICs
  (map[string]map[nodes.NodeInterface]int); BeforeAll Skips the whole suite
  upfront if none are found. Tests read from this baseline instead of
  rediscovering.

- checkDeviceSetWithReservedCPU -> waitForNICsToMatchReservedCPU: no longer
  mutates a caller map or rediscovers, just polls the baseline. Also fixes
  a real bug -- the old function returned success on the first NIC that
  matched reservedCPUCount, even for tests asserting all supported NICs
  converge.

- getRandomNodeDevice updated for the new map type, returns a NodeInterface
  instead of a bare string. Drops its defensive empty-name check --
  discoverMultiQueueNICs never inserts zero-value entries, unlike the old
  checkDeviceSupport.

- 40543/40545/72051/40668 now pull their target device from the baseline
  instead of calling checkDeviceSupport themselves. profile updates use
  `var err error` explicitly to avoid re-shadowing the Describe-scoped
  profile var now that device is a struct, not a string, everywhere.

AI Attribution: AIA Human-AI blend, Content edits, New content,
Human-initiated, Reviewed, opus 4.6 high v1.0
…line

- checkDeviceSupport split into discoverMultiQueueNICs (enumeration) and
  getCombinedChannels (per-NIC ethtool parsing). Discovery now runs once in
  BeforeAll into baselineMultiQueueNICs, Skipping the whole suite upfront if
  none are found, instead of each test re-discovering and skipping
  individually.

- checkDeviceSetWithReservedCPU -> waitForNICsToMatchReservedCPU: takes a
  NIC map to poll instead of rediscovering. Also fixes a bug where it
  returned success on the first matching NIC instead of waiting for all of
  them to converge.

- getRandomNodeDevice: updated for the new map type, returns a
  NodeInterface, drops its now-unneeded empty-name guard.

- Each test builds its own scoped NIC map (targetNICs/matchedNICs/
  expectedNICs) instead of polling the full baseline, so convergence checks
  validate only the NICs that test actually touches. Per-test
  checkDeviceSupport+Skip guards removed, BeforeAll already guarantees them.

- Skip-on-error replaced with Expect(err).ToNot(HaveOccurred()) throughout.

- profile.Spec.Net setup now only sets .Devices (UserLevelNetworking=true
  comes from the BeforeAll baseline).

- var err error added before some profile fetches so profile, err = ...
  assigns the Describe-scoped var instead of shadowing it.

- nodes.GetByName moved before scoped-map-building/profile update in every
  test, to keep the exec call out of the post-update ethtool blackout
  window.

- 40545: wildcard check now searches for the derived udev-regex form
  ("iface.*") instead of the literal device name, since tuned stores
  wildcards as regex in devices_udev_regex.

- 72051: pick device only from nodes with >=2 NICs, a single-NIC node can't
  demonstrate negation. Restored the negative assertion (pre/post
  combined-channel comparison on the negated NIC) lost when
  checkDeviceSupport was removed. Tuned-config check now searches for the
  negated pattern ("!iface") instead of the bare device name, to avoid a
  false positive from a leftover config.

- 40668: tuned-config check upgraded to a 3-way match (interface name +
  vendor ID + device ID); it previously only checked the interface name.

AI Attribution: AIA Human-AI blend, Content edits, New content,
Human-initiated, Reviewed, opus 4.6 high v1.0
…ests

- Converted remaining plain `//` comments to By() calls; unified the 4
  tests' tuned-config-check block (identical By text, no blank lines) --
  they run the same grep, differing only in what they search for.

- Added a By() before each test's final convergence check (previously
  unlabeled); all now end in "converged to reserved CPU count".

- Added testlog.Infof after each getRandomNodeDevice call, logging which
  NIC/node the run picked.

- 40545/40668: added missing By("Updating the performance profile"),
  matching 40543. 72051: split its stale "Enable ULN..." By into the same
  two-step shape as the other tests.

- 40668: removed a redundant duplicate nodes.GetByName call.

- AfterAll now logs the profile diff before reverting, mirroring
  BeforeAll's equivalent branch.

- Added a top-of-file comment on the ARM ethtool -L blackout window, and
  a doc comment on getRandomNodeDevice explaining its random-pick trick.

AI Attribution: AIA Human-AI blend, Content edits, New content,
Human-initiated, Reviewed, opus 4.6 high v1.0
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository: openshift/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 1606849d-6d5f-43f7-93d1-7fd7de6a24c7

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@qodo-for-rh-openshift

Copy link
Copy Markdown

PR Summary by Qodo

Fix netqueues e2e assertions and reduce ARM ethtool blackout flakes

🐞 Bug fix 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Fix tuned.conf device-filter assertions to match full interface names and expected udev regex.
• Rework netqueue tests to avoid false passes from dead guards and duplicated coverage.
• Pre-discover multi-queue NICs and poll for ethtool convergence to reduce blackout flakes.
Diagram

graph TD
  A["Netqueues e2e suite"] --> B["BeforeAll: load profile + reserved CPU count"] --> C["Discover multi-queue NICs (baseline)"] --> D["Update PerformanceProfile Net.Devices filters"] --> E["TuneD applies ethtool -L"] --> F["Poll: read combined channels via node exec"] --> G["Assert: channels == reserved CPU count"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Read queue/channel state from sysfs instead of ethtool
  • ➕ Avoids parsing ethtool output and potential tool availability differences
  • ➕ Potentially cheaper/faster reads during polling
  • ➖ Sysfs paths/semantics can vary across drivers and kernel versions
  • ➖ May not represent the same 'combined channels' abstraction the tests intend
2. Observe TuneD state (rendered config/daemon status) instead of node exec
  • ➕ Reduces reliance on node reachability during the ethtool blackout window
  • ➕ Could make tests less flaky by avoiding direct node exec calls
  • ➖ Harder to prove the setting actually took effect at the NIC level
  • ➖ Still needs a ground-truth signal; config presence alone can be misleading

Recommendation: Keep the PR’s approach: snapshot multi-queue NICs before disruptive updates and use polling for node-reaching checks. This directly validates the end state (combined channels) while explicitly accounting for the known ~30s connectivity blackout, and it prevents false-positive passes by removing dead guards and strengthening tuned.conf assertions.

Files changed (1) +287 / -244

Tests (1) +287 / -244
netqueues.goRework netqueue e2e suite to avoid false passes and ethtool blackout flakes +287/-244

Rework netqueue e2e suite to avoid false passes and ethtool blackout flakes

• Fixes device-filter assertions by replacing strings.ContainsAny with strings.Contains and validating expected regex strings. Removes conditional guards that could skip entire test bodies based on pre-existing profile state, deduplicates coverage by consolidating the reserved-CPU convergence check, and adds baseline NIC discovery plus polling helpers to wait for TuneD/ethtool convergence safely.

test/e2e/performanceprofile/functests/1_performance/netqueues.go

@openshift-ci
openshift-ci Bot requested review from Tal-or and ffromani August 3, 2026 09:51
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@openshift-cherrypick-robot: Jira Issue OCPBUGS-99290 has been cloned as Jira Issue OCPBUGS-100540. Will retitle bug to link to clone.
/retitle [release-4.21] OCPBUGS-100540: e2e: fix broken checks and rework netqueue tests to avoid ARM ethtool blackout flakes

Details

In response to this:

This is an automated cherry-pick of #1568

/assign oblau

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 changed the title [release-4.21] OCPBUGS-99290: e2e: fix broken checks and rework netqueue tests to avoid ARM ethtool blackout flakes [release-4.21] OCPBUGS-100540: e2e: fix broken checks and rework netqueue tests to avoid ARM ethtool blackout flakes Aug 3, 2026
@openshift-ci-robot openshift-ci-robot added jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. labels Aug 3, 2026
@openshift-ci-robot

Copy link
Copy Markdown
Contributor

@openshift-cherrypick-robot: This pull request references Jira Issue OCPBUGS-100540, which is valid. The bug has been moved to the POST state.

7 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.21.z) matches configured target version for branch (4.21.z)
  • bug is in the state New, which is one of the valid states (NEW, ASSIGNED, POST)
  • release note type set to "Release Note Not Required"
  • dependent bug Jira Issue OCPBUGS-99290 is in the state Verified, which is one of the valid states (VERIFIED, RELEASE PENDING, CLOSED (ERRATA), CLOSED (CURRENT RELEASE), CLOSED (DONE), CLOSED (DONE-ERRATA))
  • dependent Jira Issue OCPBUGS-99290 targets the "4.22.0" version, which is one of the valid target versions: 4.22.0
  • bug has dependents

The bug has been updated to refer to the pull request using the external bug tracker.

Details

In response to this:

This is an automated cherry-pick of #1568

/assign oblau

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.

@qodo-for-rh-openshift

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Negated NIC check wrong 🐞 Bug ≡ Correctness
Description
The negative-match netqueues test asserts that tuned.conf contains the literal device pattern
"!<iface>", but TuneD renders negated interface filters as a negative-lookahead regex
"^INTERFACE=(?!<iface>)". This makes the Eventually() condition never become true and the test will
time out/fail even when the profile is correctly applied.
Code

test/e2e/performanceprofile/functests/1_performance/netqueues.go[R275-276]

+				return strings.Contains(string(out), devicePattern)
+			}, cluster.ComputeTestTimeout(2*time.Minute, RunningOnSingleNode), 5*time.Second).Should(BeTrue(), "tuned config does not contain %q", devicePattern)
Relevance

●●● Strong

PR #1557 shows team actively fixing incorrect netqueues tuned.conf assertions; likely to accept this
correctness fix too.

PR-#1557

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The e2e test constructs a negated pattern with a leading '!' and then searches tuned.conf for that
literal string, but the tuned profile generator explicitly converts leading '!' patterns into a
'(?!...)' negative-lookahead and never includes the raw '!'. The tuned unit test also documents and
asserts the '(?!...)' form, confirming the expected tuned.conf content.

test/e2e/performanceprofile/functests/1_performance/netqueues.go[228-276]
pkg/performanceprofile/controller/performanceprofile/components/tuned/tuned.go[173-180]
pkg/performanceprofile/controller/performanceprofile/components/tuned/tuned_test.go[470-489]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The negative interface match test builds `devicePattern := "!" + device.Name` and then checks `grep devices_udev_regex ...` output contains that literal string. However, the TuneD generator strips the `!` and emits a negative-lookahead regex like `^INTERFACE=(?!<iface>)`, so the string containment check will never match.

## Issue Context
TuneD net device regex rendering for negated interface names is implemented in the tuned component by translating `!ens5` into `^INTERFACE=(?!ens5)` (and `*` into `.*`). The e2e test should assert against this rendered form (e.g., contain `"^INTERFACE=(?!"+device.Name+")"` or at least `"(?!"+device.Name+")"`), not the raw `!` pattern.

## Fix Focus Areas
- test/e2e/performanceprofile/functests/1_performance/netqueues.go[228-276]
- pkg/performanceprofile/controller/performanceprofile/components/tuned/tuned.go[173-180]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

Comment on lines +275 to +276
return strings.Contains(string(out), devicePattern)
}, cluster.ComputeTestTimeout(2*time.Minute, RunningOnSingleNode), 5*time.Second).Should(BeTrue(), "tuned config does not contain %q", devicePattern)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Negated nic check wrong 🐞 Bug ≡ Correctness

The negative-match netqueues test asserts that tuned.conf contains the literal device pattern
"!<iface>", but TuneD renders negated interface filters as a negative-lookahead regex
"^INTERFACE=(?!<iface>)". This makes the Eventually() condition never become true and the test will
time out/fail even when the profile is correctly applied.
Agent Prompt
## Issue description
The negative interface match test builds `devicePattern := "!" + device.Name` and then checks `grep devices_udev_regex ...` output contains that literal string. However, the TuneD generator strips the `!` and emits a negative-lookahead regex like `^INTERFACE=(?!<iface>)`, so the string containment check will never match.

## Issue Context
TuneD net device regex rendering for negated interface names is implemented in the tuned component by translating `!ens5` into `^INTERFACE=(?!ens5)` (and `*` into `.*`). The e2e test should assert against this rendered form (e.g., contain `"^INTERFACE=(?!"+device.Name+")"` or at least `"(?!"+device.Name+")"`), not the raw `!` pattern.

## Fix Focus Areas
- test/e2e/performanceprofile/functests/1_performance/netqueues.go[228-276]
- pkg/performanceprofile/controller/performanceprofile/components/tuned/tuned.go[173-180]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@oblau

oblau commented Aug 4, 2026

Copy link
Copy Markdown
Member

/retest

1 similar comment
@oblau

oblau commented Aug 4, 2026

Copy link
Copy Markdown
Member

/retest

@openshift-ci

openshift-ci Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

@openshift-cherrypick-robot: 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.

@Tal-or Tal-or left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

/lgtm

@openshift-ci openshift-ci Bot added the lgtm Indicates that a PR is ready to be merged. label Aug 4, 2026
@openshift-ci

openshift-ci Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: openshift-cherrypick-robot, Tal-or
Once this PR has been reviewed and has the lgtm label, please assign yanirq for approval. For more information see the Code Review Process.

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

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

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants