diff --git a/cmd/demo/exec.go b/cmd/demo/exec.go index b0d9510c..1cda6d0e 100644 --- a/cmd/demo/exec.go +++ b/cmd/demo/exec.go @@ -33,7 +33,10 @@ func demoClusterExec(ctx context.Context, args []string, cmdCtx cmdCore.CommandC } func execute(ctx context.Context, cli docker.Docker, args []string) error { - c := docker.GetSandbox(ctx, cli) + c, err := docker.GetSandbox(ctx, cli) + if err != nil { + return err + } if c != nil { exec, err := docker.ExecCommend(ctx, cli, c.ID, args) if err != nil { diff --git a/cmd/demo/start.go b/cmd/demo/start.go index 893bdce1..ceff28fe 100644 --- a/cmd/demo/start.go +++ b/cmd/demo/start.go @@ -10,7 +10,7 @@ import ( "time" "github.com/flyteorg/flytectl/clierrors" - "github.com/flyteorg/flytectl/pkg/githubutil" + "github.com/flyteorg/flytectl/pkg/github" "github.com/avast/retry-go" "github.com/olekukonko/tablewriter" @@ -136,7 +136,9 @@ func startDemoCluster(ctx context.Context, args []string, cmdCtx cmdCore.Command return err } - reader, err := startDemo(ctx, cli, os.Stdin) + ghRepo := github.GetGHRepoService() + + reader, err := startDemo(ctx, cli, ghRepo, os.Stdin) if err != nil { return err } @@ -178,7 +180,7 @@ func updateLocalKubeContext() error { return k8sCtxMgr.CopyContext(srcConfigAccess, demoDockerContext, demoContextName) } -func startDemo(ctx context.Context, cli docker.Docker, reader io.Reader) (*bufio.Scanner, error) { +func startDemo(ctx context.Context, cli docker.Docker, g github.GHRepoService, reader io.Reader) (*bufio.Scanner, error) { fmt.Printf("%v Bootstrapping a brand new flyte cluster... %v %v\n", emoji.FactoryWorker, emoji.Hammer, emoji.Wrench) if err := docker.RemoveSandbox(ctx, cli, reader); err != nil { @@ -211,7 +213,7 @@ func startDemo(ctx context.Context, cli docker.Docker, reader io.Reader) (*bufio } demoImage := sandboxConfig.DefaultConfig.Image if len(demoImage) == 0 { - image, version, err := githubutil.GetFullyQualifiedImageName("sha", sandboxConfig.DefaultConfig.Version, demoImageName, sandboxConfig.DefaultConfig.Prerelease) + image, version, err := github.GetFullyQualifiedImageName("sha", sandboxConfig.DefaultConfig.Version, demoImageName, sandboxConfig.DefaultConfig.Prerelease, g) if err != nil { return nil, err } diff --git a/cmd/demo/start_test.go b/cmd/demo/start_test.go index 70ab2cb7..11ebacc7 100644 --- a/cmd/demo/start_test.go +++ b/cmd/demo/start_test.go @@ -6,26 +6,23 @@ import ( "io" "io/ioutil" "os" - "path/filepath" "strings" "testing" - "github.com/flyteorg/flyteidl/clients/go/admin" - - "github.com/flyteorg/flytectl/pkg/githubutil" - - "github.com/flyteorg/flytectl/pkg/k8s" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/mount" sandboxConfig "github.com/flyteorg/flytectl/cmd/config/subcommand/sandbox" cmdCore "github.com/flyteorg/flytectl/cmd/core" "github.com/flyteorg/flytectl/pkg/docker" "github.com/flyteorg/flytectl/pkg/docker/mocks" f "github.com/flyteorg/flytectl/pkg/filesystemutils" + ghMocks "github.com/flyteorg/flytectl/pkg/github/mocks" + "github.com/flyteorg/flytectl/pkg/k8s" k8sMocks "github.com/flyteorg/flytectl/pkg/k8s/mocks" "github.com/flyteorg/flytectl/pkg/util" + "github.com/flyteorg/flyteidl/clients/go/admin" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/google/go-github/v42/github" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" corev1 "k8s.io/api/core/v1" @@ -64,6 +61,12 @@ users: provideClusterInfo: true ` +var ( + githubMock *ghMocks.GHRepoService + ctx context.Context + mockDocker *mocks.Docker +) + var fakeNode = &corev1.Node{ Spec: corev1.NodeSpec{ Taints: []corev1.Taint{}, @@ -77,8 +80,22 @@ var fakePod = corev1.Pod{ }, } +func demoSetup() { + ctx = context.Background() + mockDocker = &mocks.Docker{} + errCh := make(chan error) + sandboxConfig.DefaultConfig.Version = "v0.19.1" + bodyStatus := make(chan container.ContainerWaitOKBody) + githubMock = &ghMocks.GHRepoService{} + sandboxConfig.DefaultConfig.Image = "dummyimage" + mockDocker.OnContainerCreateMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(container.ContainerCreateCreatedBody{ + ID: "Hello", + }, nil) + + mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) +} + func TestStartDemoFunc(t *testing.T) { - p1, p2, _ := docker.GetDemoPorts() assert.Nil(t, util.SetupFlyteDir()) assert.Nil(t, os.MkdirAll(f.FilePathJoin(f.UserHomeDir(), ".flyte", "k3s"), os.ModePerm)) assert.Nil(t, ioutil.WriteFile(docker.Kubeconfig, []byte(content), os.ModePerm)) @@ -86,58 +103,21 @@ func TestStartDemoFunc(t *testing.T) { fakePod.SetName("flyte") t.Run("Successfully run demo cluster", func(t *testing.T) { - ctx := context.Background() - mockDocker := &mocks.Docker{} - errCh := make(chan error) - sandboxConfig.DefaultConfig.Version = "v0.19.1" - bodyStatus := make(chan container.ContainerWaitOKBody) - image, _, err := githubutil.GetFullyQualifiedImageName("sha", sandboxConfig.DefaultConfig.Version, demoImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, os.Stdin) + _, err := startDemo(ctx, mockDocker, githubMock, os.Stdin) assert.Nil(t, err) }) t.Run("Successfully exit when demo cluster exist", func(t *testing.T) { - ctx := context.Background() - mockDocker := &mocks.Docker{} - errCh := make(chan error) - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{ { ID: docker.FlyteSandboxClusterName, @@ -147,46 +127,23 @@ func TestStartDemoFunc(t *testing.T) { }, }, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - reader, err := startDemo(ctx, mockDocker, strings.NewReader("n")) + reader, err := startDemo(ctx, mockDocker, githubMock, strings.NewReader("n")) assert.Nil(t, err) assert.Nil(t, reader) }) t.Run("Successfully run demo cluster with source code", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} sandboxConfig.DefaultConfig.Source = f.UserHomeDir() sandboxConfig.DefaultConfig.Version = "" - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, @@ -194,41 +151,15 @@ func TestStartDemoFunc(t *testing.T) { Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, os.Stdin) + _, err := startDemo(ctx, mockDocker, githubMock, os.Stdin) assert.Nil(t, err) }) t.Run("Successfully run demo cluster with abs path of source code", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} sandboxConfig.DefaultConfig.Source = "../" sandboxConfig.DefaultConfig.Version = "" - absPath, err := filepath.Abs(sandboxConfig.DefaultConfig.Source) - assert.Nil(t, err) - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: absPath, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, @@ -236,35 +167,13 @@ func TestStartDemoFunc(t *testing.T) { Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, os.Stdin) + _, err := startDemo(ctx, mockDocker, githubMock, os.Stdin) assert.Nil(t, err) }) t.Run("Successfully run demo cluster with specific version", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Version = "v0.18.0" - sandboxConfig.DefaultConfig.Source = "" - - image, _, err := githubutil.GetFullyQualifiedImageName("sha", sandboxConfig.DefaultConfig.Version, demoImageName, false) - assert.Nil(t, err) - volumes := docker.Volumes - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, @@ -272,111 +181,42 @@ func TestStartDemoFunc(t *testing.T) { Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, os.Stdin) + sandboxConfig.DefaultConfig.Image = "" + tag := "v0.15.0" + githubMock.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&github.RepositoryRelease{ + TagName: &tag, + }, nil, nil) + + githubMock.OnGetCommitSHA1Match(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return("dummySha", nil, nil) + _, err := startDemo(ctx, mockDocker, githubMock, os.Stdin) assert.Nil(t, err) }) t.Run("Failed run demo cluster with wrong version", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Version = "v0.1444.0" - sandboxConfig.DefaultConfig.Source = "" - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - volumes := docker.Volumes - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) - mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ - ShowStderr: true, - ShowStdout: true, - Timestamps: true, - Follow: true, - }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, os.Stdin) + sandboxConfig.DefaultConfig.Image = "" + githubMock.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("non-existent-tag")) + _, err := startDemo(ctx, mockDocker, githubMock, os.Stdin) assert.NotNil(t, err) + assert.Equal(t, "non-existent-tag", err.Error()) }) t.Run("Error in pulling image", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - sandboxConfig.DefaultConfig.Source = f.UserHomeDir() - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) - mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, fmt.Errorf("error")) - mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ - ShowStderr: true, - ShowStdout: true, - Timestamps: true, - Follow: true, - }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, os.Stdin) + mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, fmt.Errorf("failed to pull")) + sandboxConfig.DefaultConfig.Image = "" + tag := "v0.15.0" + githubMock.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&github.RepositoryRelease{ + TagName: &tag, + }, nil, nil) + + githubMock.OnGetCommitSHA1Match(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return("dummySha", nil, nil) + _, err := startDemo(ctx, mockDocker, githubMock, os.Stdin) assert.NotNil(t, err) + assert.Equal(t, "failed to pull", err.Error()) }) t.Run("Error in removing existing cluster", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Source = f.UserHomeDir() - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{ { ID: docker.FlyteSandboxClusterName, @@ -386,136 +226,53 @@ func TestStartDemoFunc(t *testing.T) { }, }, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ - ShowStderr: true, - ShowStdout: true, - Timestamps: true, - Follow: true, - }).Return(nil, nil) - mockDocker.OnContainerRemove(ctx, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(fmt.Errorf("error")) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, strings.NewReader("y")) + mockDocker.OnContainerRemove(ctx, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(fmt.Errorf("failed to remove container")) + _, err := startDemo(ctx, mockDocker, githubMock, strings.NewReader("y")) assert.NotNil(t, err) + assert.Equal(t, "failed to remove container", err.Error()) }) t.Run("Error in start container", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Source = "" - sandboxConfig.DefaultConfig.Version = "" - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, fmt.Errorf("error")) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(fmt.Errorf("error")) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ - ShowStderr: true, - ShowStdout: true, - Timestamps: true, - Follow: true, - }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, os.Stdin) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(fmt.Errorf("failed to run container")) + _, err := startDemo(ctx, mockDocker, githubMock, os.Stdin) assert.NotNil(t, err) + assert.Equal(t, "failed to run container", err.Error()) }) t.Run("Error in reading logs", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Source = f.UserHomeDir() - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, - }).Return(nil, fmt.Errorf("error")) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, os.Stdin) + }).Return(nil, fmt.Errorf("failed to get container logs")) + _, err := startDemo(ctx, mockDocker, githubMock, os.Stdin) assert.NotNil(t, err) + assert.Equal(t, "failed to get container logs", err.Error()) }) t.Run("Error in list container", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Source = f.UserHomeDir() - sandboxConfig.DefaultConfig.Version = "" - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) - mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, fmt.Errorf("error")) + demoSetup() + mockDocker.OnContainerListMatch(mock.Anything, mock.Anything).Return([]types.Container{}, fmt.Errorf("failed to list containers")) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startDemo(ctx, mockDocker, os.Stdin) - assert.Nil(t, err) + _, err := startDemo(ctx, mockDocker, githubMock, os.Stdin) + assert.NotNil(t, err) + assert.Equal(t, "failed to list containers", err.Error()) }) t.Run("Successfully run demo cluster command", func(t *testing.T) { mockOutStream := new(io.Writer) - ctx := context.Background() cmdCtx := cmdCore.NewCommandContext(admin.InitializeMockClientset(), *mockOutStream) - mockDocker := &mocks.Docker{} - errCh := make(chan error) client := testclient.NewSimpleClientset() k8s.Client = client _, err := client.CoreV1().Pods("flyte").Create(ctx, &fakePod, v1.CreateOptions{}) @@ -527,24 +284,11 @@ func TestStartDemoFunc(t *testing.T) { if err != nil { t.Error(err) } - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + demoSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) - mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnImagePullMatch(mock.Anything, mock.Anything, mock.Anything).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + stringReader := strings.NewReader(docker.SuccessMessage) reader := ioutil.NopCloser(stringReader) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ @@ -553,7 +297,6 @@ func TestStartDemoFunc(t *testing.T) { Timestamps: true, Follow: true, }).Return(reader, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) mockK8sContextMgr := &k8sMocks.ContextOps{} docker.Client = mockDocker sandboxConfig.DefaultConfig.Source = "" @@ -565,40 +308,19 @@ func TestStartDemoFunc(t *testing.T) { }) t.Run("Error in running demo cluster command", func(t *testing.T) { mockOutStream := new(io.Writer) - ctx := context.Background() cmdCtx := cmdCore.NewCommandContext(admin.InitializeMockClientset(), *mockOutStream) - mockDocker := &mocks.Docker{} - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(fmt.Errorf("error")) - mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, fmt.Errorf("error")) + demoSetup() + docker.Client = mockDocker + mockDocker.OnContainerListMatch(mock.Anything, mock.Anything).Return([]types.Container{}, fmt.Errorf("failed to list containers")) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - stringReader := strings.NewReader(docker.SuccessMessage) - reader := ioutil.NopCloser(stringReader) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, - }).Return(reader, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - docker.Client = mockDocker - sandboxConfig.DefaultConfig.Source = "" - err = startDemoCluster(ctx, []string{}, cmdCtx) + }).Return(nil, nil) + err := startDemoCluster(ctx, []string{}, cmdCtx) assert.NotNil(t, err) }) } @@ -702,30 +424,3 @@ func TestGetNodeTaintStatus(t *testing.T) { assert.Equal(t, true, c) }) } - -func TestGetDemoImage(t *testing.T) { - t.Run("Get Latest demo cluster", func(t *testing.T) { - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "", demoImageName, false) - assert.Nil(t, err) - assert.Equal(t, true, strings.HasPrefix(image, "cr.flyte.org/flyteorg/flyte-sandbox-lite:sha-")) - }) - - t.Run("Get demo image with version ", func(t *testing.T) { - image, _, err := githubutil.GetFullyQualifiedImageName("sha", "v0.14.0", demoImageName, false) - assert.Nil(t, err) - assert.Equal(t, true, strings.HasPrefix(image, demoImageName)) - }) - t.Run("Get demo image with wrong version ", func(t *testing.T) { - _, _, err := githubutil.GetFullyQualifiedImageName("sha", "v100.1.0", demoImageName, false) - assert.NotNil(t, err) - }) - t.Run("Get demo image with wrong version ", func(t *testing.T) { - _, _, err := githubutil.GetFullyQualifiedImageName("sha", "aaaaaa", demoImageName, false) - assert.NotNil(t, err) - }) - t.Run("Get demo image with version that is not supported", func(t *testing.T) { - _, _, err := githubutil.GetFullyQualifiedImageName("sha", "v0.10.0", demoImageName, false) - assert.NotNil(t, err) - }) - -} diff --git a/cmd/demo/status.go b/cmd/demo/status.go index 67a7767a..942b561d 100644 --- a/cmd/demo/status.go +++ b/cmd/demo/status.go @@ -32,7 +32,10 @@ func demoClusterStatus(ctx context.Context, args []string, cmdCtx cmdCore.Comman } func printStatus(ctx context.Context, cli docker.Docker) error { - c := docker.GetSandbox(ctx, cli) + c, err := docker.GetSandbox(ctx, cli) + if err != nil { + return err + } if c == nil { fmt.Printf("%v no demo cluster found \n", emoji.StopSign) return nil diff --git a/cmd/demo/teardown.go b/cmd/demo/teardown.go index 1308b10b..bd98b22e 100644 --- a/cmd/demo/teardown.go +++ b/cmd/demo/teardown.go @@ -38,7 +38,10 @@ func teardownDemoCluster(ctx context.Context, args []string, cmdCtx cmdCore.Comm } func tearDownDemo(ctx context.Context, cli docker.Docker) error { - c := docker.GetSandbox(ctx, cli) + c, err := docker.GetSandbox(ctx, cli) + if err != nil { + return err + } if c != nil { if err := cli.ContainerRemove(context.Background(), c.ID, types.ContainerRemoveOptions{ Force: true, diff --git a/cmd/register/examples.go b/cmd/register/examples.go index eb3feff8..04d34be9 100644 --- a/cmd/register/examples.go +++ b/cmd/register/examples.go @@ -5,13 +5,12 @@ import ( "fmt" "github.com/flyteorg/flytectl/cmd/config" - + rconfig "github.com/flyteorg/flytectl/cmd/config/subcommand/register" + cmdCore "github.com/flyteorg/flytectl/cmd/core" + g "github.com/flyteorg/flytectl/pkg/github" "github.com/flyteorg/flytestdlib/logger" "github.com/google/go-github/v42/github" - - rconfig "github.com/flyteorg/flytectl/cmd/config/subcommand/register" - cmdCore "github.com/flyteorg/flytectl/cmd/core" ) const ( @@ -44,7 +43,8 @@ func registerExamplesFunc(ctx context.Context, args []string, cmdCtx cmdCore.Com // Deprecated checks for --k8Service deprecatedCheck(ctx, &rconfig.DefaultFilesConfig.K8sServiceAccount, rconfig.DefaultFilesConfig.K8ServiceAccount) - examples, tag, err := getAllExample(flytesnacks, rconfig.DefaultFilesConfig.Version) + ghRepo := g.GetGHRepoService() + examples, tag, err := getAllExample(flytesnacks, rconfig.DefaultFilesConfig.Version, ghRepo) if err != nil { return err } diff --git a/cmd/register/register_util.go b/cmd/register/register_util.go index 3d68cca6..90c18c74 100644 --- a/cmd/register/register_util.go +++ b/cmd/register/register_util.go @@ -22,7 +22,7 @@ import ( "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" - "github.com/flyteorg/flytectl/pkg/githubutil" + g "github.com/flyteorg/flytectl/pkg/github" "github.com/flyteorg/flytestdlib/contextutils" "github.com/flyteorg/flytestdlib/promutils" @@ -654,15 +654,15 @@ func filterExampleFromRelease(releases *github.RepositoryRelease) []*github.Rele return assets } -func getAllExample(repository, version string) ([]*github.ReleaseAsset, *github.RepositoryRelease, error) { +func getAllExample(repository, version string, repoService g.GHRepoService) ([]*github.ReleaseAsset, *github.RepositoryRelease, error) { if len(version) > 0 { - release, err := githubutil.CheckVersionExist(version, repository) + release, err := g.GetReleaseByTag(version, repository, repoService) if err != nil { return nil, nil, err } return filterExampleFromRelease(release), release, nil } - release, err := githubutil.GetLatestVersion(repository) + release, err := g.GetLatestRelease(repository, repoService) if err != nil { return nil, nil, err } diff --git a/cmd/register/register_util_test.go b/cmd/register/register_util_test.go index 8b614ed0..e1d30934 100644 --- a/cmd/register/register_util_test.go +++ b/cmd/register/register_util_test.go @@ -12,6 +12,7 @@ import ( "strings" "testing" + ghMocks "github.com/flyteorg/flytectl/pkg/github/mocks" "github.com/flyteorg/flyteidl/clients/go/admin/mocks" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/service" @@ -29,6 +30,7 @@ import ( rconfig "github.com/flyteorg/flytectl/cmd/config/subcommand/register" "github.com/flyteorg/flyteidl/gen/pb-go/flyteidl/admin" + "github.com/google/go-github/v42/github" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "google.golang.org/grpc/codes" @@ -434,15 +436,35 @@ func TestGetStorageClient(t *testing.T) { func TestGetAllFlytesnacksExample(t *testing.T) { t.Run("Failed to get manifest with wrong name", func(t *testing.T) { - _, _, err := getAllExample("no////ne", "") + mockGh := &ghMocks.GHRepoService{} + mockGh.OnGetLatestReleaseMatch(mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("failed")) + _, _, err := getAllExample("no////ne", "", mockGh) assert.NotNil(t, err) }) t.Run("Failed to get release", func(t *testing.T) { - _, _, err := getAllExample("homebrew-tap", "") + mockGh := &ghMocks.GHRepoService{} + tag := "v0.15.0" + sandboxManifest := "flyte_sandbox_manifest.tgz" + mockGh.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&github.RepositoryRelease{ + TagName: &tag, + Assets: []*github.ReleaseAsset{{ + Name: &sandboxManifest, + }}, + }, nil, fmt.Errorf("failed")) + _, _, err := getAllExample("homebrew-tap", "1.0", mockGh) assert.NotNil(t, err) }) t.Run("Successfully get examples", func(t *testing.T) { - assets, r, err := getAllExample("flytesnacks", "v0.2.175") + mockGh := &ghMocks.GHRepoService{} + tag := "v0.15.0" + sandboxManifest := "flyte_sandbox_manifest.tgz" + mockGh.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&github.RepositoryRelease{ + TagName: &tag, + Assets: []*github.ReleaseAsset{{ + Name: &sandboxManifest, + }}, + }, nil, nil) + assets, r, err := getAllExample("flytesnacks", tag, mockGh) assert.Nil(t, err) assert.Greater(t, len(*r.TagName), 0) assert.Greater(t, len(assets), 0) diff --git a/cmd/sandbox/exec.go b/cmd/sandbox/exec.go index 327d2e4f..0d45c235 100644 --- a/cmd/sandbox/exec.go +++ b/cmd/sandbox/exec.go @@ -33,7 +33,10 @@ func sandboxClusterExec(ctx context.Context, args []string, cmdCtx cmdCore.Comma } func execute(ctx context.Context, cli docker.Docker, args []string) error { - c := docker.GetSandbox(ctx, cli) + c, err := docker.GetSandbox(ctx, cli) + if err != nil { + return err + } if c != nil { exec, err := docker.ExecCommend(ctx, cli, c.ID, args) if err != nil { diff --git a/cmd/sandbox/start.go b/cmd/sandbox/start.go index c7afba96..9e9013b6 100644 --- a/cmd/sandbox/start.go +++ b/cmd/sandbox/start.go @@ -10,7 +10,7 @@ import ( "time" "github.com/flyteorg/flytectl/clierrors" - "github.com/flyteorg/flytectl/pkg/githubutil" + "github.com/flyteorg/flytectl/pkg/github" "github.com/avast/retry-go" "github.com/olekukonko/tablewriter" @@ -42,11 +42,13 @@ Starts the sandbox cluster without any source code: flytectl sandbox start Mounts your source code repository inside the sandbox: + :: flytectl sandbox start --source=$HOME/flyteorg/flytesnacks Runs a specific version of Flyte. Flytectl sandbox only supports Flyte version available in the Github release, https://github.com/flyteorg/flyte/tags. + :: flytectl sandbox start --version=v0.14.0 @@ -117,7 +119,9 @@ func startSandboxCluster(ctx context.Context, args []string, cmdCtx cmdCore.Comm return err } - reader, err := startSandbox(ctx, cli, os.Stdin) + ghRepo := github.GetGHRepoService() + + reader, err := startSandbox(ctx, cli, ghRepo, os.Stdin) if err != nil { return err } @@ -158,7 +162,7 @@ func updateLocalKubeContext() error { return k8sCtxMgr.CopyContext(srcConfigAccess, sandboxDockerContext, sandboxContextName) } -func startSandbox(ctx context.Context, cli docker.Docker, reader io.Reader) (*bufio.Scanner, error) { +func startSandbox(ctx context.Context, cli docker.Docker, g github.GHRepoService, reader io.Reader) (*bufio.Scanner, error) { fmt.Printf("%v Bootstrapping a brand new flyte cluster... %v %v\n", emoji.FactoryWorker, emoji.Hammer, emoji.Wrench) if err := docker.RemoveSandbox(ctx, cli, reader); err != nil { @@ -191,7 +195,7 @@ func startSandbox(ctx context.Context, cli docker.Docker, reader io.Reader) (*bu } sandboxImage := sandboxConfig.DefaultConfig.Image if len(sandboxImage) == 0 { - image, version, err := githubutil.GetFullyQualifiedImageName("dind", sandboxConfig.DefaultConfig.Version, sandboxImageName, sandboxConfig.DefaultConfig.Prerelease) + image, version, err := github.GetFullyQualifiedImageName("dind", sandboxConfig.DefaultConfig.Version, sandboxImageName, sandboxConfig.DefaultConfig.Prerelease, g) if err != nil { return nil, err } diff --git a/cmd/sandbox/start_test.go b/cmd/sandbox/start_test.go index fd6623c7..8e1f28c5 100644 --- a/cmd/sandbox/start_test.go +++ b/cmd/sandbox/start_test.go @@ -6,26 +6,24 @@ import ( "io" "io/ioutil" "os" - "path/filepath" "strings" "testing" - "github.com/flyteorg/flyteidl/clients/go/admin" - - "github.com/flyteorg/flytectl/pkg/githubutil" - - "github.com/flyteorg/flytectl/pkg/k8s" - - "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/mount" sandboxConfig "github.com/flyteorg/flytectl/cmd/config/subcommand/sandbox" cmdCore "github.com/flyteorg/flytectl/cmd/core" "github.com/flyteorg/flytectl/pkg/docker" "github.com/flyteorg/flytectl/pkg/docker/mocks" f "github.com/flyteorg/flytectl/pkg/filesystemutils" + ghutil "github.com/flyteorg/flytectl/pkg/github" + ghMocks "github.com/flyteorg/flytectl/pkg/github/mocks" + "github.com/flyteorg/flytectl/pkg/k8s" k8sMocks "github.com/flyteorg/flytectl/pkg/k8s/mocks" "github.com/flyteorg/flytectl/pkg/util" + "github.com/flyteorg/flyteidl/clients/go/admin" + + "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/container" + "github.com/google/go-github/v42/github" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" corev1 "k8s.io/api/core/v1" @@ -77,68 +75,50 @@ var fakePod = corev1.Pod{ }, } -func TestStartSandboxFunc(t *testing.T) { - p1, p2, _ := docker.GetSandboxPorts() +var ( + githubMock *ghMocks.GHRepoService + ctx context.Context + mockDocker *mocks.Docker +) + +func sandboxSetup() { + ctx = context.Background() + mockDocker = &mocks.Docker{} + errCh := make(chan error) + sandboxConfig.DefaultConfig.Version = "v0.19.1" + bodyStatus := make(chan container.ContainerWaitOKBody) + githubMock = &ghMocks.GHRepoService{} + sandboxConfig.DefaultConfig.Image = "dummyimage" + mockDocker.OnContainerCreateMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(container.ContainerCreateCreatedBody{ + ID: "Hello", + }, nil) + + mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) +} + +func TestStartFunc(t *testing.T) { assert.Nil(t, util.SetupFlyteDir()) assert.Nil(t, os.MkdirAll(f.FilePathJoin(f.UserHomeDir(), ".flyte", "k3s"), os.ModePerm)) assert.Nil(t, ioutil.WriteFile(docker.Kubeconfig, []byte(content), os.ModePerm)) - fakePod.SetName("flyte") fakePod.SetName("flyte") - t.Run("Successfully run sandbox cluster", func(t *testing.T) { - ctx := context.Background() - mockDocker := &mocks.Docker{} - errCh := make(chan error) - sandboxConfig.DefaultConfig.Version = "v0.19.1" - bodyStatus := make(chan container.ContainerWaitOKBody) - image, _, err := githubutil.GetFullyQualifiedImageName("dind", sandboxConfig.DefaultConfig.Version, sandboxImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + t.Run("Successfully run demo cluster", func(t *testing.T) { + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, os.Stdin) + _, err := startSandbox(ctx, mockDocker, githubMock, os.Stdin) assert.Nil(t, err) }) - t.Run("Successfully exit when sandbox cluster exist", func(t *testing.T) { - ctx := context.Background() - mockDocker := &mocks.Docker{} - errCh := make(chan error) - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + t.Run("Successfully exit when demo cluster exist", func(t *testing.T) { + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{ { ID: docker.FlyteSandboxClusterName, @@ -148,46 +128,23 @@ func TestStartSandboxFunc(t *testing.T) { }, }, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - reader, err := startSandbox(ctx, mockDocker, strings.NewReader("n")) + reader, err := startSandbox(ctx, mockDocker, githubMock, strings.NewReader("n")) assert.Nil(t, err) assert.Nil(t, reader) }) - t.Run("Successfully run sandbox cluster with source code", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} + t.Run("Successfully run demo cluster with source code", func(t *testing.T) { sandboxConfig.DefaultConfig.Source = f.UserHomeDir() sandboxConfig.DefaultConfig.Version = "" - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, @@ -195,41 +152,15 @@ func TestStartSandboxFunc(t *testing.T) { Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, os.Stdin) + _, err := startSandbox(ctx, mockDocker, githubMock, os.Stdin) assert.Nil(t, err) }) - t.Run("Successfully run sandbox cluster with abs path of source code", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} + t.Run("Successfully run demo cluster with abs path of source code", func(t *testing.T) { sandboxConfig.DefaultConfig.Source = "../" sandboxConfig.DefaultConfig.Version = "" - absPath, err := filepath.Abs(sandboxConfig.DefaultConfig.Source) - assert.Nil(t, err) - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: absPath, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, @@ -237,35 +168,13 @@ func TestStartSandboxFunc(t *testing.T) { Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, os.Stdin) + _, err := startSandbox(ctx, mockDocker, githubMock, os.Stdin) assert.Nil(t, err) }) - t.Run("Successfully run sandbox cluster with specific version", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Version = "v0.18.0" - sandboxConfig.DefaultConfig.Source = "" - - image, _, err := githubutil.GetFullyQualifiedImageName("dind", sandboxConfig.DefaultConfig.Version, sandboxImageName, false) - assert.Nil(t, err) - volumes := docker.Volumes - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + t.Run("Successfully run demo cluster with specific version", func(t *testing.T) { + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, @@ -273,111 +182,42 @@ func TestStartSandboxFunc(t *testing.T) { Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, os.Stdin) + sandboxConfig.DefaultConfig.Image = "" + tag := "v0.15.0" + githubMock.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&github.RepositoryRelease{ + TagName: &tag, + }, nil, nil) + + githubMock.OnGetCommitSHA1Match(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return("dummySha", nil, nil) + _, err := startSandbox(ctx, mockDocker, githubMock, os.Stdin) assert.Nil(t, err) }) - t.Run("Failed run sandbox cluster with wrong version", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Version = "v0.1444.0" - sandboxConfig.DefaultConfig.Source = "" - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - volumes := docker.Volumes - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + t.Run("Failed run demo cluster with wrong version", func(t *testing.T) { + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) - mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ - ShowStderr: true, - ShowStdout: true, - Timestamps: true, - Follow: true, - }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, os.Stdin) + sandboxConfig.DefaultConfig.Image = "" + githubMock.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("non-existent-tag")) + _, err := startSandbox(ctx, mockDocker, githubMock, os.Stdin) assert.NotNil(t, err) + assert.Equal(t, "non-existent-tag", err.Error()) }) t.Run("Error in pulling image", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - sandboxConfig.DefaultConfig.Source = f.UserHomeDir() - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) - mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, fmt.Errorf("error")) - mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ - ShowStderr: true, - ShowStdout: true, - Timestamps: true, - Follow: true, - }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, os.Stdin) + mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, fmt.Errorf("failed to pull")) + sandboxConfig.DefaultConfig.Image = "" + tag := "v0.15.0" + githubMock.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&github.RepositoryRelease{ + TagName: &tag, + }, nil, nil) + + githubMock.OnGetCommitSHA1Match(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return("dummySha", nil, nil) + _, err := startSandbox(ctx, mockDocker, githubMock, os.Stdin) assert.NotNil(t, err) + assert.Equal(t, "failed to pull", err.Error()) }) t.Run("Error in removing existing cluster", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Source = f.UserHomeDir() - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{ { ID: docker.FlyteSandboxClusterName, @@ -387,136 +227,53 @@ func TestStartSandboxFunc(t *testing.T) { }, }, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ - ShowStderr: true, - ShowStdout: true, - Timestamps: true, - Follow: true, - }).Return(nil, nil) - mockDocker.OnContainerRemove(ctx, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(fmt.Errorf("error")) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, strings.NewReader("y")) + mockDocker.OnContainerRemove(ctx, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(fmt.Errorf("failed to remove container")) + _, err := startSandbox(ctx, mockDocker, githubMock, strings.NewReader("y")) assert.NotNil(t, err) + assert.Equal(t, "failed to remove container", err.Error()) }) t.Run("Error in start container", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Source = "" - sandboxConfig.DefaultConfig.Version = "" - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, fmt.Errorf("error")) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(fmt.Errorf("error")) + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ - ShowStderr: true, - ShowStdout: true, - Timestamps: true, - Follow: true, - }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, os.Stdin) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(fmt.Errorf("failed to run container")) + _, err := startSandbox(ctx, mockDocker, githubMock, os.Stdin) assert.NotNil(t, err) + assert.Equal(t, "failed to run container", err.Error()) }) t.Run("Error in reading logs", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Source = f.UserHomeDir() - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, - }).Return(nil, fmt.Errorf("error")) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, os.Stdin) + }).Return(nil, fmt.Errorf("failed to get container logs")) + _, err := startSandbox(ctx, mockDocker, githubMock, os.Stdin) assert.NotNil(t, err) + assert.Equal(t, "failed to get container logs", err.Error()) }) t.Run("Error in list container", func(t *testing.T) { - ctx := context.Background() - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker := &mocks.Docker{} - sandboxConfig.DefaultConfig.Source = f.UserHomeDir() - sandboxConfig.DefaultConfig.Version = "" - volumes := docker.Volumes - volumes = append(volumes, mount.Mount{ - Type: mount.TypeBind, - Source: sandboxConfig.DefaultConfig.Source, - Target: docker.Source, - }) - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) - mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, fmt.Errorf("error")) + sandboxSetup() + mockDocker.OnContainerListMatch(mock.Anything, mock.Anything).Return([]types.Container{}, fmt.Errorf("failed to list containers")) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, }).Return(nil, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - _, err = startSandbox(ctx, mockDocker, os.Stdin) - assert.Nil(t, err) + _, err := startSandbox(ctx, mockDocker, githubMock, os.Stdin) + assert.NotNil(t, err) + assert.Equal(t, "failed to list containers", err.Error()) }) - t.Run("Successfully run sandbox cluster command", func(t *testing.T) { + t.Run("Successfully run demo cluster command", func(t *testing.T) { mockOutStream := new(io.Writer) - ctx := context.Background() cmdCtx := cmdCore.NewCommandContext(admin.InitializeMockClientset(), *mockOutStream) - mockDocker := &mocks.Docker{} - errCh := make(chan error) client := testclient.NewSimpleClientset() k8s.Client = client _, err := client.CoreV1().Pods("flyte").Create(ctx, &fakePod, v1.CreateOptions{}) @@ -528,24 +285,11 @@ func TestStartSandboxFunc(t *testing.T) { if err != nil { t.Error(err) } - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - bodyStatus := make(chan container.ContainerWaitOKBody) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + sandboxSetup() mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) - mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnImagePullMatch(mock.Anything, mock.Anything, mock.Anything).Return(os.Stdin, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + stringReader := strings.NewReader(docker.SuccessMessage) reader := ioutil.NopCloser(stringReader) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ @@ -554,52 +298,31 @@ func TestStartSandboxFunc(t *testing.T) { Timestamps: true, Follow: true, }).Return(reader, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) mockK8sContextMgr := &k8sMocks.ContextOps{} docker.Client = mockDocker sandboxConfig.DefaultConfig.Source = "" sandboxConfig.DefaultConfig.Version = "" k8s.ContextMgr = mockK8sContextMgr + ghutil.Client = githubMock mockK8sContextMgr.OnCopyContextMatch(mock.Anything, mock.Anything, mock.Anything).Return(nil) err = startSandboxCluster(ctx, []string{}, cmdCtx) assert.Nil(t, err) }) - t.Run("Error in running sandbox cluster command", func(t *testing.T) { + t.Run("Error in running demo cluster command", func(t *testing.T) { mockOutStream := new(io.Writer) - ctx := context.Background() cmdCtx := cmdCore.NewCommandContext(admin.InitializeMockClientset(), *mockOutStream) - mockDocker := &mocks.Docker{} - errCh := make(chan error) - bodyStatus := make(chan container.ContainerWaitOKBody) - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - mockDocker.OnContainerCreate(ctx, &container.Config{ - Env: docker.Environment, - Image: image, - Tty: false, - ExposedPorts: p1, - }, &container.HostConfig{ - Mounts: docker.Volumes, - PortBindings: p2, - Privileged: true, - }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ - ID: "Hello", - }, nil) - mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(fmt.Errorf("error")) - mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, fmt.Errorf("error")) + sandboxSetup() + docker.Client = mockDocker + mockDocker.OnContainerListMatch(mock.Anything, mock.Anything).Return([]types.Container{}, fmt.Errorf("failed to list containers")) mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - stringReader := strings.NewReader(docker.SuccessMessage) - reader := ioutil.NopCloser(stringReader) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, - }).Return(reader, nil) - mockDocker.OnContainerWaitMatch(ctx, mock.Anything, container.WaitConditionNotRunning).Return(bodyStatus, errCh) - docker.Client = mockDocker - sandboxConfig.DefaultConfig.Source = "" - err = startSandboxCluster(ctx, []string{}, cmdCtx) + }).Return(nil, nil) + err := startSandboxCluster(ctx, []string{}, cmdCtx) assert.NotNil(t, err) }) } @@ -703,30 +426,3 @@ func TestGetNodeTaintStatus(t *testing.T) { assert.Equal(t, true, c) }) } - -func TestGetSandboxImage(t *testing.T) { - t.Run("Get Latest sandbox", func(t *testing.T) { - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - assert.Equal(t, true, strings.HasPrefix(image, "cr.flyte.org/flyteorg/flyte-sandbox:dind-")) - }) - - t.Run("Get sandbox image with version ", func(t *testing.T) { - image, _, err := githubutil.GetFullyQualifiedImageName("dind", "v0.14.0", sandboxImageName, false) - assert.Nil(t, err) - assert.Equal(t, true, strings.HasPrefix(image, sandboxImageName)) - }) - t.Run("Get sandbox image with wrong version ", func(t *testing.T) { - _, _, err := githubutil.GetFullyQualifiedImageName("dind", "v100.1.0", sandboxImageName, false) - assert.NotNil(t, err) - }) - t.Run("Get sandbox image with wrong version ", func(t *testing.T) { - _, _, err := githubutil.GetFullyQualifiedImageName("dind", "aaaaaa", sandboxImageName, false) - assert.NotNil(t, err) - }) - t.Run("Get sandbox image with version that is not supported", func(t *testing.T) { - _, _, err := githubutil.GetFullyQualifiedImageName("dind", "v0.10.0", sandboxImageName, false) - assert.NotNil(t, err) - }) - -} diff --git a/cmd/sandbox/status.go b/cmd/sandbox/status.go index 49e5fb77..30160ef7 100644 --- a/cmd/sandbox/status.go +++ b/cmd/sandbox/status.go @@ -32,7 +32,10 @@ func sandboxClusterStatus(ctx context.Context, args []string, cmdCtx cmdCore.Com } func printStatus(ctx context.Context, cli docker.Docker) error { - c := docker.GetSandbox(ctx, cli) + c, err := docker.GetSandbox(ctx, cli) + if err != nil { + return err + } if c == nil { fmt.Printf("%v no Sandbox found \n", emoji.StopSign) return nil diff --git a/cmd/sandbox/teardown.go b/cmd/sandbox/teardown.go index 16ca11bf..9280e303 100644 --- a/cmd/sandbox/teardown.go +++ b/cmd/sandbox/teardown.go @@ -38,7 +38,10 @@ func teardownSandboxCluster(ctx context.Context, args []string, cmdCtx cmdCore.C } func tearDownSandbox(ctx context.Context, cli docker.Docker) error { - c := docker.GetSandbox(ctx, cli) + c, err := docker.GetSandbox(ctx, cli) + if err != nil { + return err + } if c != nil { if err := cli.ContainerRemove(context.Background(), c.ID, types.ContainerRemoveOptions{ Force: true, diff --git a/cmd/upgrade/upgrade.go b/cmd/upgrade/upgrade.go index eb1dde2b..f8c4099e 100644 --- a/cmd/upgrade/upgrade.go +++ b/cmd/upgrade/upgrade.go @@ -12,7 +12,7 @@ import ( stdlibversion "github.com/flyteorg/flytestdlib/version" - "github.com/flyteorg/flytectl/pkg/githubutil" + "github.com/flyteorg/flytectl/pkg/github" "github.com/flyteorg/flytestdlib/logger" "github.com/mouuff/go-rocket-update/pkg/updater" @@ -67,7 +67,7 @@ func selfUpgrade(ctx context.Context, args []string, cmdCtx cmdCore.CommandConte if args[0] == rollBackSubCommand && !isRollBackSupported(goos) { return nil } - ext, err := githubutil.FlytectlReleaseConfig.GetExecutable() + ext, err := github.FlytectlReleaseConfig.GetExecutable() if err != nil { return err } @@ -75,7 +75,7 @@ func selfUpgrade(ctx context.Context, args []string, cmdCtx cmdCore.CommandConte if _, err := os.Stat(backupBinary); err != nil { return errors.New("flytectl backup doesn't exist. Rollback is not possible") } - return githubutil.FlytectlReleaseConfig.Rollback() + return github.FlytectlReleaseConfig.Rollback() } if isSupported, err := isUpgradeSupported(goos); err != nil { @@ -84,7 +84,7 @@ func selfUpgrade(ctx context.Context, args []string, cmdCtx cmdCore.CommandConte return nil } - if message, err := upgrade(githubutil.FlytectlReleaseConfig); err != nil { + if message, err := upgrade(github.FlytectlReleaseConfig); err != nil { return err } else if len(message) > 0 { logger.Info(ctx, message) @@ -109,7 +109,7 @@ func upgrade(u *updater.Updater) (string, error) { } func isUpgradeSupported(goos platformutil.Platform) (bool, error) { - latest, err := githubutil.FlytectlReleaseConfig.GetLatestVersion() + latest, err := github.FlytectlReleaseConfig.GetLatestVersion() if err != nil { return false, err } @@ -121,7 +121,7 @@ func isUpgradeSupported(goos platformutil.Platform) (bool, error) { return false, nil } - message, err := githubutil.GetUpgradeMessage(latest, goos) + message, err := github.GetUpgradeMessage(latest, goos) if err != nil { return false, err } diff --git a/cmd/upgrade/upgrade_test.go b/cmd/upgrade/upgrade_test.go index 5d4ac283..7b5b211e 100644 --- a/cmd/upgrade/upgrade_test.go +++ b/cmd/upgrade/upgrade_test.go @@ -6,7 +6,7 @@ import ( "github.com/flyteorg/flytectl/cmd/testutils" - "github.com/flyteorg/flytectl/pkg/githubutil" + "github.com/flyteorg/flytectl/pkg/github" "github.com/flyteorg/flytectl/pkg/util" "github.com/flyteorg/flytectl/pkg/platformutil" @@ -48,9 +48,9 @@ func TestUpgradeCommand(t *testing.T) { func TestUpgrade(t *testing.T) { _ = util.WriteIntoFile([]byte("data"), tempExt) stdlibversion.Version = version - githubutil.FlytectlReleaseConfig.OverrideExecutable = tempExt + github.FlytectlReleaseConfig.OverrideExecutable = tempExt t.Run("Successful upgrade", func(t *testing.T) { - message, err := upgrade(githubutil.FlytectlReleaseConfig) + message, err := upgrade(github.FlytectlReleaseConfig) assert.Nil(t, err) assert.Contains(t, message, "Successfully updated to version") }) @@ -61,7 +61,7 @@ func TestCheckGoosForRollback(t *testing.T) { linux := platformutil.Linux windows := platformutil.Windows darwin := platformutil.Darwin - githubutil.FlytectlReleaseConfig.OverrideExecutable = tempExt + github.FlytectlReleaseConfig.OverrideExecutable = tempExt t.Run("checkGOOSForRollback on linux", func(t *testing.T) { assert.Equal(t, true, isRollBackSupported(linux)) assert.Equal(t, false, isRollBackSupported(windows)) @@ -71,7 +71,7 @@ func TestCheckGoosForRollback(t *testing.T) { func TestIsUpgradeable(t *testing.T) { stdlibversion.Version = version - githubutil.FlytectlReleaseConfig.OverrideExecutable = tempExt + github.FlytectlReleaseConfig.OverrideExecutable = tempExt linux := platformutil.Linux windows := platformutil.Windows darwin := platformutil.Darwin @@ -106,7 +106,7 @@ func TestIsUpgradeable(t *testing.T) { func TestSelfUpgrade(t *testing.T) { stdlibversion.Version = version - githubutil.FlytectlReleaseConfig.OverrideExecutable = tempExt + github.FlytectlReleaseConfig.OverrideExecutable = tempExt goos = platformutil.Linux t.Run("Successful upgrade", func(t *testing.T) { s := testutils.Setup() @@ -120,7 +120,7 @@ func TestSelfUpgrade(t *testing.T) { func TestSelfUpgradeError(t *testing.T) { stdlibversion.Version = version - githubutil.FlytectlReleaseConfig.OverrideExecutable = tempExt + github.FlytectlReleaseConfig.OverrideExecutable = tempExt goos = platformutil.Linux t.Run("Successful upgrade", func(t *testing.T) { s := testutils.Setup() @@ -135,7 +135,7 @@ func TestSelfUpgradeError(t *testing.T) { func TestSelfUpgradeRollback(t *testing.T) { stdlibversion.Version = version - githubutil.FlytectlReleaseConfig.OverrideExecutable = tempExt + github.FlytectlReleaseConfig.OverrideExecutable = tempExt goos = platformutil.Linux t.Run("Successful rollback", func(t *testing.T) { s := testutils.Setup() @@ -171,7 +171,7 @@ func TestSelfUpgradeRollback(t *testing.T) { stdlibversion.Build = "" stdlibversion.BuildTime = "" stdlibversion.Version = version - githubutil.FlytectlReleaseConfig.OverrideExecutable = "/" + github.FlytectlReleaseConfig.OverrideExecutable = "/" assert.Nil(t, selfUpgrade(s.Ctx, args, s.CmdCtx)) }) diff --git a/cmd/version/version.go b/cmd/version/version.go index 927ca755..f802c69b 100644 --- a/cmd/version/version.go +++ b/cmd/version/version.go @@ -6,7 +6,7 @@ import ( "fmt" "runtime" - "github.com/flyteorg/flytectl/pkg/githubutil" + "github.com/flyteorg/flytectl/pkg/github" "github.com/flyteorg/flytectl/pkg/platformutil" @@ -53,11 +53,11 @@ func GetVersionCommand(rootCmd *cobra.Command) map[string]cmdCore.CommandEntry { func getVersion(ctx context.Context, args []string, cmdCtx cmdCore.CommandContext) error { goos := platformutil.Platform(runtime.GOOS) - version, err := githubutil.FlytectlReleaseConfig.GetLatestVersion() + version, err := github.FlytectlReleaseConfig.GetLatestVersion() if err != nil { logger.Error(ctx, "Unable to get the latest version because %v", err) } else { - message, err := githubutil.GetUpgradeMessage(version, goos) + message, err := github.GetUpgradeMessage(version, goos) if err != nil { logger.Error(ctx, "Unable to detect a new version because %v", err) } diff --git a/go.mod b/go.mod index 2d68091a..30190ad0 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/docker/docker v20.10.7+incompatible github.com/docker/go-connections v0.4.0 github.com/enescakir/emoji v1.0.0 - github.com/flyteorg/flyteidl v0.24.15 + github.com/flyteorg/flyteidl v0.24.21 github.com/flyteorg/flytestdlib v0.4.16 github.com/ghodss/yaml v1.0.0 github.com/go-ozzo/ozzo-validation/v4 v4.3.0 diff --git a/go.sum b/go.sum index 23095dc0..5a749e8e 100644 --- a/go.sum +++ b/go.sum @@ -364,8 +364,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/flyteorg/flyteidl v0.24.15 h1:Iqbwx3w1a4Dh6byRZrZMlHsKPKoOZbBiS9vR0iXzacY= -github.com/flyteorg/flyteidl v0.24.15/go.mod h1:vHSugApgS3hRITIafzQDU8DZD/W8wFRfFcgaFU35Dww= +github.com/flyteorg/flyteidl v0.24.21 h1:9dowP4gQHBe/1sRfYa5PP2snT/7/ZwgRsYkof4zr19c= +github.com/flyteorg/flyteidl v0.24.21/go.mod h1:vHSugApgS3hRITIafzQDU8DZD/W8wFRfFcgaFU35Dww= github.com/flyteorg/flytestdlib v0.3.13/go.mod h1:Tz8JCECAbX6VWGwFT6cmEQ+RJpZ/6L9pswu3fzWs220= github.com/flyteorg/flytestdlib v0.4.16 h1:r4dCPUOqoE9xCAhOw9KDB7O6cBoCxyEtepIWYcj93H0= github.com/flyteorg/flytestdlib v0.4.16/go.mod h1:WA5Y4hrcgD0ybGOKJVOQ4sP8q7NLRV+S5SWOlH0axgM= diff --git a/pkg/docker/docker_util.go b/pkg/docker/docker_util.go index b6bef954..aeaae895 100644 --- a/pkg/docker/docker_util.go +++ b/pkg/docker/docker_util.go @@ -65,21 +65,28 @@ func GetDockerClient() (Docker, error) { } // GetSandbox will return sandbox container if it exist -func GetSandbox(ctx context.Context, cli Docker) *types.Container { - containers, _ := cli.ContainerList(ctx, types.ContainerListOptions{ +func GetSandbox(ctx context.Context, cli Docker) (*types.Container, error) { + containers, err := cli.ContainerList(ctx, types.ContainerListOptions{ All: true, }) + if err != nil { + return nil, err + } for _, v := range containers { if strings.Contains(v.Names[0], FlyteSandboxClusterName) { - return &v + return &v, nil } } - return nil + return nil, nil } // RemoveSandbox will remove sandbox container if exist func RemoveSandbox(ctx context.Context, cli Docker, reader io.Reader) error { - if c := GetSandbox(ctx, cli); c != nil { + c, err := GetSandbox(ctx, cli) + if err != nil { + return err + } + if c != nil { if cmdUtil.AskForConfirmation("delete existing sandbox cluster", reader) { err := cli.ContainerRemove(context.Background(), c.ID, types.ContainerRemoveOptions{ Force: true, diff --git a/pkg/docker/docker_util_test.go b/pkg/docker/docker_util_test.go index a5124fb2..37d91f90 100644 --- a/pkg/docker/docker_util_test.go +++ b/pkg/docker/docker_util_test.go @@ -43,29 +43,31 @@ func TestGetSandbox(t *testing.T) { setupSandbox() t.Run("Successfully get sandbox container", func(t *testing.T) { mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() - mockDocker.OnContainerList(context, types.ContainerListOptions{All: true}).Return(containers, nil) - c := GetSandbox(context, mockDocker) + mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return(containers, nil) + c, err := GetSandbox(ctx, mockDocker) assert.Equal(t, c.Names[0], FlyteSandboxClusterName) + assert.Nil(t, err) }) t.Run("Successfully get sandbox container with zero result", func(t *testing.T) { mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() - mockDocker.OnContainerList(context, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) - c := GetSandbox(context, mockDocker) + mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) + c, err := GetSandbox(ctx, mockDocker) assert.Nil(t, c) + assert.Nil(t, err) }) t.Run("Error in get sandbox container", func(t *testing.T) { mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() - mockDocker.OnContainerList(context, types.ContainerListOptions{All: true}).Return(containers, nil) - mockDocker.OnContainerRemove(context, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(nil) - err := RemoveSandbox(context, mockDocker, strings.NewReader("y")) + mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return(containers, nil) + mockDocker.OnContainerRemove(ctx, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(nil) + err := RemoveSandbox(ctx, mockDocker, strings.NewReader("y")) assert.Nil(t, err) }) @@ -75,23 +77,23 @@ func TestRemoveSandboxWithNoReply(t *testing.T) { setupSandbox() t.Run("Successfully remove sandbox container", func(t *testing.T) { mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() // Verify the attributes - mockDocker.OnContainerList(context, types.ContainerListOptions{All: true}).Return(containers, nil) - mockDocker.OnContainerRemove(context, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(nil) - err := RemoveSandbox(context, mockDocker, strings.NewReader("n")) + mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return(containers, nil) + mockDocker.OnContainerRemove(ctx, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(nil) + err := RemoveSandbox(ctx, mockDocker, strings.NewReader("n")) assert.NotNil(t, err) }) t.Run("Successfully remove sandbox container with zero sandbox containers are running", func(t *testing.T) { mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() // Verify the attributes - mockDocker.OnContainerList(context, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) - mockDocker.OnContainerRemove(context, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(nil) - err := RemoveSandbox(context, mockDocker, strings.NewReader("n")) + mockDocker.OnContainerList(ctx, types.ContainerListOptions{All: true}).Return([]types.Container{}, nil) + mockDocker.OnContainerRemove(ctx, mock.Anything, types.ContainerRemoveOptions{Force: true}).Return(nil) + err := RemoveSandbox(ctx, mockDocker, strings.NewReader("n")) assert.Nil(t, err) }) @@ -101,39 +103,39 @@ func TestPullDockerImage(t *testing.T) { t.Run("Successfully pull image Always", func(t *testing.T) { setupSandbox() mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() // Verify the attributes - mockDocker.OnImagePullMatch(context, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - err := PullDockerImage(context, mockDocker, "nginx:latest", sandboxConfig.ImagePullPolicyAlways, sandboxConfig.ImagePullOptions{}) + mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + err := PullDockerImage(ctx, mockDocker, "nginx:latest", sandboxConfig.ImagePullPolicyAlways, sandboxConfig.ImagePullOptions{}) assert.Nil(t, err) }) t.Run("Error in pull image", func(t *testing.T) { setupSandbox() mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() // Verify the attributes - mockDocker.OnImagePullMatch(context, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, fmt.Errorf("error")) - err := PullDockerImage(context, mockDocker, "nginx:latest", sandboxConfig.ImagePullPolicyAlways, sandboxConfig.ImagePullOptions{}) + mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, fmt.Errorf("error")) + err := PullDockerImage(ctx, mockDocker, "nginx:latest", sandboxConfig.ImagePullPolicyAlways, sandboxConfig.ImagePullOptions{}) assert.NotNil(t, err) }) t.Run("Successfully pull image IfNotPresent", func(t *testing.T) { setupSandbox() mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() // Verify the attributes - mockDocker.OnImagePullMatch(context, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) - mockDocker.OnImageListMatch(context, types.ImageListOptions{}).Return([]types.ImageSummary{}, nil) - err := PullDockerImage(context, mockDocker, "nginx:latest", sandboxConfig.ImagePullPolicyIfNotPresent, sandboxConfig.ImagePullOptions{}) + mockDocker.OnImagePullMatch(ctx, mock.Anything, types.ImagePullOptions{}).Return(os.Stdin, nil) + mockDocker.OnImageListMatch(ctx, types.ImageListOptions{}).Return([]types.ImageSummary{}, nil) + err := PullDockerImage(ctx, mockDocker, "nginx:latest", sandboxConfig.ImagePullPolicyIfNotPresent, sandboxConfig.ImagePullOptions{}) assert.Nil(t, err) }) t.Run("Successfully pull image Never", func(t *testing.T) { setupSandbox() mockDocker := &mocks.Docker{} - context := context.Background() - err := PullDockerImage(context, mockDocker, "nginx:latest", sandboxConfig.ImagePullPolicyNever, sandboxConfig.ImagePullOptions{}) + ctx := context.Background() + err := PullDockerImage(ctx, mockDocker, "nginx:latest", sandboxConfig.ImagePullPolicyNever, sandboxConfig.ImagePullOptions{}) assert.Nil(t, err) }) } @@ -144,10 +146,10 @@ func TestStartContainer(t *testing.T) { t.Run("Successfully create a container", func(t *testing.T) { setupSandbox() mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() // Verify the attributes - mockDocker.OnContainerCreate(context, &container.Config{ + mockDocker.OnContainerCreate(ctx, &container.Config{ Env: Environment, Image: imageName, Tty: false, @@ -159,8 +161,8 @@ func TestStartContainer(t *testing.T) { }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ ID: "Hello", }, nil) - mockDocker.OnContainerStart(context, "Hello", types.ContainerStartOptions{}).Return(nil) - id, err := StartContainer(context, mockDocker, Volumes, p1, p2, "nginx", imageName, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + id, err := StartContainer(ctx, mockDocker, Volumes, p1, p2, "nginx", imageName, nil) assert.Nil(t, err) assert.Greater(t, len(id), 0) assert.Equal(t, id, "Hello") @@ -169,14 +171,14 @@ func TestStartContainer(t *testing.T) { t.Run("Successfully create a container with Env", func(t *testing.T) { setupSandbox() mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() // Setup additional env additionalEnv := []string{"a=1", "b=2"} expectedEnv := append(Environment, "a=1") expectedEnv = append(expectedEnv, "b=2") // Verify the attributes - mockDocker.OnContainerCreate(context, &container.Config{ + mockDocker.OnContainerCreate(ctx, &container.Config{ Env: expectedEnv, Image: imageName, Tty: false, @@ -188,8 +190,8 @@ func TestStartContainer(t *testing.T) { }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ ID: "Hello", }, nil) - mockDocker.OnContainerStart(context, "Hello", types.ContainerStartOptions{}).Return(nil) - id, err := StartContainer(context, mockDocker, Volumes, p1, p2, "nginx", imageName, additionalEnv) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + id, err := StartContainer(ctx, mockDocker, Volumes, p1, p2, "nginx", imageName, additionalEnv) assert.Nil(t, err) assert.Greater(t, len(id), 0) assert.Equal(t, id, "Hello") @@ -199,10 +201,10 @@ func TestStartContainer(t *testing.T) { t.Run("Error in creating container", func(t *testing.T) { setupSandbox() mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() // Verify the attributes - mockDocker.OnContainerCreate(context, &container.Config{ + mockDocker.OnContainerCreate(ctx, &container.Config{ Env: Environment, Image: imageName, Tty: false, @@ -214,8 +216,8 @@ func TestStartContainer(t *testing.T) { }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ ID: "", }, fmt.Errorf("error")) - mockDocker.OnContainerStart(context, "Hello", types.ContainerStartOptions{}).Return(nil) - id, err := StartContainer(context, mockDocker, Volumes, p1, p2, "nginx", imageName, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(nil) + id, err := StartContainer(ctx, mockDocker, Volumes, p1, p2, "nginx", imageName, nil) assert.NotNil(t, err) assert.Equal(t, len(id), 0) assert.Equal(t, id, "") @@ -224,10 +226,10 @@ func TestStartContainer(t *testing.T) { t.Run("Error in start of a container", func(t *testing.T) { setupSandbox() mockDocker := &mocks.Docker{} - context := context.Background() + ctx := context.Background() // Verify the attributes - mockDocker.OnContainerCreate(context, &container.Config{ + mockDocker.OnContainerCreate(ctx, &container.Config{ Env: Environment, Image: imageName, Tty: false, @@ -239,8 +241,8 @@ func TestStartContainer(t *testing.T) { }, nil, nil, mock.Anything).Return(container.ContainerCreateCreatedBody{ ID: "Hello", }, nil) - mockDocker.OnContainerStart(context, "Hello", types.ContainerStartOptions{}).Return(fmt.Errorf("error")) - id, err := StartContainer(context, mockDocker, Volumes, p1, p2, "nginx", imageName, nil) + mockDocker.OnContainerStart(ctx, "Hello", types.ContainerStartOptions{}).Return(fmt.Errorf("error")) + id, err := StartContainer(ctx, mockDocker, Volumes, p1, p2, "nginx", imageName, nil) assert.NotNil(t, err) assert.Equal(t, len(id), 0) assert.Equal(t, id, "") @@ -252,27 +254,27 @@ func TestReadLogs(t *testing.T) { t.Run("Successfully read logs", func(t *testing.T) { mockDocker := &mocks.Docker{} - context := context.Background() - mockDocker.OnContainerLogsMatch(context, mock.Anything, types.ContainerLogsOptions{ + ctx := context.Background() + mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, }).Return(nil, nil) - _, err := ReadLogs(context, mockDocker, "test") + _, err := ReadLogs(ctx, mockDocker, "test") assert.Nil(t, err) }) t.Run("Error in reading logs", func(t *testing.T) { mockDocker := &mocks.Docker{} - context := context.Background() - mockDocker.OnContainerLogsMatch(context, mock.Anything, types.ContainerLogsOptions{ + ctx := context.Background() + mockDocker.OnContainerLogsMatch(ctx, mock.Anything, types.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Timestamps: true, Follow: true, }).Return(nil, fmt.Errorf("error")) - _, err := ReadLogs(context, mockDocker, "test") + _, err := ReadLogs(ctx, mockDocker, "test") assert.NotNil(t, err) }) } diff --git a/pkg/githubutil/githubutil.go b/pkg/github/githubutil.go similarity index 64% rename from pkg/githubutil/githubutil.go rename to pkg/github/githubutil.go index 5fa3dacc..e65feaa1 100644 --- a/pkg/githubutil/githubutil.go +++ b/pkg/github/githubutil.go @@ -1,36 +1,30 @@ -package githubutil +package github import ( "context" + "fmt" "net/http" "os" "path/filepath" "runtime" "strings" - "golang.org/x/text/cases" - "golang.org/x/text/language" - + "github.com/flyteorg/flytectl/pkg/platformutil" "github.com/flyteorg/flytectl/pkg/util" - "github.com/flyteorg/flytestdlib/logger" - - "golang.org/x/oauth2" - - "github.com/flyteorg/flytectl/pkg/platformutil" stdlibversion "github.com/flyteorg/flytestdlib/version" - "github.com/mouuff/go-rocket-update/pkg/provider" - "github.com/mouuff/go-rocket-update/pkg/updater" - - "fmt" "github.com/google/go-github/v42/github" + "github.com/mouuff/go-rocket-update/pkg/provider" + "github.com/mouuff/go-rocket-update/pkg/updater" + "golang.org/x/oauth2" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) const ( owner = "flyteorg" flyte = "flyte" - sandboxManifest = "flyte_sandbox_manifest.yaml" flytectl = "flytectl" sandboxSupportedVersion = "v0.10.0" flytectlRepository = "github.com/flyteorg/flytectl" @@ -42,6 +36,8 @@ const ( brewInstallDirectory = "/Cellar/flytectl" ) +var Client GHRepoService + // FlytectlReleaseConfig represent the updater config for flytectl binary var FlytectlReleaseConfig = &updater.Updater{ Provider: &provider.Github{ @@ -56,31 +52,28 @@ var ( arch = platformutil.Arch(runtime.GOARCH) ) -//GetGHClient will return github client -func GetGHClient() *github.Client { - if len(os.Getenv("GITHUB_TOKEN")) > 0 { - return github.NewClient(oauth2.NewClient(context.Background(), oauth2.StaticTokenSource( - &oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")}, - ))) - } - return github.NewClient(&http.Client{}) +//go:generate mockery -name=GHRepoService -case=underscore + +type GHRepoService interface { + GetLatestRelease(ctx context.Context, owner, repo string) (*github.RepositoryRelease, *github.Response, error) + ListReleases(ctx context.Context, owner, repo string, opts *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error) + GetReleaseByTag(ctx context.Context, owner, repo, tag string) (*github.RepositoryRelease, *github.Response, error) + GetCommitSHA1(ctx context.Context, owner, repo, ref, lastSHA string) (string, *github.Response, error) } -// GetLatestVersion returns the latest non-prerelease version of provided repository, as +// GetLatestRelease returns the latest non-prerelease version of provided repoName, as // described in https://docs.github.com/en/rest/reference/releases#get-the-latest-release -func GetLatestVersion(repository string) (*github.RepositoryRelease, error) { - client := GetGHClient() - release, _, err := client.Repositories.GetLatestRelease(context.Background(), owner, repository) +func GetLatestRelease(repoName string, g GHRepoService) (*github.RepositoryRelease, error) { + release, _, err := g.GetLatestRelease(context.Background(), owner, repoName) if err != nil { return nil, err } return release, err } -// GetListRelease returns the list of release of provided repository -func GetListRelease(repository string) ([]*github.RepositoryRelease, error) { - client := GetGHClient() - releases, _, err := client.Repositories.ListReleases(context.Background(), owner, repository, &github.ListOptions{ +// ListReleases returns the list of release of provided repoName +func ListReleases(repoName string, g GHRepoService) ([]*github.RepositoryRelease, error) { + releases, _, err := g.ListReleases(context.Background(), owner, repoName, &github.ListOptions{ PerPage: 100, }) if err != nil { @@ -89,11 +82,43 @@ func GetListRelease(repository string) ([]*github.RepositoryRelease, error) { return releases, err } +// GetReleaseByTag returns the provided tag release if tag exist in repository +func GetReleaseByTag(repoName, tag string, g GHRepoService) (*github.RepositoryRelease, error) { + release, _, err := g.GetReleaseByTag(context.Background(), owner, repoName, tag) + if err != nil { + return nil, err + } + return release, err +} + +// GetCommitSHA1 returns sha hash against the version +func GetCommitSHA1(repoName, version string, g GHRepoService) (string, error) { + sha, _, err := g.GetCommitSHA1(context.Background(), owner, repoName, version, "") + if err != nil { + return "", err + } + return sha, err +} + +// GetAssetFromRelease returns the asset using assetName from github release with tag +func GetAssetFromRelease(tag, assetName, repoName string, g GHRepoService) (*github.ReleaseAsset, error) { + release, _, err := g.GetReleaseByTag(context.Background(), owner, repoName, tag) + if err != nil { + return nil, err + } + for _, v := range release.Assets { + if v.GetName() == assetName { + return v, nil + } + } + return nil, fmt.Errorf("assest is not found in %s[%s] release", repoName, tag) +} + // GetSandboxImageSha returns the sha as per input -func GetSandboxImageSha(version string, pre bool) (string, string, error) { +func GetSandboxImageSha(tag string, pre bool, g GHRepoService) (string, string, error) { var release *github.RepositoryRelease - if len(version) == 0 { - releases, err := GetListRelease(flyte) + if len(tag) == 0 { + releases, err := ListReleases(flyte, g) if err != nil { return "", release.GetTagName(), err } @@ -107,8 +132,8 @@ func GetSandboxImageSha(version string, pre bool) (string, string, error) { } } logger.Infof(context.Background(), "starting with release %s", release.GetTagName()) - } else if len(version) > 0 { - r, err := CheckVersionExist(version, flyte) + } else if len(tag) > 0 { + r, err := GetReleaseByTag(flyte, tag, g) if err != nil { return "", r.GetTagName(), err } @@ -121,7 +146,7 @@ func GetSandboxImageSha(version string, pre bool) (string, string, error) { if !isGreater { return "", release.GetTagName(), fmt.Errorf("version flag only supported with flyte %s+ release", sandboxSupportedVersion) } - sha, err := GetSHAFromVersion(release.GetTagName(), flyte) + sha, err := GetCommitSHA1(flyte, release.GetTagName(), g) if err != nil { return "", release.GetTagName(), err } @@ -137,40 +162,6 @@ func getFlytectlAssetName() string { return fmt.Sprintf("flytectl_%s_%s.tar.gz", cases.Title(language.English).String(runtime.GOOS), arch.String()) } -// CheckVersionExist returns the provided version release if version exist in repository -func CheckVersionExist(version, repository string) (*github.RepositoryRelease, error) { - client := GetGHClient() - release, _, err := client.Repositories.GetReleaseByTag(context.Background(), owner, repository, version) - if err != nil { - return nil, err - } - return release, err -} - -// GetSHAFromVersion returns sha commit hash against a release -func GetSHAFromVersion(version, repository string) (string, error) { - client := GetGHClient() - sha, _, err := client.Repositories.GetCommitSHA1(context.Background(), owner, repository, version, "") - if err != nil { - return "", err - } - return sha, err -} - -// GetAssetsFromRelease returns the asset from github release -func GetAssetsFromRelease(version, assets, repository string) (*github.ReleaseAsset, error) { - release, err := CheckVersionExist(version, repository) - if err != nil { - return nil, err - } - for _, v := range release.Assets { - if v.GetName() == assets { - return v, nil - } - } - return nil, fmt.Errorf("assest is not found in %s[%s] release", repository, version) -} - // GetUpgradeMessage return the upgrade message func GetUpgradeMessage(latest string, goos platformutil.Platform) (string, error) { isGreater, err := util.IsVersionGreaterThan(latest, stdlibversion.Version) @@ -218,11 +209,28 @@ func CheckBrewInstall(goos platformutil.Platform) (string, error) { // if no version is specified then the Latest release of cr.flyte.org/flyteorg/flyte-sandbox:dind-{SHA} is used // else cr.flyte.org/flyteorg/flyte-sandbox:dind-{SHA}, where sha is derived from the version. // If pre release is true then use latest pre release of Flyte, In that case User don't need to pass version -func GetFullyQualifiedImageName(prefix, version, image string, pre bool) (string, string, error) { - sha, version, err := GetSandboxImageSha(version, pre) + +func GetFullyQualifiedImageName(prefix, version, image string, pre bool, g GHRepoService) (string, string, error) { + sha, version, err := GetSandboxImageSha(version, pre, g) if err != nil { return "", version, err } return fmt.Sprintf("%s:%s", image, fmt.Sprintf("%s-%s", prefix, sha)), version, nil } + +// GetGHRepoService returns the initialized github repo service client. +func GetGHRepoService() GHRepoService { + if Client == nil { + var gh *github.Client + if len(os.Getenv("GITHUB_TOKEN")) > 0 { + gh = github.NewClient(oauth2.NewClient(context.Background(), oauth2.StaticTokenSource( + &oauth2.Token{AccessToken: os.Getenv("GITHUB_TOKEN")}, + ))) + } else { + gh = github.NewClient(&http.Client{}) + } + return gh.Repositories + } + return Client +} diff --git a/pkg/github/githubutil_test.go b/pkg/github/githubutil_test.go new file mode 100644 index 00000000..920f7682 --- /dev/null +++ b/pkg/github/githubutil_test.go @@ -0,0 +1,205 @@ +package github + +import ( + "fmt" + "runtime" + "strings" + "testing" + + "github.com/flyteorg/flytectl/pkg/github/mocks" + "github.com/flyteorg/flytectl/pkg/platformutil" + stdlibversion "github.com/flyteorg/flytestdlib/version" + "github.com/google/go-github/v42/github" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "golang.org/x/text/cases" + "golang.org/x/text/language" +) + +var sandboxImageName = "cr.flyte.org/flyteorg/flyte-sandbox" + +func TestGetLatestVersion(t *testing.T) { + t.Run("Get latest release with wrong url", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + mockGh.OnGetLatestReleaseMatch(mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("failed")) + _, err := GetLatestRelease("fl", mockGh) + assert.NotNil(t, err) + }) + t.Run("Get latest release", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + mockGh.OnGetLatestReleaseMatch(mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, nil) + _, err := GetLatestRelease("flytectl", mockGh) + assert.Nil(t, err) + }) +} + +func TestGetLatestRelease(t *testing.T) { + mockGh := &mocks.GHRepoService{} + tag := "v1.0.0" + mockGh.OnGetLatestReleaseMatch(mock.Anything, mock.Anything, mock.Anything).Return(&github.RepositoryRelease{ + TagName: &tag, + }, nil, nil) + release, err := GetLatestRelease("flyte", mockGh) + assert.Nil(t, err) + assert.Equal(t, true, strings.HasPrefix(release.GetTagName(), "v")) +} + +func TestCheckVersionExist(t *testing.T) { + t.Run("Invalid Tag", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + mockGh.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("failed")) + _, err := GetReleaseByTag("v100.0.0", "flyte", mockGh) + assert.NotNil(t, err) + }) + t.Run("Valid Tag", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + tag := "v1.0.0" + mockGh.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&github.RepositoryRelease{ + TagName: &tag, + }, nil, nil) + release, err := GetReleaseByTag(tag, "flyte", mockGh) + assert.Nil(t, err) + assert.Equal(t, true, strings.HasPrefix(release.GetTagName(), "v")) + }) +} + +func TestGetFullyQualifiedImageName(t *testing.T) { + t.Run("Get tFully Qualified Image Name ", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + tag := "v0.15.0" + isPreRelease := false + releases := []*github.RepositoryRelease{{ + TagName: &tag, + Prerelease: &isPreRelease, + }} + mockGh.OnListReleasesMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(releases, nil, nil) + mockGh.OnGetCommitSHA1Match(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sandboxImageName, nil, nil) + image, tag, err := GetFullyQualifiedImageName("dind", "", sandboxImageName, false, mockGh) + assert.Nil(t, err) + assert.Equal(t, true, strings.HasPrefix(tag, "v")) + assert.Equal(t, true, strings.HasPrefix(image, sandboxImageName)) + }) + t.Run("Get Fully Qualified Image Name with pre release", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + tag := "v0.15.0-pre" + isPreRelease := true + releases := []*github.RepositoryRelease{{ + TagName: &tag, + Prerelease: &isPreRelease, + }} + mockGh.OnListReleasesMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(releases, nil, nil) + mockGh.OnGetCommitSHA1Match(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sandboxImageName, nil, nil) + image, tag, err := GetFullyQualifiedImageName("dind", "", sandboxImageName, isPreRelease, mockGh) + assert.Nil(t, err) + assert.Equal(t, true, strings.HasPrefix(tag, "v")) + assert.Equal(t, true, strings.HasPrefix(image, sandboxImageName)) + }) + t.Run("Get Fully Qualified Image Name with specific version", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + tag := "v0.19.0" + isPreRelease := true + release := &github.RepositoryRelease{ + TagName: &tag, + Prerelease: &isPreRelease, + } + mockGh.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(release, nil, nil) + mockGh.OnGetCommitSHA1Match(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(sandboxImageName, nil, nil) + image, tag, err := GetFullyQualifiedImageName("dind", "v0.19.0", sandboxImageName, isPreRelease, mockGh) + assert.Nil(t, err) + assert.Equal(t, "v0.19.0", tag) + assert.Equal(t, true, strings.HasPrefix(image, sandboxImageName)) + }) +} + +func TestGetSHAFromVersion(t *testing.T) { + t.Run("Invalid Tag", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + mockGh.OnGetCommitSHA1Match(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return("", nil, fmt.Errorf("failed")) + _, err := GetCommitSHA1("v100.0.0", "flyte", mockGh) + assert.NotNil(t, err) + }) + t.Run("Valid Tag", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + mockGh.OnGetCommitSHA1Match(mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return("v1.15.0", nil, nil) + release, err := GetCommitSHA1("v0.15.0", "flyte", mockGh) + assert.Nil(t, err) + assert.Greater(t, len(release), 0) + }) +} + +func TestGetAssetsFromRelease(t *testing.T) { + t.Run("Successful get assets", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + tag := "v0.15.0" + sandboxManifest := "flyte_sandbox_manifest.yaml" + mockGh.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&github.RepositoryRelease{ + TagName: &tag, + Assets: []*github.ReleaseAsset{{ + Name: &sandboxManifest, + }, + }, + }, nil, nil) + assets, err := GetAssetFromRelease(tag, sandboxManifest, flyte, mockGh) + assert.Nil(t, err) + assert.NotNil(t, assets) + assert.Equal(t, sandboxManifest, *assets.Name) + }) + + t.Run("Failed get assets with wrong name", func(t *testing.T) { + mockGh := &mocks.GHRepoService{} + mockGh.OnGetReleaseByTagMatch(mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, nil, fmt.Errorf("failed")) + assets, err := GetAssetFromRelease("v0.15.0", "test", flyte, mockGh) + assert.NotNil(t, err) + assert.Nil(t, assets) + }) +} + +func TestGetAssetsName(t *testing.T) { + t.Run("Get Assets name", func(t *testing.T) { + expected := fmt.Sprintf("flytectl_%s_386.tar.gz", cases.Title(language.English).String(runtime.GOOS)) + arch = platformutil.Arch386 + assert.Equal(t, expected, getFlytectlAssetName()) + }) +} + +func TestCheckBrewInstall(t *testing.T) { + symlink, err := CheckBrewInstall(platformutil.Darwin) + assert.Nil(t, err) + assert.Equal(t, len(symlink), 0) + symlink, err = CheckBrewInstall(platformutil.Linux) + assert.Nil(t, err) + assert.Equal(t, 0, len(symlink)) +} + +func TestGetUpgradeMessage(t *testing.T) { + var darwin = platformutil.Darwin + var linux = platformutil.Linux + var windows = platformutil.Linux + + var version = "v0.2.20" + stdlibversion.Version = "v0.2.10" + message, err := GetUpgradeMessage(version, darwin) + assert.Nil(t, err) + assert.Equal(t, 157, len(message)) + + version = "v0.2.09" + message, err = GetUpgradeMessage(version, darwin) + assert.Nil(t, err) + assert.Equal(t, 63, len(message)) + + version = "v" + message, err = GetUpgradeMessage(version, darwin) + assert.NotNil(t, err) + assert.Equal(t, 0, len(message)) + + version = "v0.2.20" + message, err = GetUpgradeMessage(version, windows) + assert.Nil(t, err) + assert.Equal(t, 157, len(message)) + + version = "v0.2.20" + message, err = GetUpgradeMessage(version, linux) + assert.Nil(t, err) + assert.Equal(t, 157, len(message)) +} diff --git a/pkg/github/mocks/gh_repo_service.go b/pkg/github/mocks/gh_repo_service.go new file mode 100644 index 00000000..04c2bfeb --- /dev/null +++ b/pkg/github/mocks/gh_repo_service.go @@ -0,0 +1,213 @@ +// Code generated by mockery v1.0.1. DO NOT EDIT. + +package mocks + +import ( + context "context" + + github "github.com/google/go-github/v42/github" + mock "github.com/stretchr/testify/mock" +) + +// GHRepoService is an autogenerated mock type for the GHRepoService type +type GHRepoService struct { + mock.Mock +} + +type GHRepoService_GetCommitSHA1 struct { + *mock.Call +} + +func (_m GHRepoService_GetCommitSHA1) Return(_a0 string, _a1 *github.Response, _a2 error) *GHRepoService_GetCommitSHA1 { + return &GHRepoService_GetCommitSHA1{Call: _m.Call.Return(_a0, _a1, _a2)} +} + +func (_m *GHRepoService) OnGetCommitSHA1(ctx context.Context, owner string, repo string, ref string, lastSHA string) *GHRepoService_GetCommitSHA1 { + c := _m.On("GetCommitSHA1", ctx, owner, repo, ref, lastSHA) + return &GHRepoService_GetCommitSHA1{Call: c} +} + +func (_m *GHRepoService) OnGetCommitSHA1Match(matchers ...interface{}) *GHRepoService_GetCommitSHA1 { + c := _m.On("GetCommitSHA1", matchers...) + return &GHRepoService_GetCommitSHA1{Call: c} +} + +// GetCommitSHA1 provides a mock function with given fields: ctx, owner, repo, ref, lastSHA +func (_m *GHRepoService) GetCommitSHA1(ctx context.Context, owner string, repo string, ref string, lastSHA string) (string, *github.Response, error) { + ret := _m.Called(ctx, owner, repo, ref, lastSHA) + + var r0 string + if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) string); ok { + r0 = rf(ctx, owner, repo, ref, lastSHA) + } else { + r0 = ret.Get(0).(string) + } + + var r1 *github.Response + if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string) *github.Response); ok { + r1 = rf(ctx, owner, repo, ref, lastSHA) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*github.Response) + } + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, string, string, string) error); ok { + r2 = rf(ctx, owner, repo, ref, lastSHA) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type GHRepoService_GetLatestRelease struct { + *mock.Call +} + +func (_m GHRepoService_GetLatestRelease) Return(_a0 *github.RepositoryRelease, _a1 *github.Response, _a2 error) *GHRepoService_GetLatestRelease { + return &GHRepoService_GetLatestRelease{Call: _m.Call.Return(_a0, _a1, _a2)} +} + +func (_m *GHRepoService) OnGetLatestRelease(ctx context.Context, owner string, repo string) *GHRepoService_GetLatestRelease { + c := _m.On("GetLatestRelease", ctx, owner, repo) + return &GHRepoService_GetLatestRelease{Call: c} +} + +func (_m *GHRepoService) OnGetLatestReleaseMatch(matchers ...interface{}) *GHRepoService_GetLatestRelease { + c := _m.On("GetLatestRelease", matchers...) + return &GHRepoService_GetLatestRelease{Call: c} +} + +// GetLatestRelease provides a mock function with given fields: ctx, owner, repo +func (_m *GHRepoService) GetLatestRelease(ctx context.Context, owner string, repo string) (*github.RepositoryRelease, *github.Response, error) { + ret := _m.Called(ctx, owner, repo) + + var r0 *github.RepositoryRelease + if rf, ok := ret.Get(0).(func(context.Context, string, string) *github.RepositoryRelease); ok { + r0 = rf(ctx, owner, repo) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*github.RepositoryRelease) + } + } + + var r1 *github.Response + if rf, ok := ret.Get(1).(func(context.Context, string, string) *github.Response); ok { + r1 = rf(ctx, owner, repo) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*github.Response) + } + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, string) error); ok { + r2 = rf(ctx, owner, repo) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type GHRepoService_GetReleaseByTag struct { + *mock.Call +} + +func (_m GHRepoService_GetReleaseByTag) Return(_a0 *github.RepositoryRelease, _a1 *github.Response, _a2 error) *GHRepoService_GetReleaseByTag { + return &GHRepoService_GetReleaseByTag{Call: _m.Call.Return(_a0, _a1, _a2)} +} + +func (_m *GHRepoService) OnGetReleaseByTag(ctx context.Context, owner string, repo string, tag string) *GHRepoService_GetReleaseByTag { + c := _m.On("GetReleaseByTag", ctx, owner, repo, tag) + return &GHRepoService_GetReleaseByTag{Call: c} +} + +func (_m *GHRepoService) OnGetReleaseByTagMatch(matchers ...interface{}) *GHRepoService_GetReleaseByTag { + c := _m.On("GetReleaseByTag", matchers...) + return &GHRepoService_GetReleaseByTag{Call: c} +} + +// GetReleaseByTag provides a mock function with given fields: ctx, owner, repo, tag +func (_m *GHRepoService) GetReleaseByTag(ctx context.Context, owner string, repo string, tag string) (*github.RepositoryRelease, *github.Response, error) { + ret := _m.Called(ctx, owner, repo, tag) + + var r0 *github.RepositoryRelease + if rf, ok := ret.Get(0).(func(context.Context, string, string, string) *github.RepositoryRelease); ok { + r0 = rf(ctx, owner, repo, tag) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*github.RepositoryRelease) + } + } + + var r1 *github.Response + if rf, ok := ret.Get(1).(func(context.Context, string, string, string) *github.Response); ok { + r1 = rf(ctx, owner, repo, tag) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*github.Response) + } + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, string, string) error); ok { + r2 = rf(ctx, owner, repo, tag) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} + +type GHRepoService_ListReleases struct { + *mock.Call +} + +func (_m GHRepoService_ListReleases) Return(_a0 []*github.RepositoryRelease, _a1 *github.Response, _a2 error) *GHRepoService_ListReleases { + return &GHRepoService_ListReleases{Call: _m.Call.Return(_a0, _a1, _a2)} +} + +func (_m *GHRepoService) OnListReleases(ctx context.Context, owner string, repo string, opts *github.ListOptions) *GHRepoService_ListReleases { + c := _m.On("ListReleases", ctx, owner, repo, opts) + return &GHRepoService_ListReleases{Call: c} +} + +func (_m *GHRepoService) OnListReleasesMatch(matchers ...interface{}) *GHRepoService_ListReleases { + c := _m.On("ListReleases", matchers...) + return &GHRepoService_ListReleases{Call: c} +} + +// ListReleases provides a mock function with given fields: ctx, owner, repo, opts +func (_m *GHRepoService) ListReleases(ctx context.Context, owner string, repo string, opts *github.ListOptions) ([]*github.RepositoryRelease, *github.Response, error) { + ret := _m.Called(ctx, owner, repo, opts) + + var r0 []*github.RepositoryRelease + if rf, ok := ret.Get(0).(func(context.Context, string, string, *github.ListOptions) []*github.RepositoryRelease); ok { + r0 = rf(ctx, owner, repo, opts) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*github.RepositoryRelease) + } + } + + var r1 *github.Response + if rf, ok := ret.Get(1).(func(context.Context, string, string, *github.ListOptions) *github.Response); ok { + r1 = rf(ctx, owner, repo, opts) + } else { + if ret.Get(1) != nil { + r1 = ret.Get(1).(*github.Response) + } + } + + var r2 error + if rf, ok := ret.Get(2).(func(context.Context, string, string, *github.ListOptions) error); ok { + r2 = rf(ctx, owner, repo, opts) + } else { + r2 = ret.Error(2) + } + + return r0, r1, r2 +} diff --git a/pkg/githubutil/githubutil_test.go b/pkg/githubutil/githubutil_test.go deleted file mode 100644 index 037a0ede..00000000 --- a/pkg/githubutil/githubutil_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package githubutil - -import ( - "fmt" - "runtime" - "strings" - "testing" - - "golang.org/x/text/cases" - "golang.org/x/text/language" - - stdlibversion "github.com/flyteorg/flytestdlib/version" - - "github.com/flyteorg/flytectl/pkg/platformutil" - - "github.com/stretchr/testify/assert" -) - -var sandboxImageName = "cr.flyte.org/flyteorg/flyte-sandbox" - -func TestGetLatestVersion(t *testing.T) { - t.Run("Get latest release with wrong url", func(t *testing.T) { - _, err := GetLatestVersion("fl") - assert.NotNil(t, err) - }) - t.Run("Get latest release", func(t *testing.T) { - _, err := GetLatestVersion("flytectl") - assert.Nil(t, err) - }) -} - -func TestGetLatestRelease(t *testing.T) { - release, err := GetLatestVersion("flyte") - assert.Nil(t, err) - assert.Equal(t, true, strings.HasPrefix(release.GetTagName(), "v")) -} - -func TestCheckVersionExist(t *testing.T) { - t.Run("Invalid Tag", func(t *testing.T) { - _, err := CheckVersionExist("v100.0.0", "flyte") - assert.NotNil(t, err) - }) - t.Run("Valid Tag", func(t *testing.T) { - release, err := CheckVersionExist("v0.15.0", "flyte") - assert.Nil(t, err) - assert.Equal(t, true, strings.HasPrefix(release.GetTagName(), "v")) - }) -} - -func TestGetFullyQualifiedImageName(t *testing.T) { - t.Run("Get tFully Qualified Image Name ", func(t *testing.T) { - image, tag, err := GetFullyQualifiedImageName("dind", "", sandboxImageName, false) - assert.Nil(t, err) - assert.Equal(t, true, strings.HasPrefix(tag, "v")) - assert.Equal(t, true, strings.HasPrefix(image, sandboxImageName)) - }) - t.Run("Get tFully Qualified Image Name with pre release", func(t *testing.T) { - image, tag, err := GetFullyQualifiedImageName("dind", "", sandboxImageName, true) - assert.Nil(t, err) - assert.Equal(t, true, strings.HasPrefix(tag, "v")) - assert.Equal(t, true, strings.HasPrefix(image, sandboxImageName)) - }) - t.Run("Get tFully Qualified Image Name with specific version", func(t *testing.T) { - image, tag, err := GetFullyQualifiedImageName("dind", "v0.19.0", sandboxImageName, true) - assert.Nil(t, err) - assert.Equal(t, "v0.19.0", tag) - assert.Equal(t, true, strings.HasPrefix(image, sandboxImageName)) - }) -} - -func TestGetSHAFromVersion(t *testing.T) { - t.Run("Invalid Tag", func(t *testing.T) { - _, err := GetSHAFromVersion("v100.0.0", "flyte") - assert.NotNil(t, err) - }) - t.Run("Valid Tag", func(t *testing.T) { - release, err := GetSHAFromVersion("v0.15.0", "flyte") - assert.Nil(t, err) - assert.Greater(t, len(release), 0) - }) -} - -func TestGetAssetsFromRelease(t *testing.T) { - t.Run("Successful get assets", func(t *testing.T) { - assets, err := GetAssetsFromRelease("v0.15.0", sandboxManifest, flyte) - assert.Nil(t, err) - assert.NotNil(t, assets) - assert.Equal(t, sandboxManifest, *assets.Name) - }) - - t.Run("Failed get assets with wrong name", func(t *testing.T) { - assets, err := GetAssetsFromRelease("v0.15.0", "test", flyte) - assert.NotNil(t, err) - assert.Nil(t, assets) - }) - t.Run("Successful get assets with wrong version", func(t *testing.T) { - assets, err := GetAssetsFromRelease("v100.15.0", "test", flyte) - assert.NotNil(t, err) - assert.Nil(t, assets) - }) -} - -func TestGetAssetsName(t *testing.T) { - t.Run("Get Assets name", func(t *testing.T) { - expected := fmt.Sprintf("flytectl_%s_386.tar.gz", cases.Title(language.English).String(runtime.GOOS)) - arch = platformutil.Arch386 - assert.Equal(t, expected, getFlytectlAssetName()) - }) -} - -func TestCheckBrewInstall(t *testing.T) { - symlink, err := CheckBrewInstall(platformutil.Darwin) - assert.Nil(t, err) - assert.Equal(t, len(symlink), 0) - symlink, err = CheckBrewInstall(platformutil.Linux) - assert.Nil(t, err) - assert.Equal(t, 0, len(symlink)) -} - -func TestGetUpgradeMessage(t *testing.T) { - var darwin = platformutil.Darwin - var linux = platformutil.Linux - var windows = platformutil.Linux - - var version = "v0.2.20" - stdlibversion.Version = "v0.2.10" - message, err := GetUpgradeMessage(version, darwin) - assert.Nil(t, err) - assert.Equal(t, 157, len(message)) - - version = "v0.2.09" - message, err = GetUpgradeMessage(version, darwin) - assert.Nil(t, err) - assert.Equal(t, 63, len(message)) - - version = "v" - message, err = GetUpgradeMessage(version, darwin) - assert.NotNil(t, err) - assert.Equal(t, 0, len(message)) - - version = "v0.2.20" - message, err = GetUpgradeMessage(version, windows) - assert.Nil(t, err) - assert.Equal(t, 157, len(message)) - - version = "v0.2.20" - message, err = GetUpgradeMessage(version, linux) - assert.Nil(t, err) - assert.Equal(t, 157, len(message)) -}