diff --git a/test/tests/components/ws-manager/prebuild_test.go b/test/tests/components/ws-manager/prebuild_test.go index a5e1c9102b130c..317653abe414ec 100644 --- a/test/tests/components/ws-manager/prebuild_test.go +++ b/test/tests/components/ws-manager/prebuild_test.go @@ -7,6 +7,8 @@ package wsmanager import ( "context" "encoding/json" + "fmt" + "strings" "testing" "time" @@ -15,6 +17,7 @@ import ( csapi "github.com/gitpod-io/gitpod/content-service/api" gitpod "github.com/gitpod-io/gitpod/gitpod-protocol" + agent "github.com/gitpod-io/gitpod/test/pkg/agent/workspace/api" "github.com/gitpod-io/gitpod/test/pkg/integration" wsmanapi "github.com/gitpod-io/gitpod/ws-manager/api" ) @@ -171,3 +174,173 @@ func TestPrebuildWorkspaceTaskFail(t *testing.T) { testEnv.Test(t, f) } + +const ( + prebuildLogPath string = "/workspace/.gitpod" + prebuildLog string = "'🤙 This task ran as a workspace prebuild'" +) + +func TestOpenWorkspaceFromPrebuild(t *testing.T) { + f := features.New("prebuild"). + WithLabel("component", "ws-manager"). + Assess("it should open workspace from prebuild successfully", func(_ context.Context, t *testing.T, cfg *envconf.Config) context.Context { + tests := []struct { + Name string + ContextURL string + WorkspaceRoot string + CheckoutLocation string + FF []wsmanapi.WorkspaceFeatureFlag + }{ + { + Name: "classic", + ContextURL: "https://github.com/gitpod-io/empty", + CheckoutLocation: "empty", + WorkspaceRoot: "/workspace/empty", + }, + { + Name: "pvc", + ContextURL: "https://github.com/gitpod-io/empty", + CheckoutLocation: "empty", + WorkspaceRoot: "/workspace/empty", + FF: []wsmanapi.WorkspaceFeatureFlag{wsmanapi.WorkspaceFeatureFlag_PERSISTENT_VOLUME_CLAIM}, + }, + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(10*len(tests))*time.Minute) + defer cancel() + + for _, test := range tests { + t.Run(test.Name, func(t *testing.T) { + api := integration.NewComponentAPI(ctx, cfg.Namespace(), kubeconfig, cfg.Client()) + t.Cleanup(func() { + api.Done(t) + }) + + // create a prebuild + _, prebuildStopWs, err := integration.LaunchWorkspaceDirectly(t, ctx, api, integration.WithRequestModifier(func(req *wsmanapi.StartWorkspaceRequest) error { + req.Type = wsmanapi.WorkspaceType_PREBUILD + req.Spec.Envvars = append(req.Spec.Envvars, &wsmanapi.EnvironmentVariable{ + Name: "GITPOD_TASKS", + Value: `[{ "init": "echo \"some output\" > someFile; sleep 60; exit 0;" }]`, + }) + req.Spec.FeatureFlags = test.FF + req.Spec.Initializer = &csapi.WorkspaceInitializer{ + Spec: &csapi.WorkspaceInitializer_Git{ + Git: &csapi.GitInitializer{ + RemoteUri: test.ContextURL, + TargetMode: csapi.CloneTargetMode_REMOTE_BRANCH, + CloneTaget: "main", + CheckoutLocation: test.CheckoutLocation, + Config: &csapi.GitConfig{}, + }, + }, + } + req.Spec.WorkspaceLocation = test.CheckoutLocation + return nil + })) + if err != nil { + t.Fatalf("cannot launch a workspace: %q", err) + } + + prebuildLastStatus, err := prebuildStopWs(true, api) + if err != nil { + t.Errorf("cannot stop workspace: %q", err) + } + + var ( + prebuildSnapshot string + fromVolumeSnapshot bool + volumeSnapshotInfo *wsmanapi.VolumeSnapshotInfo + ) + if prebuildLastStatus != nil && prebuildLastStatus.Conditions != nil { + if prebuildLastStatus.Conditions.Snapshot == "" { + t.Fatal("should have snapshot information") + } + prebuildSnapshot = prebuildLastStatus.Conditions.Snapshot + + if prebuildLastStatus.Conditions.VolumeSnapshot != nil && + prebuildLastStatus.Conditions.VolumeSnapshot.VolumeSnapshotName != "" && + prebuildLastStatus.Conditions.VolumeSnapshot.VolumeSnapshotHandle != "" { + fromVolumeSnapshot = true + volumeSnapshotInfo = prebuildLastStatus.Conditions.VolumeSnapshot + } + } + + // launch the workspace from prebuild + ws, stopWs, err := integration.LaunchWorkspaceDirectly(t, ctx, api, integration.WithRequestModifier(func(req *wsmanapi.StartWorkspaceRequest) error { + req.Spec.FeatureFlags = test.FF + req.Spec.Initializer = &csapi.WorkspaceInitializer{ + Spec: &csapi.WorkspaceInitializer_Prebuild{ + Prebuild: &csapi.PrebuildInitializer{ + Prebuild: &csapi.SnapshotInitializer{Snapshot: prebuildSnapshot, FromVolumeSnapshot: fromVolumeSnapshot}, + Git: []*csapi.GitInitializer{ + { + RemoteUri: test.ContextURL, + TargetMode: csapi.CloneTargetMode_REMOTE_BRANCH, + CloneTaget: "main", + CheckoutLocation: test.CheckoutLocation, + Config: &csapi.GitConfig{}, + }, + }, + }, + }, + } + req.Spec.VolumeSnapshot = volumeSnapshotInfo + req.Spec.WorkspaceLocation = test.CheckoutLocation + return nil + })) + if err != nil { + t.Fatalf("cannot launch a workspace: %q", err) + } + + defer func() { + sctx, scancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer scancel() + + sapi := integration.NewComponentAPI(sctx, cfg.Namespace(), kubeconfig, cfg.Client()) + defer sapi.Done(t) + + _, err = stopWs(true, sapi) + if err != nil { + t.Errorf("cannot stop workspace: %q", err) + } + }() + + rsa, closer, err := integration.Instrument(integration.ComponentWorkspace, "workspace", cfg.Namespace(), kubeconfig, cfg.Client(), integration.WithInstanceID(ws.Req.Id)) + if err != nil { + t.Error(err) + } + integration.DeferCloser(t, closer) + + var resp agent.ExecResponse + var checkPrebuildSuccess bool + for i := 0; i < 10; i++ { + err = rsa.Call("WorkspaceAgent.Exec", &agent.ExecRequest{ + Dir: prebuildLogPath, + Command: "bash", + Args: []string{ + "-c", + fmt.Sprintf("grep %s *", prebuildLog), + }, + }, &resp) + if err == nil && resp.ExitCode == 0 && strings.Trim(resp.Stdout, " \t\n") != "" { + checkPrebuildSuccess = true + break + } + + // wait 3 seconds and check + time.Sleep(3 * time.Second) + } + rsa.Close() + + if !checkPrebuildSuccess { + t.Fatalf("cannot found the prebuild message %s in %s, err:%v, exitCode:%d, stdout:%s", prebuildLog, prebuildLogPath, err, resp.ExitCode, resp.Stdout) + } + }) + } + return ctx + }). + Feature() + + testEnv.Test(t, f) +}