Skip to content

HYPERFLEET-1154 - feat: Adapter status endpoints for generic resources#284

Open
tirthct wants to merge 7 commits into
openshift-hyperfleet:mainfrom
tirthct:hyperfleet-1154
Open

HYPERFLEET-1154 - feat: Adapter status endpoints for generic resources#284
tirthct wants to merge 7 commits into
openshift-hyperfleet:mainfrom
tirthct:hyperfleet-1154

Conversation

@tirthct

@tirthct tirthct commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds GET/PUT /{plural}/{id}/statuses endpoints for all config-driven generic resources
(Channel, Version, WifConfig, and future types). Adapters can now report status on generic
resources and trigger aggregated condition computation, completing the adapter status
pipeline for the generic resource layer.

  • Entities with RequiredAdapters get full adapter lifecycle (soft-delete → finalization → hard-delete)
  • Entities with empty RequiredAdapters still accept status reports and aggregate from whatever adapters report

What changed

  • Shared validation — Extracted validateAndClassifyAdapterStatus from the duplicated
    logic in ClusterService.validateAndClassify and NodePoolService.validateAndClassifyNodePool
    (~150 lines of duplication eliminated). Both typed services now delegate to the shared function.

  • ProcessAdapterStatus on ResourceService — Same 4-DB-call pattern as Cluster/NodePool:
    lock resource → fetch all adapter statuses → validate + upsert → aggregate conditions.
    Key difference: writes conditions to resource_conditions table (not JSONB column).

  • ResourceStatusHandler — Generic handler with List/Create/ListByOwner/CreateByOwner,
    matching ClusterStatusHandler pattern. Registered for all entities in plugins/entities/plugin.go.

  • Hard-delete after finalizationtryHardDeleteResource permanently removes a
    soft-deleted resource when all required adapters report Finalized=True and no children
    (active or soft-deleted) remain. Cleans up adapter statuses and conditions before removing
    the resource row.

  • DAO updatesGetForUpdate now preloads Conditions (needed for aggregation diff).
    Added DeleteByResource to ResourceConditionDao for hard-delete cleanup.

Files

File Action
pkg/services/adapter_status_validation.go New — shared validation extracted from cluster/nodepool
pkg/services/resource.go ProcessAdapterStatus + recompute + tryHardDelete + constructor
pkg/services/cluster.go validateAndClassify → 3-line wrapper
pkg/services/node_pool.go validateAndClassifyNodePool → 3-line wrapper
pkg/handlers/resource_status_handler.go New — generic status handler
plugins/entities/plugin.go Status routes for all entities
plugins/resources/plugin.go Constructor wiring (AdapterStatusDao, ResourceConditionDao)
pkg/dao/resource.go GetForUpdate preloads Conditions
pkg/dao/resource_condition.go Added DeleteByResource

Condition storage: Cluster vs Generic Resources

Aspect Cluster / NodePool Generic Resources
Storage JSONB column on entity row Separate resource_conditions table
Write ClusterDao.SaveStatusConditions(id, []byte) ResourceConditionDao.UpdateConditions(id, []cond)
Read Part of model (implicit) Preload("Conditions") on Get/GetForUpdate

Test plan

  • make test — 1343 unit tests pass
  • Shared validation: 10 tests (all discard rules, mandatory conditions, Available classification)
  • ProcessAdapterStatus: 9 tests (happy path, 404, 400, discard, upsert, hard-delete, children block, empty adapters)
  • ResourceStatusHandler: 6 tests (List 200/404, Create 201/204/400/404)
  • Plugin routes: status route matching for top-level and nested entities
  • Integration tests compile (5 tests: PUT+GET, aggregation, nested, 404, discarded 204)
  • make test-integration — requires database

@openshift-ci openshift-ci Bot requested review from Mischulee and crizzo71 July 7, 2026 15:37
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

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

Adapter-status validation was centralized for cluster and node-pool services. Resource processing now locks resources, persists adapter statuses, recomputes conditions, and performs hard-delete cleanup with condition-row deletion. New status list/create handlers and /{id}/statuses routes were added for resources and owned children, with service injection and tests updated. Ownership checks were added in status handlers, covering CWE-285/CWE-862 boundaries.

Estimated code review effort: 4 (Complex) | ~75 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant StatusHandler
  participant ResourceService
  participant AdapterStatusDao
  participant ResourceConditionDao

  Client->>StatusHandler: PUT adapter status
  StatusHandler->>ResourceService: ProcessAdapterStatus
  ResourceService->>AdapterStatusDao: lock/load/upsert statuses
  ResourceService->>ResourceConditionDao: recompute or delete conditions
  ResourceService-->>StatusHandler: status or discard
  StatusHandler-->>Client: 201, 204, 400, or 404
Loading
🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
Title check ✅ Passed The title names the main change: generic resource adapter status endpoints.
Description check ✅ Passed The description matches the changeset and covers the new endpoints, validation, wiring, and tests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Sec-02: Secrets In Log Output ✅ Passed No CWE-532 issue: non-test logs use resource IDs/adapter names only; no token/password/credential/secret fields or interpolated strings found.
No Hardcoded Secrets ✅ Passed No hardcoded creds/secrets found in modified files; only generated tokens/UUIDs and test data. No CWE-798/259 issue.
No Weak Cryptography ✅ Passed No crypto/md5|des|rc4, SHA1-for-security, ECB, custom crypto, or secret/HMAC compares in touched files; only JSON equality. CWE-327/CWE-208 not present.
No Injection Vectors ✅ Passed No CWE-89/78/79/502 in changed non-test files; the only query strings use validated registry kinds, and owner IDs are existence-checked before use.
No Privileged Containers ✅ Passed No changed Kubernetes/OpenShift manifests, Helm templates, or Dockerfiles; no privileged flags in the PR diff (CWE-250/CWE-276).
No Pii Or Sensitive Data In Logs ✅ Passed PASS: New logs are generic error logs only; no raw bodies, PII, or credentials are emitted (CWE-532 not triggered).
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
✨ Simplify code
  • Create PR with simplified code

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

@hyperfleet-ci-bot

hyperfleet-ci-bot Bot commented Jul 7, 2026

Copy link
Copy Markdown

Risk Score: 3 — risk/medium

Signal Detail Points
PR size 2133 lines (>500) +2
Sensitive paths none +0
Test coverage Missing tests for: pkg/dao plugins/resources +1

Computed by hyperfleet-risk-scorer

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (4)
pkg/services/adapter_status_validation_test.go (1)

80-92: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Untested accept branch: equal generation with a newer observed time.

The stale-observed-time discard (incomingObs.Before(prevObs)) is covered, but the complementary accept path — same ObservedGeneration, non-zero newer LastReportTime, existingStatus != nil — is never asserted. That pass-through branch in the helper (equal-gen block that must NOT discard) is a live path adapters hit on every steady-state re-report. Add a case asserting conditions non-nil and trigger true for a newer timestamp against an existing status.

As per path instructions: "New exported functions and critical logic paths SHOULD have tests" / "Error paths SHOULD be tested, not just happy paths" (TEST-01).

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

In `@pkg/services/adapter_status_validation_test.go` around lines 80 - 92, The
existing test covers the stale observed-time discard path in
validateAndClassifyAdapterStatus, but not the equal-generation accept path when
the incoming LastReportTime is newer and existingStatus is non-nil. Add a test
near TestValidateAndClassify_StaleObservedTime_Discards that uses
adapterStatusWithGenAndTime with the same generation and a newer timestamp than
the existing status, then assert conditions is non-nil, trigger is true, and err
is nil to exercise the non-discard branch in the equal-gen block.

Source: Path instructions

test/integration/resource_status_test.go (1)

1-206: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Missing integration coverage for the hard-delete-via-status flow.

None of these tests exercise PUT-status against a soft-deleted resource to verify tryHardDeleteResource triggers via the HTTP path. This is the scenario most likely to be impacted by the existence-check ordering flagged in pkg/handlers/resource_status_handler.go — an integration test soft-deleting a resource, then PUTing a Finalized=True status and asserting eventual removal, would directly validate (or falsify) that concern.

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

In `@test/integration/resource_status_test.go` around lines 1 - 206, Add
integration coverage for the hard-delete-via-status path by extending
resource_status_test.go with a case that creates a resource, soft-deletes it,
then PUTs a status with Finalized=True through the ResourceStatus handler HTTP
route. Use the existing helpers like createTestChannelForStatus,
setupResourceTest, and newAdapterStatusRequest to locate the flow, and assert
that tryHardDeleteResource is triggered by verifying the resource is eventually
removed or returns not found after the status update.
pkg/handlers/resource_status_handler.go (1)

73-82: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Redundant existence check on the top-level Create path.

ProcessAdapterStatus already resolves the resource by kind+id via GetForUpdate and returns a NotFound ServiceError on failure (handleGetError). The extra h.resourceService.Get(ctx, h.descriptor.Kind, id) call adds a second DB round-trip on every adapter status write (unlike CreateByOwner, where the equivalent GetByOwner call is not redundant since it also enforces ownership).

♻️ Suggested simplification
 		Action: func() (interface{}, *errors.ServiceError) {
 			ctx := r.Context()
 			id := mux.Vars(r)["id"]
-
-			if _, err := h.resourceService.Get(ctx, h.descriptor.Kind, id); err != nil {
-				return nil, err
-			}
-
 			return h.processStatus(ctx, id, &req)
 		},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/handlers/resource_status_handler.go` around lines 73 - 82, Remove the
redundant existence check in the top-level Create path inside the `Action`
handler: `ProcessAdapterStatus` already performs the resource lookup through
`GetForUpdate` and handles not-found via `handleGetError`. Delete the extra
`h.resourceService.Get(ctx, h.descriptor.Kind, id)` call and let
`h.processStatus(ctx, id, &req)` own the resource resolution, keeping the
`CreateByOwner` flow unchanged since its `GetByOwner` check is still needed for
ownership validation.
pkg/handlers/resource_status_handler_test.go (1)

1-225: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

No unit tests for ListByOwner/CreateByOwner.

Only List/Create are unit-tested here; the ownership-scoped variants are new exported methods and are only exercised indirectly by the integration test. A unit test mocking GetByOwner failure (wrong parent) would directly verify the ownership-check branch. As per path instructions, **/*_test.go: "New exported functions and critical logic paths SHOULD have tests."

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

In `@pkg/handlers/resource_status_handler_test.go` around lines 1 - 225, Add unit
tests for the new ownership-scoped handlers, since only List and Create are
covered now. In resource_status_handler_test.go, add cases for
ResourceStatusHandler.ListByOwner and ResourceStatusHandler.CreateByOwner that
mock ResourceService.GetByOwner and cover the ownership-check failure path when
the parent is wrong, plus a success path if needed. Use the existing helper
newTestResourceStatusHandler and the method names ListByOwner/CreateByOwner to
locate and exercise the new exported logic directly.

Source: Path instructions

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

Nitpick comments:
In `@pkg/handlers/resource_status_handler_test.go`:
- Around line 1-225: Add unit tests for the new ownership-scoped handlers, since
only List and Create are covered now. In resource_status_handler_test.go, add
cases for ResourceStatusHandler.ListByOwner and
ResourceStatusHandler.CreateByOwner that mock ResourceService.GetByOwner and
cover the ownership-check failure path when the parent is wrong, plus a success
path if needed. Use the existing helper newTestResourceStatusHandler and the
method names ListByOwner/CreateByOwner to locate and exercise the new exported
logic directly.

In `@pkg/handlers/resource_status_handler.go`:
- Around line 73-82: Remove the redundant existence check in the top-level
Create path inside the `Action` handler: `ProcessAdapterStatus` already performs
the resource lookup through `GetForUpdate` and handles not-found via
`handleGetError`. Delete the extra `h.resourceService.Get(ctx,
h.descriptor.Kind, id)` call and let `h.processStatus(ctx, id, &req)` own the
resource resolution, keeping the `CreateByOwner` flow unchanged since its
`GetByOwner` check is still needed for ownership validation.

In `@pkg/services/adapter_status_validation_test.go`:
- Around line 80-92: The existing test covers the stale observed-time discard
path in validateAndClassifyAdapterStatus, but not the equal-generation accept
path when the incoming LastReportTime is newer and existingStatus is non-nil.
Add a test near TestValidateAndClassify_StaleObservedTime_Discards that uses
adapterStatusWithGenAndTime with the same generation and a newer timestamp than
the existing status, then assert conditions is non-nil, trigger is true, and err
is nil to exercise the non-discard branch in the equal-gen block.

In `@test/integration/resource_status_test.go`:
- Around line 1-206: Add integration coverage for the hard-delete-via-status
path by extending resource_status_test.go with a case that creates a resource,
soft-deletes it, then PUTs a status with Finalized=True through the
ResourceStatus handler HTTP route. Use the existing helpers like
createTestChannelForStatus, setupResourceTest, and newAdapterStatusRequest to
locate the flow, and assert that tryHardDeleteResource is triggered by verifying
the resource is eventually removed or returns not found after the status update.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: cbceb04c-1233-4e9b-afaf-58183e98e2ab

📥 Commits

Reviewing files that changed from the base of the PR and between 29dffce and 620abec.

📒 Files selected for processing (14)
  • pkg/dao/resource.go
  • pkg/dao/resource_condition.go
  • pkg/handlers/resource_status_handler.go
  • pkg/handlers/resource_status_handler_test.go
  • pkg/services/adapter_status_validation.go
  • pkg/services/adapter_status_validation_test.go
  • pkg/services/cluster.go
  • pkg/services/node_pool.go
  • pkg/services/resource.go
  • pkg/services/resource_test.go
  • plugins/entities/plugin.go
  • plugins/entities/plugin_test.go
  • plugins/resources/plugin.go
  • test/integration/resource_status_test.go
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)

@tirthct

tirthct commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

/retest

1 similar comment
@tirthct

tirthct commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

/retest

@tirthct tirthct force-pushed the hyperfleet-1154 branch from 7edda6e to 8b03c86 Compare July 7, 2026 17:54

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

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

Inline comments:
In `@pkg/handlers/resource_status_handler.go`:
- Around line 157-159: The client-facing error messages in
resource_status_handler.go are leaking internal details by formatting presErr
into GeneralError, which then gets returned via AsProblemDetails(). Update the
error handling in the adapter status presentation and ConvertAdapterStatus paths
so the returned GeneralError uses a generic message without the raw wrapped
error, and keep the detailed presErr only in server-side logging. Apply the same
fix to all repeated occurrences in this file so no internal presenter/conversion
details reach HTTP responses.
🪄 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: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: f7d716d6-ddda-47d0-bda6-555d3e533a9d

📥 Commits

Reviewing files that changed from the base of the PR and between 7edda6e and 8b03c86.

📒 Files selected for processing (14)
  • pkg/dao/resource.go
  • pkg/dao/resource_condition.go
  • pkg/handlers/resource_status_handler.go
  • pkg/handlers/resource_status_handler_test.go
  • pkg/services/adapter_status_validation.go
  • pkg/services/adapter_status_validation_test.go
  • pkg/services/cluster.go
  • pkg/services/node_pool.go
  • pkg/services/resource.go
  • pkg/services/resource_test.go
  • plugins/entities/plugin.go
  • plugins/entities/plugin_test.go
  • plugins/resources/plugin.go
  • test/integration/resource_status_test.go
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)
🚧 Files skipped from review as they are similar to previous changes (13)
  • pkg/dao/resource.go
  • pkg/services/node_pool.go
  • plugins/entities/plugin.go
  • plugins/resources/plugin.go
  • test/integration/resource_status_test.go
  • pkg/services/cluster.go
  • pkg/dao/resource_condition.go
  • pkg/services/adapter_status_validation_test.go
  • pkg/services/adapter_status_validation.go
  • pkg/handlers/resource_status_handler_test.go
  • plugins/entities/plugin_test.go
  • pkg/services/resource.go
  • pkg/services/resource_test.go

Comment thread pkg/handlers/resource_status_handler.go
Comment thread pkg/services/node_pool.go Outdated
Comment on lines +417 to +421
// validateAndClassifyNodePool performs all stateless validation and discard-rule checks on an
// incoming adapter status for a node pool. Returns the parsed conditions and whether aggregation
// should be triggered. Returns (nil, false, nil) when the update should be silently discarded.
// validateAndClassifyNodePool delegates to the shared validateAndClassifyAdapterStatus
// with nodepool-specific logger context.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Tip

nit — non-blocking suggestion

Category: Inconsistency

The old doc comment (lines 417-419) still describes the inline validation logic that was extracted into validateAndClassifyAdapterStatus. In cluster.go the old comment was replaced, but here it was kept alongside the new delegation note. This makes the comment block self-contradictory — the method is now a one-liner.

To match how cluster.go:validateAndClassify was handled, replace the full comment block:

Suggested change
// validateAndClassifyNodePool performs all stateless validation and discard-rule checks on an
// incoming adapter status for a node pool. Returns the parsed conditions and whether aggregation
// should be triggered. Returns (nil, false, nil) when the update should be silently discarded.
// validateAndClassifyNodePool delegates to the shared validateAndClassifyAdapterStatus
// with nodepool-specific logger context.
// validateAndClassifyNodePool delegates to the shared validateAndClassifyAdapterStatus
// with nodepool-specific logger context.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ack, fixed

Comment thread pkg/services/resource.go Outdated
// whose children haven't finished their own reconciliation.
hasChildResources := false
if resource.DeletedTime != nil {
for _, child := range registry.ChildrenOf(resource.Kind) {

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.

two functions, recomputeAndSaveResourceConditions and tryHardDeleteResource, have the same block. worth doing this one time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. Fixed

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.

nit:
thanks, i see that this block was extracted, but recomputeAndSaveResourceConditions is called every time, which means if resource is soft-deleted, we're making additional db requests (one in tryhardelete, other in recompute)

@tirthct tirthct force-pushed the hyperfleet-1154 branch from 8b03c86 to 563fe73 Compare July 8, 2026 13:11
Comment thread pkg/services/resource.go Outdated

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.

please remove this guard.

and add before resourceDao.Delete

s.adapterStatusDao.DeleteByResource(ctx, resource.Kind, resource.ID)
s.resourceConditionDao.DeleteByResource(ctx, resource.ID)

And please remove TestAllGenericDescriptors_HaveNoRequiredAdapters and TestGenericDescriptors_HaveNoRequiredAdapters

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

@openshift-ci

openshift-ci Bot commented Jul 8, 2026

Copy link
Copy Markdown

[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 rh-amarin 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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
pkg/handlers/resource_status_handler_test.go (1)

297-342: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing test for ProcessAdapterStatus returning a real error (not just the nil,nil discard case).

TestRootResourceHandler_CreateStatus_HappyPath and _Discarded_Returns204 cover success and silent-discard, but no test asserts the handler correctly surfaces a *errors.ServiceError from ProcessAdapterStatus (e.g. a validation or DB failure). As per path instructions, "Error paths SHOULD be tested, not just happy paths."

func TestRootResourceHandler_CreateStatus_ServiceError(t *testing.T) {
	RegisterTestingT(t)
	ctrl := gomock.NewController(t)

	handler, mockResourceSvc, _ := newTestRootResourceHandler(ctrl)

	resource := &api.Resource{Kind: "Channel"}
	resource.ID = testChannelID
	mockResourceSvc.EXPECT().GetByID(gomock.Any(), testChannelID).Return(resource, nil)
	mockResourceSvc.EXPECT().ProcessAdapterStatus(
		gomock.Any(), "Channel", testChannelID, gomock.Any(),
	).Return(nil, errors.GeneralError("boom"))

	// ...build request, PUT, assert 500
}

Want me to open a ticket to track this?

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

In `@pkg/handlers/resource_status_handler_test.go` around lines 297 - 342, Add a
test in TestRootResourceHandler_CreateStatus coverage for the real error path
from ProcessAdapterStatus: mock GetByID to return the resource, have
ProcessAdapterStatus return a non-nil *errors.ServiceError such as
errors.GeneralError("boom"), then build the PUT request and assert CreateStatus
maps that failure to the expected HTTP 500 response instead of only covering the
happy path and discarded nil,nil case.

Source: Path instructions

pkg/handlers/root_resource_handler.go (1)

197-287: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Extract the shared status list/create flow RootResourceHandler duplicates ResourceStatusHandler’s paginate → present and convert → process → present logic. Move those pieces into shared helpers and pass the resolved kind/resource in from the caller so the status paths stay in sync.

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

In `@pkg/handlers/root_resource_handler.go` around lines 197 - 287,
RootResourceHandler duplicates the same status list/create pipeline already used
by ResourceStatusHandler. Extract the shared paginate → present and convert →
process → present logic into reusable helpers, then have ListStatuses and
CreateStatus call those helpers with the resolved resource kind and ID from
h.service.GetByID so both status paths stay aligned. Keep the presentation/error
handling centralized in the shared functions and preserve the existing
logger/presenter behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/handlers/resource_status_handler_test.go`:
- Around line 297-342: Add a test in TestRootResourceHandler_CreateStatus
coverage for the real error path from ProcessAdapterStatus: mock GetByID to
return the resource, have ProcessAdapterStatus return a non-nil
*errors.ServiceError such as errors.GeneralError("boom"), then build the PUT
request and assert CreateStatus maps that failure to the expected HTTP 500
response instead of only covering the happy path and discarded nil,nil case.

In `@pkg/handlers/root_resource_handler.go`:
- Around line 197-287: RootResourceHandler duplicates the same status
list/create pipeline already used by ResourceStatusHandler. Extract the shared
paginate → present and convert → process → present logic into reusable helpers,
then have ListStatuses and CreateStatus call those helpers with the resolved
resource kind and ID from h.service.GetByID so both status paths stay aligned.
Keep the presentation/error handling centralized in the shared functions and
preserve the existing logger/presenter behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Central YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 4d6be611-bf41-4a72-912c-1ebba95d7304

📥 Commits

Reviewing files that changed from the base of the PR and between e799cd2 and 373295a.

📒 Files selected for processing (4)
  • pkg/handlers/resource_status_handler_test.go
  • pkg/handlers/root_resource_handler.go
  • plugins/entities/plugin.go
  • plugins/entities/plugin_test.go
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • openshift-hyperfleet/architecture (manual)
  • openshift-hyperfleet/hyperfleet-api (manual)
  • openshift-hyperfleet/hyperfleet-sentinel (manual)
  • openshift-hyperfleet/hyperfleet-adapter (manual)
  • openshift-hyperfleet/hyperfleet-broker (manual)
🚧 Files skipped from review as they are similar to previous changes (2)
  • plugins/entities/plugin.go
  • plugins/entities/plugin_test.go

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants