@@ -35,6 +35,17 @@ type ClusterClient struct {
3535 client client.Client
3636}
3737
38+ // Update an object that already exists on the cluster.
39+ func (cl * ClusterClient ) Update (ctx context.Context , obj client.Object ) error {
40+ cl .Helper ()
41+ nn := types.NamespacedName {Name : obj .GetName (), Namespace : obj .GetNamespace ()}
42+ cl .Logf ("Updating object %T (%s)" , obj , nn .String ())
43+ if err := cl .client .Update (ctx , obj ); err != nil {
44+ return fmt .Errorf ("update %T (%s): %w" , obj , nn .String (), err )
45+ }
46+ return nil
47+ }
48+
3849// CreateWithCleanup creates the specified object and cleans up the object after
3950// the test completes.
4051func (cl * ClusterClient ) CreateWithCleanup (ctx context.Context , obj client.Object ) error {
@@ -51,6 +62,9 @@ func (cl *ClusterClient) CreateWithCleanup(ctx context.Context, obj client.Objec
5162 if err := cl .client .Delete (context .Background (), obj ); err != nil && ! k8serrors .IsNotFound (err ) {
5263 cl .Errorf ("CreateWithCleanup %T (%s): %s" , obj , nn .String (), err )
5364 }
65+ if err := cl .WaitForObjectNotFound (context .Background (), obj ); err != nil {
66+ cl .Errorf ("CreateWithCleanup %T (%s): %s" , obj , nn .String (), err )
67+ }
5468 })
5569 return nil
5670}
@@ -72,13 +86,35 @@ func (cl *ClusterClient) ValidateObject(ctx context.Context, obj client.Object,
7286 return nil
7387}
7488
89+ // ValidateObjectNotFound verifies the specified object does not exist.
90+ func (cl * ClusterClient ) ValidateObjectNotFound (ctx context.Context , obj client.Object ) error {
91+ cl .Helper ()
92+ nn := types.NamespacedName {Name : obj .GetName (), Namespace : obj .GetNamespace ()}
93+ cl .Logf ("ValidateObjectNotFound %T (%s)" , obj , nn .String ())
94+ err := cl .client .Get (ctx , nn , obj )
95+ if err == nil { // object still exists - error
96+ return fmt .Errorf ("ValidateObjectNotFound %T (%s): object still exists" ,
97+ obj , nn .String ())
98+ } else if ! k8serrors .IsNotFound (err ) { // unexpected error
99+ return fmt .Errorf ("ValidateObjectNotFound %T (%s): %w" ,
100+ obj , nn .String (), err )
101+ }
102+ return nil // happy path - object not found
103+ }
104+
75105// WaitForObject waits for the specified object to exist and satisfy the provided
76106// predicates.
77107func (cl * ClusterClient ) WaitForObject (ctx context.Context , obj client.Object , p ... predicates.ObjectPredicate ) error {
78108 cl .Helper ()
79109 // Static 30 second timeout, this can be adjusted if needed
80110 timeoutCtx , cancel := context .WithTimeout (ctx , 30 * time .Second )
81111 defer cancel ()
112+ start := time .Now ()
113+ nn := types.NamespacedName {Name : obj .GetName (), Namespace : obj .GetNamespace ()}
114+ defer func () {
115+ cl .Helper ()
116+ cl .Logf ("WaitForObject %T (%s) took %s" , obj , nn , time .Since (start ))
117+ }()
82118 var validationErr error
83119 for {
84120 select {
@@ -94,6 +130,33 @@ func (cl *ClusterClient) WaitForObject(ctx context.Context, obj client.Object, p
94130 }
95131}
96132
133+ // WaitForObjectNotFound waits for the specified object to not exist.
134+ func (cl * ClusterClient ) WaitForObjectNotFound (ctx context.Context , obj client.Object ) error {
135+ cl .Helper ()
136+ // Static 30 second timeout, this can be adjusted if needed
137+ timeoutCtx , cancel := context .WithTimeout (ctx , 30 * time .Second )
138+ defer cancel ()
139+ start := time .Now ()
140+ nn := types.NamespacedName {Name : obj .GetName (), Namespace : obj .GetNamespace ()}
141+ defer func () {
142+ cl .Helper ()
143+ cl .Logf ("WaitForObjectNotFound %T (%s) took %s" , obj , nn , time .Since (start ))
144+ }()
145+ var validationErr error
146+ for {
147+ select {
148+ case <- timeoutCtx .Done ():
149+ return fmt .Errorf ("timed out waiting for object: %w" , validationErr )
150+ default :
151+ if validationErr = cl .ValidateObjectNotFound (timeoutCtx , obj ); validationErr == nil {
152+ return nil
153+ }
154+ // Simple sleep for fixed duration (basic MVP)
155+ time .Sleep (time .Second )
156+ }
157+ }
158+ }
159+
97160// validateAgentSandboxInstallation verifies agent-sandbox system components are
98161// installed.
99162func (cl * ClusterClient ) validateAgentSandboxInstallation (ctx context.Context ) error {
0 commit comments