From 899e388db56cdf8679388a5a4e376864dc04f2c4 Mon Sep 17 00:00:00 2001 From: Calum Murray Date: Mon, 13 Apr 2026 09:44:56 -0400 Subject: [PATCH] fix: wait works when no conditions set Signed-off-by: Calum Murray --- pkg/extension/operations.go | 2 +- pkg/extension/wait.go | 26 +++++++++-- pkg/extension/wait_test.go | 91 ++++++++++++++++++++++++++++++++++++- 3 files changed, 113 insertions(+), 6 deletions(-) diff --git a/pkg/extension/operations.go b/pkg/extension/operations.go index 5bb481e..ac764b2 100644 --- a/pkg/extension/operations.go +++ b/pkg/extension/operations.go @@ -70,7 +70,7 @@ func (e *Extension) registerOperations() { Description: "Timeout duration (e.g., 60s, 5m, default: 60s)", }, }, - Required: []string{"apiVersion", "kind", "metadata", "condition"}, + Required: []string{"apiVersion", "kind", "metadata"}, }), ), e.handleWait, diff --git a/pkg/extension/wait.go b/pkg/extension/wait.go index f19d4b1..5a180b1 100644 --- a/pkg/extension/wait.go +++ b/pkg/extension/wait.go @@ -26,9 +26,6 @@ func (e *Extension) handleWait(ctx context.Context, req *sdk.OperationRequest) ( } condition, _ := args["condition"].(string) - if condition == "" { - return sdk.Failure(fmt.Errorf("condition is required")), nil - } status, _ := args["status"].(string) if status == "" { @@ -66,6 +63,11 @@ func (e *Extension) handleWait(ctx context.Context, req *sdk.OperationRequest) ( return false, nil // Keep polling on transient errors } + // No condition specified — resource exists, that's enough + if condition == "" { + return true, nil + } + conditions, found, err := unstructured.NestedSlice(obj.Object, "status", "conditions") if err != nil || !found { lastStatus = "NoConditions" @@ -92,6 +94,16 @@ func (e *Extension) handleWait(ctx context.Context, req *sdk.OperationRequest) ( }) if err != nil { + if condition == "" { + e.LogError(ctx, "Resource wait timed out", map[string]any{ + "kind": ref.kind, + "name": ref.name, + }) + return sdk.FailureWithMessage( + fmt.Sprintf("Resource %s/%s not found", ref.kind, ref.name), + fmt.Errorf("timed out waiting for %s/%s to exist", ref.kind, ref.name), + ), nil + } e.LogError(ctx, "Condition wait timed out", map[string]any{ "kind": ref.kind, "name": ref.name, @@ -104,6 +116,14 @@ func (e *Extension) handleWait(ctx context.Context, req *sdk.OperationRequest) ( ), nil } + if condition == "" { + e.LogInfo(ctx, "Resource exists", map[string]any{ + "kind": ref.kind, + "name": ref.name, + }) + return sdk.Success(fmt.Sprintf("%s/%s exists", ref.kind, ref.name)), nil + } + e.LogInfo(ctx, "Condition met", map[string]any{ "kind": ref.kind, "name": ref.name, diff --git a/pkg/extension/wait_test.go b/pkg/extension/wait_test.go index 9697566..f38c2a5 100644 --- a/pkg/extension/wait_test.go +++ b/pkg/extension/wait_test.go @@ -2,6 +2,7 @@ package extension import ( "context" + "fmt" "testing" "github.com/mcpchecker/mcpchecker/pkg/extension/sdk" @@ -65,13 +66,99 @@ func TestHandleWait(t *testing.T) { wantSuccess: false, }, { - name: "missing condition field", + name: "missing condition field checks existence", args: map[string]any{ "apiVersion": "v1", "kind": "Pod", "metadata": map[string]any{"name": "test"}, + "timeout": "1s", + }, + client: &mockClient{ + getFn: func(ctx context.Context, gvr schema.GroupVersionResource, name, namespace string) (*unstructured.Unstructured, error) { + return &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "v1", + "kind": "Pod", + "metadata": map[string]any{"name": "test"}, + }, + }, nil + }, + }, + wantSuccess: true, + }, + { + name: "no condition - resource not found times out", + args: map[string]any{ + "apiVersion": "v1", + "kind": "Pod", + "metadata": map[string]any{"name": "test"}, + "timeout": "1s", + }, + client: &mockClient{ + getFn: func(ctx context.Context, gvr schema.GroupVersionResource, name, namespace string) (*unstructured.Unstructured, error) { + return nil, fmt.Errorf("not found") + }, + }, + wantSuccess: false, + }, + { + name: "no condition - succeeds when resource exists", + args: map[string]any{ + "apiVersion": "networking.istio.io/v1", + "kind": "Gateway", + "metadata": map[string]any{"name": "my-gateway", "namespace": "istio-system"}, + "timeout": "2s", + }, + client: &mockClient{ + getFn: func(ctx context.Context, gvr schema.GroupVersionResource, name, namespace string) (*unstructured.Unstructured, error) { + return &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "networking.istio.io/v1", + "kind": "Gateway", + "metadata": map[string]any{ + "name": "my-gateway", + "namespace": "istio-system", + }, + "spec": map[string]any{ + "selector": map[string]any{ + "istio": "ingressgateway", + }, + }, + }, + }, nil + }, + }, + wantSuccess: true, + }, + { + name: "resource without status.conditions times out (e.g. Istio Gateway)", + args: map[string]any{ + "apiVersion": "networking.istio.io/v1", + "kind": "Gateway", + "metadata": map[string]any{"name": "my-gateway", "namespace": "istio-system"}, + "condition": "Available", + "status": "True", + "timeout": "2s", + }, + client: &mockClient{ + getFn: func(ctx context.Context, gvr schema.GroupVersionResource, name, namespace string) (*unstructured.Unstructured, error) { + return &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": "networking.istio.io/v1", + "kind": "Gateway", + "metadata": map[string]any{ + "name": "my-gateway", + "namespace": "istio-system", + }, + "spec": map[string]any{ + "selector": map[string]any{ + "istio": "ingressgateway", + }, + }, + }, + }, nil + }, }, - client: &mockClient{}, wantSuccess: false, }, }