Skip to content

Commit 67f63ff

Browse files
authored
Merge pull request #1968 from lizardruss/e2e-ssh-proxy-commands
Add E2E Tests for SSH and Proxy Commands
2 parents cf1cb71 + d45c0c1 commit 67f63ff

8 files changed

Lines changed: 248 additions & 0 deletions

File tree

e2e/e2e_suite_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@ 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/proxycommands"
2223
_ "github.com/loft-sh/devspace/e2e/tests/pullsecret"
2324
_ "github.com/loft-sh/devspace/e2e/tests/render"
2425
_ "github.com/loft-sh/devspace/e2e/tests/replacepods"
26+
_ "github.com/loft-sh/devspace/e2e/tests/ssh"
2527
_ "github.com/loft-sh/devspace/e2e/tests/sync"
2628
_ "github.com/loft-sh/devspace/e2e/tests/terminal"
2729
)
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package proxycommands
2+
3+
import "github.com/onsi/ginkgo"
4+
5+
// DevSpaceDescribe annotates the test with the label.
6+
func DevSpaceDescribe(text string, body func()) bool {
7+
return ginkgo.Describe("[proxycommands] "+text, body)
8+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package proxycommands
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
"os"
8+
"os/exec"
9+
"time"
10+
11+
"github.com/loft-sh/devspace/cmd"
12+
"github.com/loft-sh/devspace/cmd/flags"
13+
"github.com/loft-sh/devspace/e2e/framework"
14+
"github.com/loft-sh/devspace/e2e/kube"
15+
"github.com/loft-sh/devspace/pkg/util/factory"
16+
"github.com/onsi/ginkgo"
17+
corev1 "k8s.io/api/core/v1"
18+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
19+
"k8s.io/apimachinery/pkg/util/wait"
20+
)
21+
22+
var _ = DevSpaceDescribe("proxyCommands", func() {
23+
initialDir, err := os.Getwd()
24+
if err != nil {
25+
panic(err)
26+
}
27+
28+
// create a new factory
29+
var (
30+
f factory.Factory
31+
kubeClient *kube.KubeHelper
32+
)
33+
34+
ginkgo.BeforeEach(func() {
35+
f = framework.NewDefaultFactory()
36+
37+
kubeClient, err = kube.NewKubeHelper()
38+
framework.ExpectNoError(err)
39+
})
40+
41+
ginkgo.It("devspace dev should proxy commands to host machine", func() {
42+
tempDir, err := framework.CopyToTempDir("tests/proxycommands/testdata/proxycommands-simple")
43+
framework.ExpectNoError(err)
44+
defer framework.CleanupTempDir(initialDir, tempDir)
45+
46+
ns, err := kubeClient.CreateNamespace("proxycommands")
47+
framework.ExpectNoError(err)
48+
defer framework.ExpectDeleteNamespace(kubeClient, ns)
49+
50+
// create a new dev command and start it
51+
done := make(chan error)
52+
cancelCtx, cancel := context.WithCancel(context.Background())
53+
defer cancel()
54+
55+
go func() {
56+
defer ginkgo.GinkgoRecover()
57+
58+
devCmd := &cmd.DevCmd{
59+
GlobalFlags: &flags.GlobalFlags{
60+
NoWarn: true,
61+
Namespace: ns,
62+
},
63+
Ctx: cancelCtx,
64+
}
65+
66+
done <- devCmd.Run(f)
67+
}()
68+
69+
// Check that the command is proxied to the host.
70+
var stdout, stderr bytes.Buffer
71+
cmd := exec.Command("uname", "-n")
72+
cmd.Stdout = &stdout
73+
cmd.Stderr = &stderr
74+
err = cmd.Run()
75+
framework.ExpectNoError(err)
76+
77+
// Get the expected Pod hostname
78+
var pods *corev1.PodList
79+
err = wait.Poll(time.Second, time.Minute, func() (done bool, err error) {
80+
pods, err = kubeClient.RawClient().CoreV1().Pods(ns).List(context.TODO(), metav1.ListOptions{LabelSelector: "app.kubernetes.io/component=test"})
81+
if err != nil {
82+
return false, err
83+
}
84+
fmt.Printf("%+v\n", pods)
85+
return len(pods.Items) > 0, nil
86+
})
87+
framework.ExpectNoError(err)
88+
podName := pods.Items[0].Name
89+
90+
framework.ExpectLocalFileContents("host.out", stdout.String())
91+
framework.ExpectRemoteFileContents("alpine", ns, "container.out", fmt.Sprintf("%s\n", podName))
92+
93+
cancel()
94+
95+
err = <-done
96+
framework.ExpectNoError(err)
97+
})
98+
})
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
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+
dev:
16+
test:
17+
imageSelector: ${IMAGE}
18+
proxyCommands:
19+
- command: host-check
20+
localCommand: ./host-check.sh
21+
22+
pipelines:
23+
dev:
24+
run: |
25+
run_default_pipeline dev
26+
exec_container --image-selector ${IMAGE} -- sh -c 'uname -n > container.out'
27+
exec_container --image-selector ${IMAGE} -- sh -c host-check
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#!/bin/sh
2+
uname -n > host.out

e2e/tests/ssh/framework.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package ssh
2+
3+
import "github.com/onsi/ginkgo"
4+
5+
// DevSpaceDescribe annotates the test with the label.
6+
func DevSpaceDescribe(text string, body func()) bool {
7+
return ginkgo.Describe("[ssh] "+text, body)
8+
}

e2e/tests/ssh/ssh.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package ssh
2+
3+
import (
4+
"context"
5+
"os"
6+
"os/exec"
7+
"time"
8+
9+
"github.com/loft-sh/devspace/cmd"
10+
"github.com/loft-sh/devspace/cmd/flags"
11+
"github.com/loft-sh/devspace/e2e/framework"
12+
"github.com/loft-sh/devspace/e2e/kube"
13+
"github.com/loft-sh/devspace/pkg/util/factory"
14+
"github.com/onsi/ginkgo"
15+
"k8s.io/apimachinery/pkg/util/wait"
16+
)
17+
18+
var _ = DevSpaceDescribe("ssh", func() {
19+
initialDir, err := os.Getwd()
20+
if err != nil {
21+
panic(err)
22+
}
23+
24+
// create a new factory
25+
var (
26+
f factory.Factory
27+
kubeClient *kube.KubeHelper
28+
)
29+
30+
ginkgo.BeforeEach(func() {
31+
f = framework.NewDefaultFactory()
32+
33+
kubeClient, err = kube.NewKubeHelper()
34+
framework.ExpectNoError(err)
35+
})
36+
37+
ginkgo.It("devspace dev should start an SSH service", func() {
38+
tempDir, err := framework.CopyToTempDir("tests/ssh/testdata/ssh-simple")
39+
framework.ExpectNoError(err)
40+
defer framework.CleanupTempDir(initialDir, tempDir)
41+
42+
ns, err := kubeClient.CreateNamespace("ssh")
43+
framework.ExpectNoError(err)
44+
defer framework.ExpectDeleteNamespace(kubeClient, ns)
45+
46+
// create a new dev command and start it
47+
done := make(chan error)
48+
cancelCtx, cancel := context.WithCancel(context.Background())
49+
defer cancel()
50+
51+
go func() {
52+
defer ginkgo.GinkgoRecover()
53+
54+
devCmd := &cmd.DevCmd{
55+
GlobalFlags: &flags.GlobalFlags{
56+
NoWarn: true,
57+
Namespace: ns,
58+
},
59+
Ctx: cancelCtx,
60+
}
61+
62+
done <- devCmd.Run(f)
63+
}()
64+
65+
// connect to the SSH server
66+
err = wait.PollImmediate(time.Second, time.Minute*2, func() (bool, error) {
67+
cmd := exec.Command("ssh", "test.ssh-simple.devspace", "ls")
68+
err := cmd.Run()
69+
if err != nil {
70+
return false, nil
71+
}
72+
73+
return true, nil
74+
})
75+
framework.ExpectNoError(err)
76+
77+
cancel()
78+
79+
err = <-done
80+
framework.ExpectNoError(err)
81+
})
82+
})
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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+
dev:
16+
test:
17+
imageSelector: ${IMAGE}
18+
ssh:
19+
enabled: true
20+
localHostname: test.ssh-simple.devspace
21+
localPort: 10022

0 commit comments

Comments
 (0)