Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: add e2e test helper for container use spec #640

Merged
merged 15 commits into from
Jul 21, 2022
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
*.report

# Dependency directories (remove the comment below to include it)
vendor/
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -150,11 +150,11 @@ test-local:
@go test -v -race -coverprofile=coverage.out ./...

test: generate ## Run the tests
@go test -race -coverpkg=./pkg/... -coverprofile=coverage.out $(shell go list ./... | grep -v app)
@go test -race -coverpkg=./pkg/... -coverprofile=coverage.out $(shell go list ./... | grep -v e2e)
@go tool cover -func coverage.out | tail -n 1 | awk '{ print "Total coverage: " $$3 }'

e2e-test: generate
@go test -race -coverpkg=./pkg/app -coverprofile=e2e-coverage.out ./pkg/app
@go test -race -coverpkg=./pkg/app -coverprofile=e2e-coverage.out ./e2e

clean: ## Clean the outputs and artifacts
@-rm -vrf ${OUTPUT_DIR}
Expand Down
23 changes: 12 additions & 11 deletions pkg/app/build_test.go → e2e/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package app
package e2e

import (
"context"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/tensorchord/envd/pkg/app"
"github.com/tensorchord/envd/pkg/docker"
"github.com/tensorchord/envd/pkg/home"
)
Expand All @@ -29,44 +30,44 @@ var _ = Describe("build command", Ordered, func() {
customImageTestName := "testdata/custom-image-test"
When("given the right arguments", func() {
It("should build successfully", func() {
app := New()
err := app.Run([]string{"envd.test", "--debug", "bootstrap"})
envdApp := app.New()
err := envdApp.Run([]string{"envd.test", "--debug", "bootstrap"})
Expect(err).NotTo(HaveOccurred())
cli, err := docker.NewClient(context.TODO())
Expect(err).NotTo(HaveOccurred())
_, err = cli.Destroy(context.TODO(), buildTestName)
Expect(err).NotTo(HaveOccurred())

app = New()
envdApp = app.New()
args := []string{
"envd.test", "--debug", "build", "--path", buildTestName,
}
err = app.Run(args)
err = envdApp.Run(args)
Expect(err).NotTo(HaveOccurred())
})
})
When("given the custom image", func() {
It("should build successfully", func() {
app := New()
err := app.Run([]string{"envd.test", "--debug", "bootstrap"})
envdApp := app.New()
err := envdApp.Run([]string{"envd.test", "--debug", "bootstrap"})
Expect(err).NotTo(HaveOccurred())
cli, err := docker.NewClient(context.TODO())
Expect(err).NotTo(HaveOccurred())
_, err = cli.Destroy(context.TODO(), customImageTestName)
Expect(err).NotTo(HaveOccurred())

app = New()
envdApp = app.New()
args := []string{
"envd.test", "--debug", "build", "--path", customImageTestName,
}
err = app.Run(args)
err = envdApp.Run(args)
Expect(err).NotTo(HaveOccurred())
})
})
AfterAll(func() {
Expect(home.Initialize()).NotTo(HaveOccurred())
app := New()
err := app.Run([]string{"envd.test", "--debug", "bootstrap"})
envdApp := app.New()
err := envdApp.Run([]string{"envd.test", "--debug", "bootstrap"})
Expect(err).NotTo(HaveOccurred())
cli, err := docker.NewClient(context.TODO())
Expect(err).NotTo(HaveOccurred())
Expand Down
7 changes: 4 additions & 3 deletions pkg/app/context_test.go → e2e/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package app
package e2e

import (
"os/exec"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/tensorchord/envd/pkg/app"
"github.com/tensorchord/envd/pkg/home"
"github.com/tensorchord/envd/pkg/types"
)
Expand Down Expand Up @@ -69,8 +70,8 @@ var _ = Describe("home context", func() {

It("should be able to build image with TCP context", func() {
args := []string{"envd.test", "--debug", "build", "--path", buildContext}
app := New()
err := app.Run(args)
envdApp := app.New()
err := envdApp.Run(args)
Expect(err).NotTo(HaveOccurred())
})

Expand Down
140 changes: 140 additions & 0 deletions e2e/e2e_helper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// Copyright 2022 The envd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e

import (
"context"
"strings"

"github.com/sirupsen/logrus"

"github.com/tensorchord/envd/pkg/app"
"github.com/tensorchord/envd/pkg/docker"
"github.com/tensorchord/envd/pkg/ssh"
sshconfig "github.com/tensorchord/envd/pkg/ssh/config"
)

func BuildImage(exampleName string) func() {
return func() {
logrus.Info("building quick-start image")
err := BuildExampleImage(exampleName, app.New())
if err != nil {
panic(err)
}
}
}

func RemoveImage(exampleName string) func() {
return func() {
err := RemoveExampleImage(exampleName)
if err != nil {
panic(err)
}
}
}

func RunContainer(exampleName string) func() {
return func() {
err := RunExampleContainer(exampleName, app.New())
if err != nil {
panic(err)
}
}
}

func DestoryContainer(exampleName string) func() {
return func() {
err := DestroyExampleContainer(exampleName, app.New())
if err != nil {
panic(err)
}
}
}

type Example struct {
Name string
}

func example(name string) *Example {
return &Example{
Name: name,
}
}

func (e *Example) Exec(cmd string) string {
sshClient := getSSHClient(e.Name)
ret, err := sshClient.ExecWithOutput(cmd)
if err != nil {
panic(err)
}
return strings.Trim(string(ret), "\n")
}

func BuildExampleImage(exampleName string, app app.EnvdApp) error {
buildContext := "testdata/" + exampleName
tag := exampleName + ":e2etest"
args := []string{
"envd.test", "--debug", "build", "--path", buildContext, "--tag", tag, "--force",
}
err := app.Run(args)
return err
}

func RemoveExampleImage(exampleName string) error {
ctx := context.TODO()
dockerClient, err := docker.NewClient(ctx)
if err != nil {
return err
}
err = dockerClient.RemoveImage(ctx, exampleName+":e2etest")
if err != nil {
return err
}
return nil
}

func RunExampleContainer(exampleName string, app app.EnvdApp) error {
buildContext := "testdata/" + exampleName
tag := exampleName + ":e2etest"
args := []string{
"envd.test", "--debug", "up", "--path", buildContext, "--tag", tag, "--detach", "--force",
}
err := app.Run(args)
return err
}

func DestroyExampleContainer(exampleName string, app app.EnvdApp) error {
buildContext := "testdata/" + exampleName
args := []string{
"envd.test", "--debug", "destroy", "--path", buildContext,
}
err := app.Run(args)
return err
}

func getSSHClient(exampleName string) ssh.Client {
localhost := "127.0.0.1"
port, err := sshconfig.GetPort(exampleName)
if err != nil {
panic(err)
}
priv_path := sshconfig.GetPrivateKey()
sshClient, err := ssh.NewClient(
localhost, "envd", port, true, priv_path, "")
if err != nil {
panic(err)
}
return sshClient
}
11 changes: 6 additions & 5 deletions pkg/app/get_env_test.go → e2e/get_env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package app
package e2e

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/tensorchord/envd/pkg/app"
"github.com/tensorchord/envd/pkg/home"
)

Expand All @@ -27,14 +28,14 @@ var _ = Describe("get env command", func() {
}
BeforeEach(func() {
Expect(home.Initialize()).NotTo(HaveOccurred())
app := New()
err := app.Run([]string{"envd.test", "--debug", "bootstrap"})
envdApp := app.New()
err := envdApp.Run([]string{"envd.test", "--debug", "bootstrap"})
Expect(err).NotTo(HaveOccurred())
})
When("given the right arguments", func() {
It("should get the environments successfully", func() {
app := New()
err := app.Run(args)
envdApp := app.New()
err := envdApp.Run(args)
Expect(err).NotTo(HaveOccurred())
})
})
Expand Down
31 changes: 31 additions & 0 deletions e2e/quick_start_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2022 The envd Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package e2e

import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("e2e quickstart", Ordered, func() {
exampleName := "quick-start"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should place the example in testdata/.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should place the example in testdata/.

I just want to test all examples

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I could move the extra envd-quick-start to testdata. And other tests shoule be wrote to cover the examples

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

examples may be complex. Personally, I prefer to test different features in different test cases. WDYT

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

BeforeAll(BuildImage(exampleName))
BeforeEach(RunContainer(exampleName))
It("execute python demo.py", func() {
Expect(example(exampleName).Exec("python demo.py")).To(Equal("[2 3 4]"))
})
AfterEach(DestoryContainer(exampleName))
AfterAll(RemoveImage(exampleName))
})
2 changes: 1 addition & 1 deletion pkg/app/suite_test.go → e2e/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package app
package e2e

import (
"testing"
Expand Down
6 changes: 6 additions & 0 deletions e2e/testdata/quick-start/build.envd
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def build():
base(os="ubuntu20.04", language="python3")
install.python_packages(name = [
"numpy",
])
shell("zsh")
5 changes: 5 additions & 0 deletions e2e/testdata/quick-start/demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import numpy as np

a = np.array([2, 3, 4])

print(a)
File renamed without changes.
Loading