@@ -76,13 +76,46 @@ func TestE2E(t *testing.T) {
76
76
name : "random-yaml-nonroot" ,
77
77
f : func (t * testing.T ) {
78
78
t .Parallel ()
79
-
79
+ // 1. Test `WorkspaceReclaimPolicy` is unset.
80
80
cmd := exec .Command ("kubectl" , "apply" , "-f" , "e2e/testdata/random-yaml-nonroot" )
81
81
require .NoError (t , run (cmd ))
82
82
dumpLogs (t , "random-yaml-nonroot" , "pod/random-yaml-nonroot-workspace-0" )
83
83
84
- // _, err := waitFor[pulumiv1.Stack]("stacks/random-yaml-nonroot", "random-yaml-nonroot", "condition=Ready", 5*time.Minute)
85
- // assert.NoError(t, err) // Failing on CI
84
+ _ , err := waitFor [pulumiv1.Stack ]("stacks/random-yaml-nonroot" , "random-yaml-nonroot" , 5 * time .Minute , "condition=Ready" )
85
+ assert .NoError (t , err )
86
+
87
+ // Ensure that the workspace pod was not deleted after successful Stack reconciliation.
88
+ found , err := foundEvent ("Pod" , "random-yaml-nonroot-workspace-0" , "random-yaml-nonroot" , "Killing" )
89
+ assert .NoError (t , err )
90
+ assert .False (t , found )
91
+
92
+ // 2. Test `WorkspaceReclaimPolicy` is set to `Delete`.
93
+ // Update the Stack spec to set the `WorkspaceReclaimPolicy` to `Delete`.
94
+ cmd = exec .Command ("kubectl" , "patch" , "stacks" , "--namespace" , "random-yaml-nonroot" , "random-yaml-nonroot" , "--type=merge" , "-p" , `{"spec":{"workspaceReclaimPolicy":"Delete"}}` )
95
+ require .NoError (t , run (cmd ))
96
+
97
+ // Wait for the Stack to be reconciled, and observedGeneration to be updated.
98
+ _ , err = waitFor [pulumiv1.Stack ](
99
+ "stacks/random-yaml-nonroot" ,
100
+ "random-yaml-nonroot" ,
101
+ 5 * time .Minute ,
102
+ "condition=Ready" ,
103
+ "jsonpath={.status.observedGeneration}=3" )
104
+ assert .NoError (t , err )
105
+
106
+ // Ensure that the workspace pod is now deleted after successful Stack reconciliation.
107
+ retryUntil (t , 30 * time .Second , true , func () bool {
108
+ found , err = foundEvent ("Pod" , "random-yaml-nonroot-workspace-0" , "random-yaml-nonroot" , "Killing" )
109
+ assert .NoError (t , err )
110
+ return found
111
+ })
112
+
113
+ if t .Failed () {
114
+ cmd := exec .Command ("kubectl" , "get" , "pods" , "-A" )
115
+ out , err := cmd .CombinedOutput ()
116
+ assert .NoError (t , err )
117
+ t .Log (string (out ))
118
+ }
86
119
},
87
120
},
88
121
{
@@ -92,12 +125,11 @@ func TestE2E(t *testing.T) {
92
125
if os .Getenv ("PULUMI_BOT_TOKEN" ) == "" {
93
126
t .Skip ("missing PULUMI_BOT_TOKEN" )
94
127
}
95
-
96
128
cmd := exec .Command ("bash" , "-c" , "envsubst < e2e/testdata/git-auth-nonroot/* | kubectl apply -f -" )
97
129
require .NoError (t , run (cmd ))
98
130
dumpLogs (t , "git-auth-nonroot" , "pod/git-auth-nonroot-workspace-0" )
99
131
100
- stack , err := waitFor [pulumiv1.Stack ]("stacks/git-auth-nonroot" , "git-auth-nonroot" , "condition=Ready" , 5 * time .Minute )
132
+ stack , err := waitFor [pulumiv1.Stack ]("stacks/git-auth-nonroot" , "git-auth-nonroot" , 5 * time .Minute , "condition=Ready" )
101
133
assert .NoError (t , err )
102
134
103
135
assert .Equal (t , `"[secret]"` , string (stack .Status .Outputs ["secretOutput" ].Raw ))
@@ -113,7 +145,7 @@ func TestE2E(t *testing.T) {
113
145
require .NoError (t , run (cmd ))
114
146
dumpLogs (t , "targets" , "pod/targets-workspace-0" )
115
147
116
- stack , err := waitFor [pulumiv1.Stack ]("stacks/targets" , "targets" , "condition=Ready" , 5 * time .Minute )
148
+ stack , err := waitFor [pulumiv1.Stack ]("stacks/targets" , "targets" , 5 * time .Minute , "condition=Ready" )
117
149
assert .NoError (t , err )
118
150
119
151
assert .Contains (t , stack .Status .Outputs , "targeted" )
@@ -127,6 +159,19 @@ func TestE2E(t *testing.T) {
127
159
}
128
160
}
129
161
162
+ // retryUntil retries the provided function until it returns the required condition or the deadline is reached.
163
+ func retryUntil (t * testing.T , d time.Duration , condition bool , f func () bool ) {
164
+ t .Helper ()
165
+ deadline := time .Now ().Add (d )
166
+ for time .Now ().Before (deadline ) {
167
+ if f () == condition {
168
+ return
169
+ }
170
+ time .Sleep (1 * time .Second )
171
+ }
172
+ t .Fatalf ("timed out waiting for condition" )
173
+ }
174
+
130
175
// dumpLogs prints logs if the test fails.
131
176
func dumpLogs (t * testing.T , namespace , name string ) {
132
177
t .Cleanup (func () {
@@ -141,13 +186,22 @@ func dumpLogs(t *testing.T, namespace, name string) {
141
186
})
142
187
}
143
188
144
- func waitFor [T any ](name , namespace , condition string , d time.Duration ) (* T , error ) {
189
+ func waitFor [T any ](name , namespace string , d time.Duration , conditions ... string ) (* T , error ) {
190
+ if len (conditions ) == 0 {
191
+ return nil , fmt .Errorf ("no conditions provided" )
192
+ }
193
+
145
194
cmd := exec .Command ("kubectl" , "wait" , name ,
146
195
"-n" , namespace ,
147
- "--for" , condition ,
196
+ "--for" , conditions [ 0 ] ,
148
197
fmt .Sprintf ("--timeout=%ds" , int (d .Seconds ())),
149
198
"--output=yaml" ,
150
199
)
200
+ // Add additional conditions if provided.
201
+ for _ , condition := range conditions [1 :] {
202
+ cmd .Args = append (cmd .Args , "--for" , condition )
203
+ }
204
+
151
205
err := run (cmd )
152
206
if err != nil {
153
207
return nil , err
@@ -163,6 +217,22 @@ func waitFor[T any](name, namespace, condition string, d time.Duration) (*T, err
163
217
return & obj , nil
164
218
}
165
219
220
+ // foundEvent checks if a Kubernetes event with the given kind, name, namespace, and reason exists.
221
+ func foundEvent (kind , name , namespace , reason string ) (bool , error ) {
222
+ cmd := exec .Command ("kubectl" , "get" , "events" ,
223
+ "-n" , namespace ,
224
+ "--field-selector" , fmt .Sprintf ("involvedObject.kind=%s,involvedObject.name=%s,reason=%s" , kind , name , reason ),
225
+ "--output=name" ,
226
+ )
227
+ err := run (cmd )
228
+ if err != nil {
229
+ return false , err
230
+ }
231
+
232
+ buf , _ := cmd .Stdout .(* bytes.Buffer )
233
+ return strings .Contains (buf .String (), "event/" + name ), nil
234
+ }
235
+
166
236
// run executes the provided command within this context
167
237
func run (cmd * exec.Cmd ) error {
168
238
command := strings .Join (cmd .Args , " " )
0 commit comments