Skip to content

Conversation

@huali9
Copy link
Contributor

@huali9 huali9 commented Oct 28, 2025

machine update e2e, I tested in my local and works @sunzhaohua2 @miyadav @damdo @theobarberbany PTAL, thanks!

Summary by CodeRabbit

  • Tests
    • Expanded end-to-end coverage for machine migration: added suites validating add/modify/delete of labels and annotations on both authoritative sides.
    • Added helpers to capture and verify pre/post machine state (generations and synchronized time) to ensure correct synchronization behavior.
    • Added a pending deletion sync test tied to a known issue; enhanced assertions to ensure no unintended generation/condition changes.

@coderabbitai
Copy link

coderabbitai bot commented Oct 28, 2025

Walkthrough

Adds a MachineState type and helpers to capture and verify pre/post MAPI/CAPI generations and synchronized time; introduces new end-to-end test suites for MAPI and CAPI machine updates (label/annotation add/modify/delete) and imports Gomega. Duplicate test blocks were added in test files.

Changes

Cohort / File(s) Summary
Machine state helpers
e2e/machine_migration_helpers.go
Adds MachineState struct and three helpers: captureMachineStateBeforeUpdate, verifyMachineStateChanged, and verifyMachineStateUnchanged to snapshot and assert MAPI/CAPI generation and synchronized-time transitions.
MAPI update tests
e2e/machine_migration_mapi_authoritative_test.go
Adds a new "Update MAPI Machine" test suite exercising add/modify/delete of labels and annotations, synchronization checks to CAPI, state-capture/verification usage, and imports Gomega. The suite appears duplicated.
CAPI update tests
e2e/machine_migration_capi_authoritative_test.go
Adds a new "Update CAPI Machine" test suite mirroring the update tests and imports Gomega.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Test as E2E Test
    participant Helper as MachineState Helper
    participant MAPI as MAPI API
    participant CAPI as CAPI API

    rect rgba(173,216,230,0.15)
    Test->>Helper: captureMachineStateBeforeUpdate(machineName)
    Helper->>MAPI: Get Machine, Status (generation, conds)
    Helper->>CAPI: Get Mirror Machine, Status (generation)
    Helper-->>Test: MachineState{MAPIGeneration, CAPIGeneration, SynchronizedTime}
    end

    rect rgba(144,238,144,0.12)
    Test->>MAPI: Apply change (add/modify/delete labels/annotations)
    Note right of MAPI: change may be metadata-only or metadata+generation
    MAPI-->>Test: update acknowledged
    end

    rect rgba(255,228,196,0.12)
    Test->>Helper: wait & verify synchronization
    Helper->>CAPI: Poll mirror for expected label/annotation state
    CAPI-->>Helper: updated state observed
    Helper-->>Test: sync confirmed
    end

    rect rgba(221,160,221,0.08)
    Test->>Helper: verifyMachineStateChanged/Unchanged(prevState, authority, op)
    Helper->>MAPI: fetch post-op status
    Helper->>CAPI: fetch post-op status
    Helper-->>Test: verdict (generations/time changed or unchanged)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to duplicated test suites (clarify intent or remove duplicates).
  • Review correctness of generation/time comparisons and nil-handling in MachineState helpers.
  • Validate timing/polling logic in tests for flakiness and environment sensitivity.
  • Confirm imported Gomega usage matches project testing conventions.

Poem

🐇 I sniff the state, then jot the time,

Labels hop over, annotations chime.
MAPI and CAPI in a gentle spin,
I cheer the syncs — a soft, tiny grin. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'OCPCLOUD-2992: machine update' is vague and does not clearly convey the specific nature of the changes; it lacks descriptive detail about what the machine update entails. Consider using a more descriptive title that captures the main change, such as 'Add machine state verification e2e tests for CAPI/MAPI synchronization' or 'Add e2e tests for machine metadata updates and state tracking'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a4dd8b0 and 36d3beb.

📒 Files selected for processing (3)
  • e2e/machine_migration_capi_authoritative_test.go (3 hunks)
  • e2e/machine_migration_helpers.go (1 hunks)
  • e2e/machine_migration_mapi_authoritative_test.go (2 hunks)
🔇 Additional comments (9)
e2e/machine_migration_helpers.go (3)

328-333: LGTM: Well-defined state tracking structure.

The MachineState type appropriately captures generation metadata and synchronized time for both MAPI and CAPI machines. Using a pointer for SynchronizedTime correctly handles cases where the condition may not exist.


335-358: LGTM: Correct state capture implementation.

The function properly fetches both MAPI and CAPI machines, captures their generations, and safely handles the case where the synchronized condition may not exist by leaving the pointer nil.


407-419: Good: Proper nil guard for synchronized time.

This function correctly checks if previousState.SynchronizedTime is nil before dereferencing it (line 408). This is the correct pattern that should also be applied to verifyMachineStateChanged at lines 375-386.

e2e/machine_migration_capi_authoritative_test.go (3)

7-7: LGTM: Appropriate test imports.

The Gomega dot import and komega additions are standard for Kubernetes e2e tests using Ginkgo/Gomega.

Also applies to: 16-16


304-324: LGTM: Well-structured test setup.

The BeforeAll block properly creates test machines with CAPI authority and registers cleanup handlers. The use of DeferCleanup ensures resources are removed even if tests fail.


326-446: Well-designed test coverage for CAPI updates.

The test suite comprehensively covers add, modify, and delete operations for labels/annotations, verifying synchronization to both MAPI metadata and spec.objectMeta. The state capture and verification pattern is sound.

Note: These tests depend on verifyMachineStateChanged which has a nil-deref bug that must be fixed.

e2e/machine_migration_mapi_authoritative_test.go (3)

7-7: LGTM: Appropriate test imports.

The Gomega and komega imports are consistent with the CAPI test file and appropriate for Kubernetes e2e tests.

Also applies to: 15-15


208-294: LGTM: Correct test logic for MAPI authoritative updates.

The test suite properly verifies that metadata-only changes on the authoritative MAPI machine are synchronized to CAPI but do not trigger generation or synchronized time changes. The use of verifyMachineStateUnchanged is correct for this scenario.


306-322: Appropriate handling of known deletion sync issue.

The pending test correctly documents the known issue (OCPBUGS-61596) where label/annotation deletions on MAPI machines don't synchronize to CAPI. Using PIt ensures the test suite can pass while tracking this limitation.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 golangci-lint (2.5.0)

Error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions
The command is terminated due to an error: can't load config: unsupported version of the configuration: "" See https://golangci-lint.run/docs/product/migration-guide for migration instructions


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

@openshift-ci openshift-ci bot requested review from chrischdi and mdbooth October 28, 2025 04:53
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Oct 28, 2025

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (5)
e2e/machine_migration_helpers.go (3)

328-333: Prefer value + presence flag over pointer for SynchronizedTime

Using a pointer here (and later taking an address of a range copy) is fragile. Store the time value and a boolean presence flag instead; it’s simpler and avoids accidental aliasing.

 type MachineState struct {
   MAPIGeneration   int64
   CAPIGeneration   int64
-  SynchronizedTime *metav1.Time
+  SynchronizedTime metav1.Time
+  HasSynchronizedTime bool
 }

Follow-ups (outside this hunk):

  • In captureMachineStateBeforeUpdate: set both SynchronizedTime and HasSynchronizedTime when the condition is found.
  • In verify helpers: gate temporal assertions on HasSynchronizedTime and use SynchronizedTime directly.

339-356: Don’t take the address of a for-range copy; capture the value instead

This loop takes the address of condition.LastTransitionTime where condition is a copy. Prefer copying the value into state (or use the boolean flag from the previous comment).

- for _, condition := range currentMAPIMachine.Status.Conditions {
+ for _, condition := range currentMAPIMachine.Status.Conditions {
     if condition.Type == SynchronizedCondition {
-      state.SynchronizedTime = &condition.LastTransitionTime
+      // value copy; no pointer to range variable
+      state.SynchronizedTime = condition.LastTransitionTime
+      state.HasSynchronizedTime = true
       break
     }
   }

408-419: DRY the “find synchronized time” scan into a tiny helper

Both verify functions repeat the same loop. Extract a small helper to read the synchronized condition’s LastTransitionTime and reuse it. Keeps tests terse and less error-prone.

// outside: helpers.go
func getSynchronizedLastTransitionTime(m *mapiv1beta1.Machine) (*metav1.Time, bool) {
  for _, c := range m.Status.Conditions {
    if c.Type == SynchronizedCondition {
      t := c.LastTransitionTime
      return &t, true
    }
  }
  return nil, false
}

Then replace the loops with getSynchronizedLastTransitionTime(mapiMachine).

e2e/machine_migration_capi_authoritative_test.go (1)

325-341: Stabilize capture: wait for Synchronized condition before recording previous state

If the synchronized condition isn’t set yet, previousState.SynchronizedTime may be nil and downstream assertions may skip/flake. Ensure it’s True before capture.

 It("should add labels/annotations on CAPI machine", func() {
-  // Capture state before the update
-  previousState = captureMachineStateBeforeUpdate(cl, newMapiMachine.Name)
+  // Ensure sync condition is present, then capture state
+  verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityClusterAPI)
+  previousState = captureMachineStateBeforeUpdate(cl, newMapiMachine.Name)
   Eventually(func() error {

Please run this suite once locally to confirm reduced flakes in the first “Update CAPI Machine” block.

e2e/machine_migration_mapi_authoritative_test.go (1)

229-248: Optional: add the same precondition before capture for consistency

Align with the CAPI suite by waiting for the Synchronized condition before capturing; reduces any timing window variability.

 It("should add labels/annotations on MAPI machine", func() {
-  // Capture state before the update
+  // Optional: ensure sync condition is present, then capture state
+  verifyMAPIMachineSynchronizedCondition(newMapiMachine, mapiv1beta1.MachineAuthorityMachineAPI)
   previousState = captureMachineStateBeforeUpdate(cl, newMapiMachine.Name)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Cache: Disabled due to data retention organization setting

Knowledge base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between a1a97d6 and a4dd8b0.

📒 Files selected for processing (3)
  • e2e/machine_migration_capi_authoritative_test.go (2 hunks)
  • e2e/machine_migration_helpers.go (1 hunks)
  • e2e/machine_migration_mapi_authoritative_test.go (2 hunks)

Comment on lines +375 to +386
// Verify synchronized time is updated
var currentSynchronizedTime *metav1.Time
for _, condition := range mapiMachine.Status.Conditions {
if condition.Type == SynchronizedCondition {
currentSynchronizedTime = &condition.LastTransitionTime
break
}
}
Expect(currentSynchronizedTime).ToNot(BeNil(), "Synchronized condition should exist")
By(fmt.Sprintf("Verifying synchronized time changed after %s (previous: %v, current: %v)", operation, previousState.SynchronizedTime.Time, currentSynchronizedTime.Time))
Expect(currentSynchronizedTime.Time).To(BeTemporally(">", previousState.SynchronizedTime.Time), fmt.Sprintf("Synchronized time should change when syncing %s metadata to spec", operation))

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Nil-deref risk: previousState.SynchronizedTime can be nil

If the synchronized condition wasn’t present when captured, this dereferences a nil pointer (both in By() and BeTemporally(">")). Guard it and still assert that current sync time is set.

- // Verify synchronized time is updated
- var currentSynchronizedTime *metav1.Time
+ // Verify synchronized time is updated
+ var currentSynchronizedTime *metav1.Time
   for _, condition := range mapiMachine.Status.Conditions {
     if condition.Type == SynchronizedCondition {
       currentSynchronizedTime = &condition.LastTransitionTime
       break
     }
   }
   Expect(currentSynchronizedTime).ToNot(BeNil(), "Synchronized condition should exist")
- By(fmt.Sprintf("Verifying synchronized time changed after %s (previous: %v, current: %v)", operation, previousState.SynchronizedTime.Time, currentSynchronizedTime.Time))
- Expect(currentSynchronizedTime.Time).To(BeTemporally(">", previousState.SynchronizedTime.Time), fmt.Sprintf("Synchronized time should change when syncing %s metadata to spec", operation))
+ if previousState.SynchronizedTime != nil {
+   By(fmt.Sprintf(
+     "Verifying synchronized time changed after %s (previous: %v, current: %v)",
+     operation, previousState.SynchronizedTime.Time, currentSynchronizedTime.Time))
+   Expect(currentSynchronizedTime.Time).
+     To(BeTemporally(">", previousState.SynchronizedTime.Time),
+        fmt.Sprintf("Synchronized time should change when syncing %s metadata to spec", operation))
+ } else {
+   By(fmt.Sprintf("Previous synchronized time missing; asserting current time is set after %s", operation))
+   Expect(currentSynchronizedTime.Time.IsZero()).To(BeFalse(), "Synchronized time should be set after synchronization")
+ }

Optional hardening: re-fetch mapiMachine at the start of this function to reduce reliance on the caller providing a fresh object.

@huali9 huali9 changed the title machine update OCPCLOUD-2992: machine update Oct 28, 2025
@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Oct 28, 2025
@openshift-ci-robot
Copy link

openshift-ci-robot commented Oct 28, 2025

@huali9: This pull request references OCPCLOUD-2992 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 story to target the "4.21.0" version, but no target version was set.

In response to this:

machine update e2e, I tested in my local and works @sunzhaohua2 @miyadav @damdo @theobarberbany PTAL, thanks!

Summary by CodeRabbit

  • Tests
  • Expanded end-to-end test coverage for machine migration scenarios, including MAPI machine updates with metadata changes.
  • Introduced new test helpers to track and validate machine state transitions and synchronization status before and after operations.
  • Enhanced verification that generation metadata and synchronized conditions remain consistent during expected update operations.

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
Copy link
Contributor

openshift-ci bot commented Oct 28, 2025

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

Test name Commit Details Required Rerun command
ci/prow/okd-scos-e2e-aws-ovn a4dd8b0 link false /test okd-scos-e2e-aws-ovn

Full PR test history. Your PR dashboard.

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.

@sunzhaohua2
Copy link
Contributor

@huali9 can we use Komega for Eventually?

@huali9
Copy link
Contributor Author

huali9 commented Nov 5, 2025

@huali9 can we use Komega for Eventually?

Sure, updated, PTAL again @sunzhaohua2

@openshift-ci-robot
Copy link

openshift-ci-robot commented Nov 5, 2025

@huali9: This pull request references OCPCLOUD-2992 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 story to target the "4.21.0" version, but no target version was set.

In response to this:

machine update e2e, I tested in my local and works @sunzhaohua2 @miyadav @damdo @theobarberbany PTAL, thanks!

Summary by CodeRabbit

  • Tests
  • Expanded end-to-end coverage for machine migration: added suites validating add/modify/delete of labels and annotations on both authoritative sides.
  • Added helpers to capture and verify pre/post machine state (generations and synchronized time) to ensure correct synchronization behavior.
  • Added a pending deletion sync test tied to a known issue; enhanced assertions to ensure no unintended generation/condition changes.

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.

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

Labels

jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants