Skip to content

Commit 43b1efb

Browse files
dmartinolCopilot
andauthored
Refactor status collector architecture with structured errors (#2016)
* Refactor status collector architecture with structured errors * added deriver to codespell ignore list * more test coverage Signed-off-by: Daniele Martinoli <[email protected]> * review comment Signed-off-by: Daniele Martinoli <[email protected]> * Add MCPRegistry status management improvements - Removed the `Idle` phase from `SyncPhase` and updated related logic to ensure only `Syncing`, `Complete`, and `Failed` phases are used. - Enhanced the `ShouldSync` method to avoid syncing when the requeue timeout did not elapse. - Avoid updating sync status at all if sync is not needed (it would cause a new reconciliation) Signed-off-by: Daniele Martinoli <[email protected]> * chart version bump Signed-off-by: Daniele Martinoli <[email protected]> * Update cmd/thv-operator/pkg/mcpregistrystatus/types.go Co-authored-by: Copilot <[email protected]> --------- Signed-off-by: Daniele Martinoli <[email protected]> Co-authored-by: Copilot <[email protected]>
1 parent a517677 commit 43b1efb

23 files changed

+1169
-632
lines changed

.codespellrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
[codespell]
2-
ignore-words-list = NotIn,notin,AfterAll,ND,aks
2+
ignore-words-list = NotIn,notin,AfterAll,ND,aks,deriver
33
skip = *.svg,*.mod,*.sum

cmd/thv-operator/api/v1alpha1/mcpregistry_types.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ type MCPRegistryStatus struct {
205205
// SyncStatus provides detailed information about data synchronization
206206
type SyncStatus struct {
207207
// Phase represents the current synchronization phase
208-
// +kubebuilder:validation:Enum=Idle;Syncing;Complete;Failed
208+
// +kubebuilder:validation:Enum=Syncing;Complete;Failed
209209
Phase SyncPhase `json:"phase"`
210210

211211
// Message provides additional information about the sync status
@@ -256,13 +256,10 @@ type APIStatus struct {
256256
}
257257

258258
// SyncPhase represents the data synchronization state
259-
// +kubebuilder:validation:Enum=Idle;Syncing;Complete;Failed
259+
// +kubebuilder:validation:Enum=Syncing;Complete;Failed
260260
type SyncPhase string
261261

262262
const (
263-
// SyncPhaseIdle means no sync is needed or scheduled
264-
SyncPhaseIdle SyncPhase = "Idle"
265-
266263
// SyncPhaseSyncing means sync is currently in progress
267264
SyncPhaseSyncing SyncPhase = "Syncing"
268265

@@ -389,7 +386,7 @@ func (r *MCPRegistry) DeriveOverallPhase() MCPRegistryPhase {
389386
apiStatus := r.Status.APIStatus
390387

391388
// Default phases if status not set
392-
syncPhase := SyncPhaseIdle
389+
var syncPhase SyncPhase
393390
if syncStatus != nil {
394391
syncPhase = syncStatus.Phase
395392
}
@@ -409,8 +406,8 @@ func (r *MCPRegistry) DeriveOverallPhase() MCPRegistryPhase {
409406
return MCPRegistryPhaseSyncing
410407
}
411408

412-
// If sync is complete or idle (no sync needed), check API status
413-
if syncPhase == SyncPhaseComplete || syncPhase == SyncPhaseIdle {
409+
// If sync is complete (no sync needed), check API status
410+
if syncPhase == SyncPhaseComplete {
414411
switch apiPhase {
415412
case APIPhaseReady:
416413
return MCPRegistryPhaseReady

cmd/thv-operator/api/v1alpha1/mcpregistry_types_test.go

Lines changed: 6 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -131,63 +131,6 @@ func TestMCPRegistry_DeriveOverallPhase(t *testing.T) {
131131
description: "Sync complete + API unhealthy should result in Pending",
132132
},
133133

134-
// Sync Idle + API combinations (key test cases for the recent fix)
135-
{
136-
name: "sync_idle_api_ready",
137-
syncStatus: &SyncStatus{
138-
Phase: SyncPhaseIdle,
139-
},
140-
apiStatus: &APIStatus{
141-
Phase: APIPhaseReady,
142-
},
143-
expectedPhase: MCPRegistryPhaseReady,
144-
description: "Sync idle + API ready should result in Ready (fixed behavior)",
145-
},
146-
{
147-
name: "sync_idle_api_error",
148-
syncStatus: &SyncStatus{
149-
Phase: SyncPhaseIdle,
150-
},
151-
apiStatus: &APIStatus{
152-
Phase: APIPhaseError,
153-
},
154-
expectedPhase: MCPRegistryPhaseFailed,
155-
description: "Sync idle + API error should result in Failed",
156-
},
157-
{
158-
name: "sync_idle_api_notstarted",
159-
syncStatus: &SyncStatus{
160-
Phase: SyncPhaseIdle,
161-
},
162-
apiStatus: &APIStatus{
163-
Phase: APIPhaseNotStarted,
164-
},
165-
expectedPhase: MCPRegistryPhasePending,
166-
description: "Sync idle + API not started should result in Pending",
167-
},
168-
{
169-
name: "sync_idle_api_deploying",
170-
syncStatus: &SyncStatus{
171-
Phase: SyncPhaseIdle,
172-
},
173-
apiStatus: &APIStatus{
174-
Phase: APIPhaseDeploying,
175-
},
176-
expectedPhase: MCPRegistryPhasePending,
177-
description: "Sync idle + API deploying should result in Pending",
178-
},
179-
{
180-
name: "sync_idle_api_unhealthy",
181-
syncStatus: &SyncStatus{
182-
Phase: SyncPhaseIdle,
183-
},
184-
apiStatus: &APIStatus{
185-
Phase: APIPhaseUnhealthy,
186-
},
187-
expectedPhase: MCPRegistryPhasePending,
188-
description: "Sync idle + API unhealthy should result in Pending",
189-
},
190-
191134
// Partial status combinations (one nil, one set)
192135
{
193136
name: "sync_complete_api_nil",
@@ -200,19 +143,8 @@ func TestMCPRegistry_DeriveOverallPhase(t *testing.T) {
200143
name: "sync_nil_api_ready",
201144
syncStatus: nil,
202145
apiStatus: &APIStatus{Phase: APIPhaseReady},
203-
expectedPhase: MCPRegistryPhaseReady,
204-
description: "Sync nil + API ready should result in Ready (sync defaults to Idle, which is treated as valid)",
205-
},
206-
207-
// Edge case: sync idle with nil API (common in real scenarios)
208-
{
209-
name: "sync_idle_api_nil",
210-
syncStatus: &SyncStatus{
211-
Phase: SyncPhaseIdle,
212-
},
213-
apiStatus: nil,
214146
expectedPhase: MCPRegistryPhasePending,
215-
description: "Sync idle + API nil should result in Pending (API defaults to NotStarted)",
147+
description: "Sync nil + API ready should result in Pending",
216148
},
217149
}
218150

@@ -247,7 +179,7 @@ func TestMCPRegistry_DeriveOverallPhase(t *testing.T) {
247179
// Helper function to get sync phase as string for better test output
248180
func getSyncPhaseString(syncStatus *SyncStatus) string {
249181
if syncStatus == nil {
250-
return "nil (defaults to Idle)"
182+
return "nil"
251183
}
252184
return string(syncStatus.Phase)
253185
}
@@ -264,20 +196,20 @@ func getAPIPhaseString(apiStatus *APIStatus) string {
264196
func TestMCPRegistry_DeriveOverallPhase_EdgeCases(t *testing.T) {
265197
t.Parallel()
266198

267-
t.Run("regression_test_idle_ready_becomes_ready", func(t *testing.T) {
199+
t.Run("regression_test_complete_ready_becomes_ready", func(t *testing.T) {
268200
t.Parallel()
269201
// This is the specific regression test for the bug fix where
270-
// syncPhase=Idle + apiPhase=Ready was incorrectly returning Pending
202+
// syncPhase=Complete + apiPhase=Ready was incorrectly returning Pending
271203
registry := &MCPRegistry{
272204
Status: MCPRegistryStatus{
273-
SyncStatus: &SyncStatus{Phase: SyncPhaseIdle},
205+
SyncStatus: &SyncStatus{Phase: SyncPhaseComplete},
274206
APIStatus: &APIStatus{Phase: APIPhaseReady},
275207
},
276208
}
277209

278210
phase := registry.DeriveOverallPhase()
279211
assert.Equal(t, MCPRegistryPhaseReady, phase,
280-
"The specific case syncPhase=Idle + apiPhase=Ready should result in Ready phase")
212+
"The specific case syncPhase=Complete + apiPhase=Ready should result in Ready phase")
281213
})
282214

283215
t.Run("all_api_phases_with_failed_sync", func(t *testing.T) {

0 commit comments

Comments
 (0)