Skip to content

Commit 21f818f

Browse files
authored
Merge pull request #2050 from tukobadnyanoba/add-e2e-test
Added e2e tests for port forwarding, reverse port forwarding and uploadExcludePaths
2 parents 2e68d9f + f90f40b commit 21f818f

34 files changed

Lines changed: 15667 additions & 23 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1060,7 +1060,7 @@ This project is mainly written in Golang. If you want to contribute code:
10601060
5. Build the project, e.g. via `go build -o devspace[.exe]`
10611061
6. Evaluate and test your changes `./devspace [SOME_COMMAND]`
10621062

1063-
See [Contributing Guideslines](CONTRIBUTING.md) for more information.
1063+
See [Contributing Guidelines](CONTRIBUTING.md) for more information.
10641064

10651065
<br>
10661066

e2e/e2e_suite_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
_ "github.com/loft-sh/devspace/e2e/tests/imports"
2020
_ "github.com/loft-sh/devspace/e2e/tests/init"
2121
_ "github.com/loft-sh/devspace/e2e/tests/pipelines"
22+
_ "github.com/loft-sh/devspace/e2e/tests/portforward"
2223
_ "github.com/loft-sh/devspace/e2e/tests/proxycommands"
2324
_ "github.com/loft-sh/devspace/e2e/tests/pullsecret"
2425
_ "github.com/loft-sh/devspace/e2e/tests/render"

e2e/framework/helper.go

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,15 @@ package framework
22

33
import (
44
"fmt"
5-
"io/ioutil"
6-
"os"
7-
"strings"
8-
"time"
9-
5+
"github.com/go-resty/resty/v2"
106
"github.com/loft-sh/devspace/e2e/kube"
117
"github.com/onsi/gomega"
128
"github.com/pkg/errors"
9+
"io/ioutil"
1310
"k8s.io/apimachinery/pkg/util/wait"
11+
"os"
12+
"strings"
13+
"time"
1414
)
1515

1616
// ExpectEqual expects the specified two are the same, otherwise an exception raises
@@ -28,7 +28,7 @@ func ExpectError(err error, explain ...interface{}) {
2828
gomega.ExpectWithOffset(1, err).To(gomega.HaveOccurred(), explain...)
2929
}
3030

31-
// ExpectMatchError expects an error happens and has a message matching the given string, otherwise an exception raises
31+
// ExpectErrorMatch ExpectMatchError expects an error happens and has a message matching the given string, otherwise an exception raises
3232
func ExpectErrorMatch(err error, msg string, explain ...interface{}) {
3333
gomega.ExpectWithOffset(1, err).To(gomega.HaveOccurred(), explain...)
3434
gomega.ExpectWithOffset(1, err, explain...).To(gomega.MatchError(msg), explain...)
@@ -75,6 +75,30 @@ func ExpectRemoteFileContents(imageSelector string, namespace string, filePath s
7575
ExpectNoErrorWithOffset(1, err)
7676
}
7777

78+
func ExpectLocalCurlContents(urlString string, contents string) {
79+
client := resty.New()
80+
err := wait.PollImmediate(time.Second, time.Minute*2, func() (done bool, err error) {
81+
resp, _ := client.R().
82+
EnableTrace().
83+
Get(urlString)
84+
return strings.TrimSpace(string(resp.Body())) == strings.TrimSpace(contents), nil
85+
})
86+
ExpectNoErrorWithOffset(1, err)
87+
}
88+
89+
func ExpectRemoteCurlContents(imageSelector string, namespace string, urlString string, contents string) {
90+
kubeClient, err := kube.NewKubeHelper()
91+
ExpectNoErrorWithOffset(1, err)
92+
err = wait.PollImmediate(time.Second, time.Minute*2, func() (done bool, err error) {
93+
out, err := kubeClient.ExecByImageSelector(imageSelector, namespace, []string{"curl", urlString})
94+
if err != nil {
95+
return false, nil
96+
}
97+
return strings.TrimSpace(out) == strings.TrimSpace(contents), nil
98+
})
99+
ExpectNoErrorWithOffset(1, err)
100+
}
101+
78102
func ExpectRemoteFileNotFound(imageSelector string, namespace string, filePath string) {
79103
kubeClient, err := kube.NewKubeHelper()
80104
ExpectNoErrorWithOffset(1, err)

e2e/tests/pipelines/pipelines.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
"github.com/onsi/ginkgo"
1515
)
1616

17-
var _ = DevSpaceDescribe("portforward", func() {
17+
var _ = DevSpaceDescribe("pipelines", func() {
1818
initialDir, err := os.Getwd()
1919
if err != nil {
2020
panic(err)
Lines changed: 72 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,85 @@
11
package portforward
22

33
import (
4+
"context"
5+
"fmt"
6+
"github.com/loft-sh/devspace/cmd"
7+
"github.com/loft-sh/devspace/cmd/flags"
8+
"github.com/loft-sh/devspace/e2e/framework"
9+
"github.com/loft-sh/devspace/e2e/kube"
10+
"github.com/loft-sh/devspace/pkg/util/factory"
411
"github.com/onsi/ginkgo"
12+
"net/http"
13+
"os"
514
)
615

716
var _ = DevSpaceDescribe("portforward", func() {
8-
ginkgo.It("should forward ports", func() {
9-
// TODO
10-
})
17+
initialDir, err := os.Getwd()
18+
if err != nil {
19+
panic(err)
20+
}
1121

12-
ginkgo.It("should restart port forwarding", func() {
13-
// TODO
14-
})
22+
// create a new factory
23+
var (
24+
f factory.Factory
25+
kubeClient *kube.KubeHelper
26+
)
27+
28+
ginkgo.BeforeEach(func() {
29+
f = framework.NewDefaultFactory()
1530

16-
ginkgo.It("should reverse forward ports", func() {
17-
// TODO
31+
kubeClient, err = kube.NewKubeHelper()
32+
framework.ExpectNoError(err)
33+
34+
go func() {
35+
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
36+
_, _ = fmt.Fprintf(w, "Hello World!")
37+
})
38+
fmt.Println("Server started at port 8888")
39+
err := http.ListenAndServe(":8888", nil)
40+
framework.ExpectNoError(err)
41+
}()
1842
})
1943

20-
ginkgo.It("should restart reverse forward ports", func() {
21-
// TODO
44+
ginkgo.It("should forward and reverse forward ports", func() {
45+
tempDir, err := framework.CopyToTempDir("tests/portforward/testdata/portforward-simple")
46+
framework.ExpectNoError(err)
47+
defer framework.CleanupTempDir(initialDir, tempDir)
48+
49+
ns, err := kubeClient.CreateNamespace("portforward")
50+
framework.ExpectNoError(err)
51+
defer framework.ExpectDeleteNamespace(kubeClient, ns)
52+
53+
// create a new dev command and start it
54+
done := make(chan error)
55+
cancelCtx, cancel := context.WithCancel(context.Background())
56+
defer cancel()
57+
58+
go func() {
59+
defer ginkgo.GinkgoRecover()
60+
devCmd := &cmd.RunPipelineCmd{
61+
GlobalFlags: &flags.GlobalFlags{
62+
NoWarn: true,
63+
Namespace: ns,
64+
ConfigPath: "devspace.yaml",
65+
},
66+
Pipeline: "dev",
67+
Ctx: cancelCtx,
68+
}
69+
done <- devCmd.RunDefault(f)
70+
}()
71+
72+
nginxResp := "<!DOCTYPE html>\n<html>\n<head>\n<title>Welcome to nginx!</title>\n<style>\nhtml { color-scheme: light dark; }\nbody { width: 35em; margin: 0 auto;\nfont-family: Tahoma, Verdana, Arial, sans-serif; }\n</style>\n</head>\n<body>\n<h1>Welcome to nginx!</h1>\n<p>If you see this page, the nginx web server is successfully installed and\nworking. Further configuration is required.</p>\n\n<p>For online documentation and support please refer to\n<a href=\"http://nginx.org/\">nginx.org</a>.<br/>\nCommercial support is available at\n<a href=\"http://nginx.com/\">nginx.com</a>.</p>\n\n<p><em>Thank you for using nginx.</em></p>\n</body>\n</html>"
73+
framework.ExpectRemoteCurlContents("nginx", ns, "localhost", nginxResp)
74+
framework.ExpectLocalCurlContents("http://localhost:3000", nginxResp)
75+
76+
httpServerResp := "Hello World!"
77+
framework.ExpectLocalCurlContents("http://localhost:8888", httpServerResp)
78+
framework.ExpectRemoteCurlContents("nginx", ns, "localhost:8888", httpServerResp)
79+
80+
cancel()
81+
err = <-done
82+
framework.ExpectNoError(err)
2283
})
84+
2385
})
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
version: v2beta1
2+
name: portforward-ex
3+
4+
deployments:
5+
app:
6+
helm:
7+
values:
8+
containers:
9+
- image: nginx
10+
# imagePullPolicy: Never
11+
dev:
12+
app:
13+
imageSelector: nginx
14+
ports:
15+
- port: "3000:80"
16+
reversePorts:
17+
- port: "8888:8888"

e2e/tests/sync/sync.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,73 @@ var _ = DevSpaceDescribe("sync", func() {
551551
waitGroup.Wait()
552552
})
553553

554+
ginkgo.It("should sync to a pod container with uploadExcludePaths configuration", func() {
555+
tempDir, err := framework.CopyToTempDir("tests/sync/testdata/sync-exclude-dir")
556+
framework.ExpectNoError(err)
557+
defer framework.CleanupTempDir(initialDir, tempDir)
558+
559+
ns, err := kubeClient.CreateNamespace("sync")
560+
framework.ExpectNoError(err)
561+
defer func() {
562+
err := kubeClient.DeleteNamespace(ns)
563+
framework.ExpectNoError(err)
564+
}()
565+
566+
// deploy app to sync
567+
deployCmd := &cmd.RunPipelineCmd{
568+
GlobalFlags: &flags.GlobalFlags{
569+
NoWarn: true,
570+
Namespace: ns,
571+
ConfigPath: "devspace.yaml",
572+
},
573+
Pipeline: "deploy",
574+
}
575+
err = deployCmd.RunDefault(f)
576+
framework.ExpectNoError(err)
577+
578+
cancelCtx, stop := context.WithCancel(context.Background())
579+
defer stop()
580+
581+
// sync command
582+
syncCmd := &cmd.SyncCmd{
583+
GlobalFlags: &flags.GlobalFlags{
584+
NoWarn: true,
585+
Namespace: ns,
586+
ConfigPath: "devspace.yaml",
587+
},
588+
Wait: true,
589+
Ctx: cancelCtx,
590+
}
591+
592+
// start the command
593+
waitGroup := sync.WaitGroup{}
594+
waitGroup.Add(1)
595+
go func() {
596+
defer ginkgo.GinkgoRecover()
597+
defer waitGroup.Done()
598+
err = syncCmd.Run(f)
599+
framework.ExpectNoError(err)
600+
}()
601+
602+
// check that uploadExcludePaths folder was not synced
603+
framework.ExpectRemoteFileNotFound("alpine", ns, "/app/node_modules")
604+
605+
// check that included file was synced
606+
framework.ExpectRemoteFileContents("alpine", ns, "/app/syncme/file.txt", "I will be synced")
607+
608+
// write a file and check that it got synced
609+
payload := randutil.GenerateRandomString(10000)
610+
err = ioutil.WriteFile(filepath.Join(tempDir, "watching.txt"), []byte(payload), 0666)
611+
framework.ExpectNoError(err)
612+
framework.ExpectRemoteFileContents("alpine", ns, "/app/watching.txt", payload)
613+
614+
// stop command
615+
stop()
616+
617+
// wait for the command to finish
618+
waitGroup.Wait()
619+
})
620+
554621
ginkgo.It("should sync to a pod container with excludeFile, downloadExcludeFile, and uploadExcludeFile configuration", func() {
555622
tempDir, err := framework.CopyToTempDir("tests/sync/testdata/sync-exclude-file")
556623
framework.ExpectNoError(err)
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
version: v2beta1
2+
vars:
3+
IMAGE: alpine
4+
deployments:
5+
test:
6+
helm:
7+
chart:
8+
name: component-chart
9+
repo: https://charts.devspace.sh
10+
values:
11+
containers:
12+
- image: ${IMAGE}
13+
command: ["sleep"]
14+
args: ["999999999999"]
15+
pipelines:
16+
deploy: |-
17+
run_dependencies --all
18+
create_deployments --all
19+
echo "dep2" >> out.txt
20+
dev:
21+
test:
22+
imageSelector: ${IMAGE}
23+
sync:
24+
- path: ./:/app
25+
uploadExcludePaths:
26+
- node_modules/

e2e/tests/sync/testdata/sync-exclude-dir/node_modules/nodemon/nodemon.js

Lines changed: 16 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
I will be synced

0 commit comments

Comments
 (0)