Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/test/tests/components/ws-manager/prebuild_test.go
2500 views
1
// Copyright (c) 2020 Gitpod GmbH. All rights reserved.
2
// Licensed under the GNU Affero General Public License (AGPL).
3
// See License.AGPL.txt in the project root for license information.
4
5
package wsmanager
6
7
import (
8
"context"
9
"encoding/json"
10
"errors"
11
"fmt"
12
"path/filepath"
13
"strings"
14
"testing"
15
"time"
16
17
"sigs.k8s.io/e2e-framework/pkg/envconf"
18
"sigs.k8s.io/e2e-framework/pkg/features"
19
20
csapi "github.com/gitpod-io/gitpod/content-service/api"
21
gitpod "github.com/gitpod-io/gitpod/gitpod-protocol"
22
agent "github.com/gitpod-io/gitpod/test/pkg/agent/workspace/api"
23
"github.com/gitpod-io/gitpod/test/pkg/integration"
24
wsmanapi "github.com/gitpod-io/gitpod/ws-manager/api"
25
)
26
27
func TestPrebuildWorkspaceTaskSuccess(t *testing.T) {
28
f := features.New("prebuild").
29
WithLabel("component", "ws-manager").
30
Assess("it should create a prebuild and succeed the defined tasks", func(testCtx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
31
tests := []struct {
32
Name string
33
ContextURL string
34
WorkspaceRoot string
35
CheckoutLocation string
36
Task []gitpod.TasksItems
37
FF []wsmanapi.WorkspaceFeatureFlag
38
}{
39
{
40
Name: "classic",
41
ContextURL: "https://github.com/gitpod-io/empty",
42
CheckoutLocation: "empty",
43
WorkspaceRoot: "/workspace/empty",
44
Task: []gitpod.TasksItems{
45
{Init: "echo \"some output\" > someFile; exit 0;"},
46
},
47
},
48
}
49
for _, test := range tests {
50
test := test
51
t.Run(test.Name, func(t *testing.T) {
52
t.Parallel()
53
54
ctx, cancel := context.WithTimeout(testCtx, time.Duration(5*len(tests))*time.Minute)
55
defer cancel()
56
57
api := integration.NewComponentAPI(ctx, cfg.Namespace(), kubeconfig, cfg.Client())
58
t.Cleanup(func() {
59
api.Done(t)
60
})
61
62
// TODO: change to use server API to launch the workspace, so we could run the integration test as the user code flow
63
// which is client -> server -> ws-manager rather than client -> ws-manager directly
64
ws, stopWs, err := integration.LaunchWorkspaceDirectly(t, ctx, api, integration.WithRequestModifier(func(req *wsmanapi.StartWorkspaceRequest) error {
65
req.Type = wsmanapi.WorkspaceType_PREBUILD
66
67
tasks, err := json.Marshal(test.Task)
68
if err != nil {
69
return err
70
}
71
req.Spec.Envvars = append(req.Spec.Envvars, &wsmanapi.EnvironmentVariable{
72
Name: "GITPOD_TASKS",
73
Value: string(tasks),
74
})
75
76
req.Spec.FeatureFlags = test.FF
77
req.Spec.Initializer = &csapi.WorkspaceInitializer{
78
Spec: &csapi.WorkspaceInitializer_Git{
79
Git: &csapi.GitInitializer{
80
RemoteUri: test.ContextURL,
81
CheckoutLocation: test.CheckoutLocation,
82
Config: &csapi.GitConfig{},
83
},
84
},
85
}
86
req.Spec.WorkspaceLocation = test.CheckoutLocation
87
return nil
88
}), integration.WithWaitWorkspaceForOpts(integration.WaitForStopped))
89
if err != nil {
90
t.Fatalf("cannot launch a workspace: %q", err)
91
}
92
t.Cleanup(func() {
93
// stop workspace in defer function to prevent we forget to stop the workspace
94
if err := stopWorkspace(t, cfg, stopWs); err != nil {
95
t.Errorf("cannot stop workspace: %q", err)
96
}
97
})
98
99
if ws.LastStatus == nil {
100
t.Fatal("workspace status is nil")
101
}
102
if ws.LastStatus.Phase != wsmanapi.WorkspacePhase_STOPPED {
103
t.Fatalf("unexpected workspace phase: %v", ws.LastStatus.Phase)
104
}
105
if ws.LastStatus.Conditions != nil && ws.LastStatus.Conditions.HeadlessTaskFailed != "" {
106
t.Logf("Conditions: %v", ws.LastStatus.Conditions)
107
t.Fatalf("unexpected HeadlessTaskFailed condition: %v", ws.LastStatus.Conditions.HeadlessTaskFailed)
108
}
109
})
110
}
111
return testCtx
112
}).
113
Feature()
114
115
testEnv.Test(t, f)
116
}
117
118
func TestPrebuildWorkspaceTaskFail(t *testing.T) {
119
f := features.New("prebuild").
120
WithLabel("component", "server").
121
Assess("it should create a prebuild and fail after running the defined tasks", func(testCtx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
122
t.Parallel()
123
124
ctx, cancel := context.WithTimeout(testCtx, 5*time.Minute)
125
defer cancel()
126
127
api := integration.NewComponentAPI(ctx, cfg.Namespace(), kubeconfig, cfg.Client())
128
t.Cleanup(func() {
129
api.Done(t)
130
})
131
132
ws, stopWs, err := integration.LaunchWorkspaceDirectly(t, ctx, api, integration.WithRequestModifier(func(req *wsmanapi.StartWorkspaceRequest) error {
133
req.Type = wsmanapi.WorkspaceType_PREBUILD
134
req.Spec.Envvars = append(req.Spec.Envvars, &wsmanapi.EnvironmentVariable{
135
Name: "GITPOD_TASKS",
136
Value: `[{ "init": "echo \"some output\" > someFile; exit 1;" }]`,
137
})
138
return nil
139
}), integration.WithWaitWorkspaceForOpts(integration.WaitForStopped))
140
if err != nil {
141
t.Fatalf("cannot start workspace: %q", err)
142
}
143
144
t.Cleanup(func() {
145
// stop workspace in defer function to prevent we forget to stop the workspace
146
if err := stopWorkspace(t, cfg, stopWs); err != nil {
147
t.Errorf("cannot stop workspace: %q", err)
148
}
149
})
150
151
if ws.LastStatus == nil {
152
t.Fatal("workspace status is nil")
153
}
154
if ws.LastStatus.Phase != wsmanapi.WorkspacePhase_STOPPED {
155
t.Fatalf("unexpected workspace phase: %v", ws.LastStatus.Phase)
156
}
157
if ws.LastStatus.Conditions == nil || ws.LastStatus.Conditions.HeadlessTaskFailed == "" {
158
t.Logf("Status: %v", ws.LastStatus)
159
t.Fatal("expected HeadlessTaskFailed condition")
160
}
161
162
return testCtx
163
}).
164
Feature()
165
166
testEnv.Test(t, f)
167
}
168
169
const (
170
prebuildLogPath string = "/workspace/.gitpod"
171
prebuildLog string = "'🍊 This task ran as a workspace prebuild'"
172
initTask string = "echo \"some output\" > someFile;"
173
regularPrefix string = "ws-"
174
)
175
176
// TestOpenWorkspaceFromPrebuild
177
// - create a prebuild
178
// - stop the prebuild workspace
179
// - open the regular workspace from prebuild
180
// - make sure either one of the condition mets
181
// - the prebuild log message exists
182
// - the init task message exists
183
// - the init task generated file exists
184
//
185
// - make sure the .git/ folder with correct permission
186
// - write a new file foobar.txt
187
// - stop the regular workspace
188
// - relaunch the regular workspace
189
// - make sure the file foobar.txt exists
190
func TestOpenWorkspaceFromPrebuild(t *testing.T) {
191
f := features.New("prebuild").
192
WithLabel("component", "ws-manager").
193
Assess("it should open workspace from prebuild successfully", func(testCtx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
194
tests := []struct {
195
Name string
196
ContextURL string
197
WorkspaceRoot string
198
CheckoutLocation string
199
FF []wsmanapi.WorkspaceFeatureFlag
200
}{
201
{
202
Name: "classic",
203
ContextURL: "https://github.com/gitpod-io/empty",
204
CheckoutLocation: "empty",
205
WorkspaceRoot: "/workspace/empty",
206
},
207
}
208
209
for _, test := range tests {
210
test := test
211
t.Run(test.Name, func(t *testing.T) {
212
t.Parallel()
213
214
ctx, cancel := context.WithTimeout(testCtx, time.Duration(10*len(tests))*time.Minute)
215
defer cancel()
216
217
api := integration.NewComponentAPI(ctx, cfg.Namespace(), kubeconfig, cfg.Client())
218
t.Cleanup(func() {
219
api.Done(t)
220
})
221
222
var prebuildSnapshot string
223
func() {
224
// create a prebuild and stop workspace
225
// TODO: change to use server API to launch the workspace, so we could run the integration test as the user code flow
226
// which is client -> server -> ws-manager rather than client -> ws-manager directly
227
ws, prebuildStopWs, err := integration.LaunchWorkspaceDirectly(t, ctx, api,
228
integration.WithRequestModifier(func(req *wsmanapi.StartWorkspaceRequest) error {
229
req.Type = wsmanapi.WorkspaceType_PREBUILD
230
req.Spec.Envvars = append(req.Spec.Envvars, &wsmanapi.EnvironmentVariable{
231
Name: "GITPOD_TASKS",
232
Value: fmt.Sprintf(`[{ "init": %q }]`, initTask),
233
})
234
req.Spec.FeatureFlags = test.FF
235
req.Spec.Initializer = &csapi.WorkspaceInitializer{
236
Spec: &csapi.WorkspaceInitializer_Git{
237
Git: &csapi.GitInitializer{
238
RemoteUri: test.ContextURL,
239
CheckoutLocation: test.CheckoutLocation,
240
Config: &csapi.GitConfig{},
241
},
242
},
243
}
244
req.Spec.WorkspaceLocation = test.CheckoutLocation
245
return nil
246
}),
247
// Wait for the prebuild to finish, as this can happen quickly before we
248
// would have time to observe the workspace to stop and get its status.
249
integration.WithWaitWorkspaceForOpts(integration.WaitForStopped),
250
)
251
if err != nil {
252
t.Fatalf("cannot launch a workspace: %q", err)
253
}
254
defer func() {
255
if err := stopWorkspace(t, cfg, prebuildStopWs); err != nil {
256
t.Errorf("cannot stop workspace: %q", err)
257
}
258
}()
259
260
prebuildSnapshot, _, err = findSnapshotFromStoppedWs(t, ctx, ws.LastStatus)
261
if err != nil {
262
_ = stopWorkspace(t, cfg, prebuildStopWs)
263
t.Fatalf("stop workspace and find snapshot error: %v", err)
264
}
265
266
t.Logf("prebuild snapshot: %s", prebuildSnapshot)
267
268
// check the prebuild logs have been uploaded
269
checkPrebuildLogUploaded(t, ctx, api, ws)
270
}()
271
272
// launch the workspace from prebuild
273
// TODO: change to use server API to launch the workspace, so we could run the integration test as the user code flow
274
// which is client -> server -> ws-manager rather than client -> ws-manager directly
275
ws, stopWsFunc, err := integration.LaunchWorkspaceDirectly(t, ctx, api, integration.WithRequestModifier(func(req *wsmanapi.StartWorkspaceRequest) error {
276
req.Spec.FeatureFlags = test.FF
277
req.Spec.Initializer = &csapi.WorkspaceInitializer{
278
Spec: &csapi.WorkspaceInitializer_Prebuild{
279
Prebuild: &csapi.PrebuildInitializer{
280
Prebuild: &csapi.SnapshotInitializer{
281
Snapshot: prebuildSnapshot,
282
FromVolumeSnapshot: false,
283
},
284
Git: []*csapi.GitInitializer{
285
{
286
RemoteUri: test.ContextURL,
287
CheckoutLocation: test.CheckoutLocation,
288
Config: &csapi.GitConfig{},
289
},
290
},
291
},
292
},
293
}
294
295
req.Spec.WorkspaceLocation = test.CheckoutLocation
296
return nil
297
}))
298
if err != nil {
299
t.Fatalf("cannot launch a workspace: %q", err)
300
}
301
302
t.Cleanup(func() {
303
// stop workspace in defer function to prevent we forget to stop the workspace
304
if err := stopWorkspace(t, cfg, stopWsFunc); err != nil {
305
t.Errorf("cannot stop workspace: %q", err)
306
}
307
})
308
309
rsa, closer, err := integration.Instrument(integration.ComponentWorkspace, "workspace", cfg.Namespace(), kubeconfig, cfg.Client(),
310
integration.WithInstanceID(ws.Req.Id),
311
)
312
if err != nil {
313
t.Fatal(err)
314
}
315
t.Cleanup(func() {
316
rsa.Close()
317
})
318
integration.DeferCloser(t, closer)
319
320
// check prebuild log message exists
321
checkPrebuildLogExist(t, cfg, rsa, ws, test.WorkspaceRoot)
322
323
// check the folder permission is gitpod
324
checkFolderPermission(t, rsa, "/workspace")
325
326
// check the files/folders permission under .git/ is gitpod
327
checkGitFolderPermission(t, rsa, test.WorkspaceRoot)
328
329
// write file foobar.txt and stop the workspace
330
var writeFileResp agent.ExecResponse
331
err = rsa.Call("WorkspaceAgent.WriteFile", &agent.WriteFileRequest{
332
Path: fmt.Sprintf("%s/foobar.txt", test.WorkspaceRoot),
333
Content: []byte("hello world"),
334
Mode: 0644,
335
}, &writeFileResp)
336
if err != nil {
337
t.Fatalf("cannot write file %s", fmt.Sprintf("%s/foobar.txt", test.WorkspaceRoot))
338
}
339
340
sctx, scancel := context.WithTimeout(context.Background(), 5*time.Minute)
341
defer scancel()
342
343
sapi := integration.NewComponentAPI(sctx, cfg.Namespace(), kubeconfig, cfg.Client())
344
defer sapi.Done(t)
345
346
// stop workspace and wait, we're about to restart it
347
_, err = stopWsFunc(true, sapi)
348
if err != nil {
349
t.Fatal(err)
350
}
351
352
// reopen the workspace and make sure the file foobar.txt exists
353
ws1, stopWs1Func, err := integration.LaunchWorkspaceDirectly(t, ctx, sapi, integration.WithRequestModifier(func(req *wsmanapi.StartWorkspaceRequest) error {
354
req.ServicePrefix = ws.Req.ServicePrefix
355
req.Metadata.MetaId = ws.Req.Metadata.MetaId
356
req.Metadata.Owner = ws.Req.Metadata.Owner
357
req.Spec.FeatureFlags = test.FF
358
req.Spec.Initializer = &csapi.WorkspaceInitializer{
359
Spec: &csapi.WorkspaceInitializer_Backup{
360
Backup: &csapi.FromBackupInitializer{
361
CheckoutLocation: test.CheckoutLocation,
362
FromVolumeSnapshot: false,
363
},
364
},
365
}
366
req.Spec.WorkspaceLocation = test.CheckoutLocation
367
return nil
368
}))
369
if err != nil {
370
t.Fatalf("cannot launch a workspace: %q", err)
371
}
372
373
t.Cleanup(func() {
374
// stop workspace in defer function to prevent we forget to stop the workspace
375
if err := stopWorkspace(t, cfg, stopWs1Func); err != nil {
376
t.Errorf("cannot stop workspace: %q", err)
377
}
378
})
379
380
rsa, closer, err = integration.Instrument(integration.ComponentWorkspace, "workspace", cfg.Namespace(), kubeconfig, cfg.Client(),
381
integration.WithInstanceID(ws1.Req.Id),
382
)
383
if err != nil {
384
t.Fatal(err)
385
}
386
integration.DeferCloser(t, closer)
387
388
var ls agent.ListDirResponse
389
err = rsa.Call("WorkspaceAgent.ListDir", &agent.ListDirRequest{
390
Dir: test.WorkspaceRoot,
391
}, &ls)
392
if err != nil {
393
t.Fatal(err)
394
}
395
rsa.Close()
396
397
var found bool
398
for _, f := range ls.Files {
399
if filepath.Base(f) == "foobar.txt" {
400
found = true
401
break
402
}
403
}
404
if !found {
405
t.Fatal("did not find foobar.txt from previous workspace instance")
406
}
407
})
408
}
409
return testCtx
410
}).
411
Feature()
412
413
testEnv.Test(t, f)
414
}
415
416
// TestOpenWorkspaceFromOutdatedPrebuild
417
// - create a prebuild on older commit
418
// - open a workspace from a later commit with a prebuild initializer
419
// - make sure the workspace's init task ran (the init task will create a file `incremental.txt` see https://github.com/gitpod-io/test-incremental-workspace/blob/main/.gitpod.yml)
420
func TestOpenWorkspaceFromOutdatedPrebuild(t *testing.T) {
421
422
f := features.New("prebuild").
423
WithLabel("component", "ws-manager").
424
Assess("it should open a workspace from with an older prebuild initializer successfully and run the init task", func(testCtx context.Context, t *testing.T, cfg *envconf.Config) context.Context {
425
tests := []struct {
426
Name string
427
RemoteUri string
428
CloneTargetForPrebuild string
429
CloneTargetForWorkspace string
430
WorkspaceRoot string
431
CheckoutLocation string
432
FF []wsmanapi.WorkspaceFeatureFlag
433
}{
434
{
435
Name: "classic",
436
RemoteUri: "https://github.com/gitpod-io/test-incremental-workspace",
437
CloneTargetForPrebuild: "prebuild",
438
CloneTargetForWorkspace: "main",
439
CheckoutLocation: "test-incremental-workspace",
440
WorkspaceRoot: "/workspace/test-incremental-workspace",
441
},
442
}
443
444
for _, test := range tests {
445
test := test
446
t.Run(test.Name, func(t *testing.T) {
447
t.Parallel()
448
449
ctx, cancel := context.WithTimeout(testCtx, time.Duration(10*len(tests))*time.Minute)
450
defer cancel()
451
452
api := integration.NewComponentAPI(ctx, cfg.Namespace(), kubeconfig, cfg.Client())
453
t.Cleanup(func() {
454
api.Done(t)
455
})
456
457
// create a prebuild
458
ws, prebuildStopWs, err := integration.LaunchWorkspaceDirectly(t, ctx, api,
459
integration.WithRequestModifier(func(req *wsmanapi.StartWorkspaceRequest) error {
460
req.Type = wsmanapi.WorkspaceType_PREBUILD
461
req.Spec.Envvars = append(req.Spec.Envvars, &wsmanapi.EnvironmentVariable{
462
Name: "GITPOD_TASKS",
463
Value: `[{ "init": "./init.sh" }]`,
464
})
465
req.Spec.FeatureFlags = test.FF
466
req.Spec.Initializer = &csapi.WorkspaceInitializer{
467
Spec: &csapi.WorkspaceInitializer_Git{
468
Git: &csapi.GitInitializer{
469
RemoteUri: test.RemoteUri,
470
TargetMode: csapi.CloneTargetMode_REMOTE_BRANCH,
471
CloneTaget: test.CloneTargetForPrebuild,
472
CheckoutLocation: test.CheckoutLocation,
473
Config: &csapi.GitConfig{},
474
},
475
},
476
}
477
req.Spec.WorkspaceLocation = test.CheckoutLocation
478
return nil
479
}),
480
// The init task only runs for a short duration, so it's possible we miss the Running state, as it quickly transitions to Stopping/Stopped.
481
// Therefore wait for the workspace to stop to get its last status.
482
integration.WithWaitWorkspaceForOpts(integration.WaitForStopped))
483
if err != nil {
484
t.Fatalf("cannot launch a workspace: %q", err)
485
}
486
defer func() {
487
// stop workspace in defer function to prevent we forget to stop the workspace
488
if err := stopWorkspace(t, cfg, prebuildStopWs); err != nil {
489
t.Errorf("cannot stop workspace: %q", err)
490
}
491
}()
492
prebuildSnapshot, _, err := findSnapshotFromStoppedWs(t, ctx, ws.LastStatus)
493
if err != nil {
494
t.Fatalf("stop workspace and find snapshot error: %v", err)
495
}
496
if prebuildSnapshot == "" {
497
t.Fatalf("prebuild snapshot is empty")
498
}
499
500
t.Logf("prebuild snapshot: %s", prebuildSnapshot)
501
502
// launch the workspace on a later commit using this prebuild
503
ws, stopWs, err := integration.LaunchWorkspaceDirectly(t, ctx, api, integration.WithRequestModifier(func(req *wsmanapi.StartWorkspaceRequest) error {
504
req.Spec.Envvars = append(req.Spec.Envvars, &wsmanapi.EnvironmentVariable{
505
Name: "GITPOD_TASKS",
506
Value: `[{ "init": "./init.sh" }]`,
507
})
508
req.Spec.FeatureFlags = test.FF
509
req.Spec.Initializer = &csapi.WorkspaceInitializer{
510
Spec: &csapi.WorkspaceInitializer_Prebuild{
511
Prebuild: &csapi.PrebuildInitializer{
512
Prebuild: &csapi.SnapshotInitializer{
513
Snapshot: prebuildSnapshot,
514
},
515
Git: []*csapi.GitInitializer{
516
{
517
RemoteUri: test.RemoteUri,
518
TargetMode: csapi.CloneTargetMode_REMOTE_BRANCH,
519
CloneTaget: test.CloneTargetForWorkspace,
520
CheckoutLocation: test.CheckoutLocation,
521
Config: &csapi.GitConfig{},
522
},
523
},
524
},
525
},
526
}
527
528
req.Spec.WorkspaceLocation = test.CheckoutLocation
529
return nil
530
}))
531
if err != nil {
532
t.Fatalf("cannot launch a workspace: %q", err)
533
}
534
535
defer func() {
536
// stop workspace in defer function to prevent we forget to stop the workspace
537
if err := stopWorkspace(t, cfg, stopWs); err != nil {
538
t.Errorf("cannot stop workspace: %q", err)
539
}
540
}()
541
542
rsa, closer, err := integration.Instrument(integration.ComponentWorkspace, "workspace", cfg.Namespace(), kubeconfig, cfg.Client(),
543
integration.WithInstanceID(ws.Req.Id),
544
)
545
if err != nil {
546
t.Fatal(err)
547
}
548
t.Cleanup(func() {
549
rsa.Close()
550
})
551
integration.DeferCloser(t, closer)
552
553
var ls agent.ListDirResponse
554
err = rsa.Call("WorkspaceAgent.ListDir", &agent.ListDirRequest{
555
Dir: test.WorkspaceRoot,
556
}, &ls)
557
if err != nil {
558
t.Fatal(err)
559
}
560
rsa.Close()
561
562
var found bool
563
for _, f := range ls.Files {
564
t.Logf("file: %s", f)
565
if filepath.Base(f) == "incremental.txt" {
566
found = true
567
}
568
}
569
if !found {
570
t.Fatal("did not find incremental.txt")
571
}
572
})
573
}
574
return testCtx
575
}).
576
Feature()
577
578
testEnv.Test(t, f)
579
}
580
581
// checkPrebuildLogExist checks the prebuild log message exists
582
func checkPrebuildLogExist(t *testing.T, cfg *envconf.Config, rsa *integration.RpcClient, ws *integration.LaunchWorkspaceDirectlyResult, wsRoot string) {
583
// since the message '🍊 This task ran as a workspace prebuild' is generated by
584
// a prebuild workspace supervisor, so we add a retry mechanism to make sure that we
585
// won't check the message too earlier before the supervisor generated it.
586
var (
587
err error
588
grepResp agent.ExecResponse
589
checkPrebuildLog bool
590
)
591
err = rsa.Call("WorkspaceAgent.Exec", &agent.ExecRequest{
592
Dir: prebuildLogPath,
593
Command: "bash",
594
Args: []string{
595
"-c",
596
fmt.Sprintf("grep -r %s *", prebuildLog),
597
},
598
}, &grepResp)
599
if err == nil && grepResp.ExitCode == 0 && strings.Trim(grepResp.Stdout, " \t\n") != "" {
600
checkPrebuildLog = true
601
}
602
if checkPrebuildLog {
603
return
604
}
605
606
t.Logf("cannot found the prebuild message %s in %s, err:%v, exitCode:%d, stdout:%s, stderr:%s", prebuildLog, prebuildLogPath, err, grepResp.ExitCode, grepResp.Stdout, grepResp.Stderr)
607
608
// somehow, the prebuild log message '🍊 This task ran as a workspace prebuild' does not exists
609
// we fall back to check the init task message within the /workspace/.gitpod/prebuild-log-* or not
610
var grepResp1 agent.ExecResponse
611
var checkInitTaskMsg bool
612
err = rsa.Call("WorkspaceAgent.Exec", &agent.ExecRequest{
613
Dir: prebuildLogPath,
614
Command: "bash",
615
Args: []string{
616
"-c",
617
fmt.Sprintf("grep %q *", initTask),
618
},
619
}, &grepResp1)
620
if err == nil && grepResp1.ExitCode == 0 && strings.Trim(grepResp1.Stdout, " \t\n") != "" {
621
checkInitTaskMsg = true
622
}
623
if checkInitTaskMsg {
624
return
625
}
626
627
t.Logf("cannot found the init task message %s in %s, err:%v, exitCode:%d, stdout:%s", initTask, prebuildLogPath, err, grepResp.ExitCode, grepResp.Stdout)
628
629
// somehow, the init task message does not exist within the /workspace/.gitpod/prebuild-log-*
630
// we fall back to check the file exists or not
631
var ls agent.ListDirResponse
632
err = rsa.Call("WorkspaceAgent.ListDir", &agent.ListDirRequest{
633
Dir: wsRoot,
634
}, &ls)
635
if err != nil {
636
t.Fatal(err)
637
}
638
639
var found bool
640
for _, f := range ls.Files {
641
if filepath.Base(f) == "someFile" {
642
found = true
643
break
644
}
645
}
646
if found {
647
return
648
}
649
t.Fatal("did not find someFile from previous workspace instance")
650
}
651
652
// checkFolderPermission checks the folder UID and GID is gitpod
653
func checkFolderPermission(t *testing.T, rsa *integration.RpcClient, workspace string) {
654
var uid agent.ExecResponse
655
err := rsa.Call("WorkspaceAgent.Exec", &agent.ExecRequest{
656
Command: "stat",
657
Args: []string{"--format", "%U", workspace},
658
}, &uid)
659
if err != nil || uid.ExitCode != 0 || strings.Trim(uid.Stdout, " \t\n") != "gitpod" {
660
t.Fatalf("folder %s UID %s is incorrect, err:%v, exitCode:%d", workspace, uid.Stdout, err, uid.ExitCode)
661
}
662
663
var gid agent.ExecResponse
664
err = rsa.Call("WorkspaceAgent.Exec", &agent.ExecRequest{
665
Command: "stat",
666
Args: []string{"--format", "%G", workspace},
667
}, &gid)
668
if err != nil || uid.ExitCode != 0 || strings.Trim(gid.Stdout, " \t\n") != "gitpod" {
669
t.Fatalf("folder %s GID %s is incorrect, err:%v, exitCode:%d", workspace, gid.Stdout, err, uid.ExitCode)
670
}
671
}
672
673
// checkGitFolderPermission checks the files/folders UID and GID under .git/ is gitpod
674
func checkGitFolderPermission(t *testing.T, rsa *integration.RpcClient, workspaceRoot string) {
675
var findUserResp agent.ExecResponse
676
var gitDir string = fmt.Sprintf("%s/%s", workspaceRoot, ".git")
677
678
err := rsa.Call("WorkspaceAgent.Exec", &agent.ExecRequest{
679
Dir: gitDir,
680
Command: "find",
681
Args: []string{"!", "-user", "gitpod"},
682
}, &findUserResp)
683
if err != nil || findUserResp.ExitCode != 0 || strings.Trim(findUserResp.Stdout, " \t\n") != "" {
684
t.Fatalf("incorrect UID under %s folder, err:%v, exitCode:%d, stdout:%s", gitDir, err, findUserResp.ExitCode, findUserResp.Stdout)
685
}
686
687
var findGroupResp agent.ExecResponse
688
err = rsa.Call("WorkspaceAgent.Exec", &agent.ExecRequest{
689
Dir: gitDir,
690
Command: "find",
691
Args: []string{"!", "-group", "gitpod"},
692
}, &findGroupResp)
693
if err != nil || findGroupResp.ExitCode != 0 || strings.Trim(findGroupResp.Stdout, " \t\n") != "" {
694
t.Fatalf("incorrect GID under %s folder, err:%v, exitCode:%d, stdout:%s", gitDir, err, findGroupResp.ExitCode, findGroupResp.Stdout)
695
}
696
}
697
698
func checkPrebuildLogUploaded(t *testing.T, ctx context.Context, api *integration.ComponentAPI, ws *integration.LaunchWorkspaceDirectlyResult) {
699
cs, err := api.ContentService()
700
if err != nil {
701
t.Fatal(err)
702
}
703
resp, err := cs.ListLogs(ctx, &csapi.ListLogsRequest{
704
WorkspaceId: ws.LastStatus.Metadata.MetaId,
705
InstanceId: ws.Req.Id,
706
OwnerId: ws.LastStatus.Metadata.Owner,
707
})
708
if err != nil {
709
t.Fatal(err)
710
}
711
if len(resp.TaskId) == 0 {
712
t.Fatal("no logs found")
713
}
714
t.Logf("found logs (task ids: %v)", resp.TaskId)
715
}
716
717
func findSnapshotFromStoppedWs(t *testing.T, ctx context.Context, lastStatus *wsmanapi.WorkspaceStatus) (string, *wsmanapi.VolumeSnapshotInfo, error) {
718
if lastStatus == nil {
719
return "", nil, fmt.Errorf("did not get last workspace status")
720
}
721
if lastStatus.Phase != wsmanapi.WorkspacePhase_STOPPED {
722
return "", nil, fmt.Errorf("workspace is not stopped: %s", lastStatus.Phase)
723
}
724
if lastStatus.Conditions == nil {
725
return "", nil, nil
726
}
727
if lastStatus.Conditions.HeadlessTaskFailed != "" {
728
return "", nil, errors.New("unexpected HeadlessTaskFailed condition")
729
}
730
return lastStatus.Conditions.Snapshot, lastStatus.Conditions.VolumeSnapshot, nil
731
}
732
733
func stopWorkspace(t *testing.T, cfg *envconf.Config, StopWorkspaceFunc integration.StopWorkspaceFunc) error {
734
sctx, scancel := context.WithTimeout(context.Background(), 5*time.Minute)
735
defer scancel()
736
737
sapi := integration.NewComponentAPI(sctx, cfg.Namespace(), kubeconfig, cfg.Client())
738
defer sapi.Done(t)
739
740
_, err := StopWorkspaceFunc(true, sapi)
741
return err
742
}
743
744