Skip to content

Commit 43645c0

Browse files
committed
refactor: restart helper
1 parent c570885 commit 43645c0

File tree

11 files changed

+276
-236
lines changed

11 files changed

+276
-236
lines changed

cmd/dev.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,7 @@ type DevCmd struct {
6464
log log.Logger
6565

6666
// used for testing to allow interruption
67-
Ctx context.Context
68-
Stdout io.Writer
69-
Stderr io.Writer
70-
Stdin io.Reader
67+
Ctx context.Context
7168
}
7269

7370
// NewDevCmd creates a new devspace dev command

e2e/tests/terminal/terminal.go

Lines changed: 191 additions & 182 deletions
Original file line numberDiff line numberDiff line change
@@ -1,184 +1,193 @@
11
package terminal
22

3-
// import (
4-
// "bytes"
5-
// "context"
6-
// "io/ioutil"
7-
// "os"
8-
// "strings"
9-
// "sync"
10-
// "time"
11-
12-
// "github.com/loft-sh/devspace/cmd"
13-
// "github.com/loft-sh/devspace/cmd/flags"
14-
// "github.com/loft-sh/devspace/e2e/framework"
15-
// "github.com/loft-sh/devspace/e2e/kube"
16-
// "github.com/loft-sh/devspace/pkg/util/factory"
17-
// "github.com/onsi/ginkgo"
18-
// kerrors "k8s.io/apimachinery/pkg/api/errors"
19-
// metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
20-
// "k8s.io/apimachinery/pkg/util/wait"
21-
// )
22-
23-
// var _ = DevSpaceDescribe("terminal", func() {
24-
// initialDir, err := os.Getwd()
25-
// if err != nil {
26-
// panic(err)
27-
// }
28-
29-
// // create a new factory
30-
// var (
31-
// f factory.Factory
32-
// kubeClient *kube.KubeHelper
33-
// )
34-
35-
// ginkgo.BeforeEach(func() {
36-
// f = framework.NewDefaultFactory()
37-
38-
// kubeClient, err = kube.NewKubeHelper()
39-
// framework.ExpectNoError(err)
40-
// })
41-
42-
// ginkgo.It("should restart terminal", func() {
43-
// tempDir, err := framework.CopyToTempDir("tests/terminal/testdata/restart")
44-
// framework.ExpectNoError(err)
45-
// defer framework.CleanupTempDir(initialDir, tempDir)
46-
47-
// ns, err := kubeClient.CreateNamespace("terminal")
48-
// framework.ExpectNoError(err)
49-
// defer framework.ExpectDeleteNamespace(kubeClient, ns)
50-
51-
// // create a new dev command and start it
52-
// done := make(chan error)
53-
// cancelCtx, cancel := context.WithCancel(context.Background())
54-
// defer cancel()
55-
// stdout := &Buffer{}
56-
// go func() {
57-
// devCmd := &cmd.DevCmd{
58-
// GlobalFlags: &flags.GlobalFlags{
59-
// NoWarn: true,
60-
// Namespace: ns,
61-
// },
62-
// Ctx: cancelCtx,
63-
// Stdout: stdout,
64-
// }
65-
// done <- devCmd.Run(f, []string{"sh", "-c", "while sleep 1; do echo $HOSTNAME; done"})
66-
// }()
67-
68-
// // wait until we get the first hostnames
69-
// var podName string
70-
// err = wait.PollImmediate(time.Second, time.Minute*3, func() (done bool, err error) {
71-
// lines := strings.Split(stdout.String(), "\n")
72-
// if len(lines) <= 1 {
73-
// return false, nil
74-
// }
75-
76-
// podName = lines[0]
77-
// return true, nil
78-
// })
79-
// framework.ExpectNoError(err)
80-
81-
// // make sure the pod exists
82-
// pod, err := kubeClient.RawClient().CoreV1().Pods(ns).Get(context.TODO(), podName, metav1.GetOptions{})
83-
// framework.ExpectNoError(err)
84-
// framework.ExpectEqual(pod.Spec.Containers[0].Image, "ubuntu:18.04")
85-
86-
// // now make a change to the config
87-
// fileContents, err := ioutil.ReadFile("devspace.yaml")
88-
// framework.ExpectNoError(err)
89-
// newString := strings.Replace(string(fileContents), "ubuntu:18.04", "alpine:3.14", -1)
90-
// newString = strings.Replace(newString, "container-0", "container-1", -1)
91-
// err = ioutil.WriteFile("devspace.yaml", []byte(newString), 0666)
92-
// framework.ExpectNoError(err)
93-
94-
// // wait until pod is terminated
95-
// err = wait.PollImmediate(time.Second, time.Minute*3, func() (done bool, err error) {
96-
// _, err = kubeClient.RawClient().CoreV1().Pods(ns).Get(context.TODO(), podName, metav1.GetOptions{})
97-
// if err != nil {
98-
// if kerrors.IsNotFound(err) {
99-
// return true, nil
100-
// }
101-
102-
// return false, err
103-
// }
104-
105-
// return false, nil
106-
// })
107-
// framework.ExpectNoError(err)
108-
109-
// // get new pod name
110-
// err = wait.PollImmediate(time.Second, time.Minute*3, func() (done bool, err error) {
111-
// lines := strings.Split(stdout.String(), "\n")
112-
// if len(lines) <= 1 {
113-
// return false, nil
114-
// }
115-
116-
// newPodName := lines[len(lines)-2]
117-
// if newPodName != podName {
118-
// podName = newPodName
119-
// return true, nil
120-
// }
121-
122-
// return false, nil
123-
// })
124-
// framework.ExpectNoError(err)
125-
126-
// // make sure the pod exists
127-
// pod, err = kubeClient.RawClient().CoreV1().Pods(ns).Get(context.TODO(), podName, metav1.GetOptions{})
128-
// framework.ExpectNoError(err)
129-
// framework.ExpectEqual(pod.Spec.Containers[0].Image, "alpine:3.14")
130-
// framework.ExpectEqual(pod.Spec.Containers[0].Name, "container-1")
131-
132-
// // make sure command terminates correctly
133-
// cancel()
134-
// err = <-done
135-
// framework.ExpectNoError(err)
136-
// })
137-
138-
// ginkgo.It("should run command locally", func() {
139-
// tempDir, err := framework.CopyToTempDir("tests/terminal/testdata/run_cmd_locally")
140-
// framework.ExpectNoError(err)
141-
// defer framework.CleanupTempDir(initialDir, tempDir)
142-
143-
// ns, err := kubeClient.CreateNamespace("terminal")
144-
// framework.ExpectNoError(err)
145-
// defer framework.ExpectDeleteNamespace(kubeClient, ns)
146-
147-
// cancelCtx, cancel := context.WithCancel(context.Background())
148-
// defer cancel()
149-
// stdout := &Buffer{}
150-
// devCmd := &cmd.DevCmd{
151-
// GlobalFlags: &flags.GlobalFlags{
152-
// NoWarn: true,
153-
// Namespace: ns,
154-
// },
155-
// Ctx: cancelCtx,
156-
// Stdout: stdout,
157-
// }
158-
// err = devCmd.Run(f, nil)
159-
// framework.ExpectNoError(err)
160-
// framework.ExpectEqual("hello", strings.TrimSuffix(stdout.String(), "\n"))
161-
// })
162-
// })
163-
164-
// // Buffer is a goroutine safe bytes.Buffer
165-
// type Buffer struct {
166-
// buffer bytes.Buffer
167-
// mutex sync.Mutex
168-
// }
169-
170-
// // Write appends the contents of p to the buffer, growing the buffer as needed. It returns
171-
// // the number of bytes written.
172-
// func (s *Buffer) Write(p []byte) (n int, err error) {
173-
// s.mutex.Lock()
174-
// defer s.mutex.Unlock()
175-
// return s.buffer.Write(p)
176-
// }
177-
178-
// // String returns the contents of the unread portion of the buffer
179-
// // as a string. If the Buffer is a nil pointer, it returns "<nil>".
180-
// func (s *Buffer) String() string {
181-
// s.mutex.Lock()
182-
// defer s.mutex.Unlock()
183-
// return s.buffer.String()
184-
// }
3+
import (
4+
"bytes"
5+
"context"
6+
"fmt"
7+
"github.com/loft-sh/devspace/cmd"
8+
"github.com/loft-sh/devspace/cmd/flags"
9+
"github.com/loft-sh/devspace/e2e/framework"
10+
"github.com/loft-sh/devspace/e2e/kube"
11+
"github.com/loft-sh/devspace/pkg/devspace/devpod"
12+
"github.com/loft-sh/devspace/pkg/util/factory"
13+
"github.com/onsi/ginkgo"
14+
"io/ioutil"
15+
kerrors "k8s.io/apimachinery/pkg/api/errors"
16+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
17+
"k8s.io/apimachinery/pkg/util/wait"
18+
"os"
19+
"path/filepath"
20+
"strings"
21+
"sync"
22+
"time"
23+
)
24+
25+
var _ = DevSpaceDescribe("terminal", func() {
26+
initialDir, err := os.Getwd()
27+
if err != nil {
28+
panic(err)
29+
}
30+
31+
// create a new factory
32+
var (
33+
f factory.Factory
34+
kubeClient *kube.KubeHelper
35+
)
36+
37+
ginkgo.BeforeEach(func() {
38+
f = framework.NewDefaultFactory()
39+
40+
kubeClient, err = kube.NewKubeHelper()
41+
framework.ExpectNoError(err)
42+
})
43+
44+
ginkgo.FIt("should restart terminal", func() {
45+
tempDir, err := framework.CopyToTempDir("tests/terminal/testdata/restart")
46+
framework.ExpectNoError(err)
47+
defer framework.CleanupTempDir(initialDir, tempDir)
48+
49+
ns, err := kubeClient.CreateNamespace("terminal")
50+
framework.ExpectNoError(err)
51+
defer framework.ExpectDeleteNamespace(kubeClient, ns)
52+
53+
buffer := &bytes.Buffer{}
54+
devpod.DefaultTerminalStdout = buffer
55+
devpod.DefaultTerminalStderr = buffer
56+
devpod.DefaultTerminalStdin = nil
57+
defer func() {
58+
devpod.DefaultTerminalStdout = os.Stdout
59+
devpod.DefaultTerminalStderr = os.Stderr
60+
devpod.DefaultTerminalStdin = os.Stdin
61+
}()
62+
63+
// create a new dev command and start it
64+
done := make(chan error)
65+
cancelCtx, cancel := context.WithCancel(context.Background())
66+
defer cancel()
67+
go func() {
68+
devCmd := &cmd.DevCmd{
69+
GlobalFlags: &flags.GlobalFlags{
70+
NoWarn: true,
71+
Namespace: ns,
72+
},
73+
Ctx: cancelCtx,
74+
}
75+
done <- devCmd.Run(f)
76+
}()
77+
78+
// wait until we get the first hostnames
79+
var podName string
80+
err = wait.PollImmediate(time.Second, time.Minute*3, func() (done bool, err error) {
81+
fmt.Println(buffer.String())
82+
lines := strings.Split(buffer.String(), "\n")
83+
if len(lines) <= 1 {
84+
return false, nil
85+
}
86+
87+
podName = lines[0]
88+
return true, nil
89+
})
90+
framework.ExpectNoError(err)
91+
92+
// make sure the pod exists
93+
pod, err := kubeClient.RawClient().CoreV1().Pods(ns).Get(context.TODO(), podName, metav1.GetOptions{})
94+
framework.ExpectNoError(err)
95+
framework.ExpectEqual(pod.Spec.Containers[0].Image, "ubuntu:18.04")
96+
97+
// now make a change to the config
98+
fileContents, err := ioutil.ReadFile("devspace.yaml")
99+
framework.ExpectNoError(err)
100+
newString := strings.Replace(string(fileContents), "ubuntu:18.04", "alpine:3.14", -1)
101+
newString = strings.Replace(newString, "container-0", "container-1", -1)
102+
err = ioutil.WriteFile("devspace.yaml", []byte(newString), 0666)
103+
framework.ExpectNoError(err)
104+
105+
// wait until pod is terminated
106+
err = wait.PollImmediate(time.Second, time.Minute*3, func() (done bool, err error) {
107+
_, err = kubeClient.RawClient().CoreV1().Pods(ns).Get(context.TODO(), podName, metav1.GetOptions{})
108+
if err != nil {
109+
if kerrors.IsNotFound(err) {
110+
return true, nil
111+
}
112+
113+
return false, err
114+
}
115+
116+
return false, nil
117+
})
118+
framework.ExpectNoError(err)
119+
120+
// get new pod name
121+
err = wait.PollImmediate(time.Second, time.Minute*3, func() (done bool, err error) {
122+
lines := strings.Split(buffer.String(), "\n")
123+
if len(lines) <= 1 {
124+
return false, nil
125+
}
126+
127+
newPodName := lines[len(lines)-2]
128+
if newPodName != podName {
129+
podName = newPodName
130+
return true, nil
131+
}
132+
133+
return false, nil
134+
})
135+
framework.ExpectNoError(err)
136+
137+
// make sure the pod exists
138+
pod, err = kubeClient.RawClient().CoreV1().Pods(ns).Get(context.TODO(), podName, metav1.GetOptions{})
139+
framework.ExpectNoError(err)
140+
framework.ExpectEqual(pod.Spec.Containers[0].Image, "alpine:3.14")
141+
framework.ExpectEqual(pod.Spec.Containers[0].Name, "container-1")
142+
143+
// make sure command terminates correctly
144+
cancel()
145+
err = <-done
146+
framework.ExpectNoError(err)
147+
})
148+
149+
ginkgo.It("should run command locally", func() {
150+
tempDir, err := framework.CopyToTempDir("tests/terminal/testdata/run_cmd_locally")
151+
framework.ExpectNoError(err)
152+
defer framework.CleanupTempDir(initialDir, tempDir)
153+
154+
ns, err := kubeClient.CreateNamespace("terminal")
155+
framework.ExpectNoError(err)
156+
defer framework.ExpectDeleteNamespace(kubeClient, ns)
157+
158+
cancelCtx, cancel := context.WithCancel(context.Background())
159+
defer cancel()
160+
devCmd := &cmd.DevCmd{
161+
GlobalFlags: &flags.GlobalFlags{
162+
NoWarn: true,
163+
Namespace: ns,
164+
},
165+
Ctx: cancelCtx,
166+
}
167+
err = devCmd.Run(f)
168+
framework.ExpectNoError(err)
169+
framework.ExpectLocalFileContentsImmediately(filepath.Join(tempDir, "terminal-done.txt"), "Hello World!\n")
170+
})
171+
})
172+
173+
// Buffer is a goroutine safe bytes.Buffer
174+
type Buffer struct {
175+
buffer bytes.Buffer
176+
mutex sync.Mutex
177+
}
178+
179+
// Write appends the contents of p to the buffer, growing the buffer as needed. It returns
180+
// the number of bytes written.
181+
func (s *Buffer) Write(p []byte) (n int, err error) {
182+
s.mutex.Lock()
183+
defer s.mutex.Unlock()
184+
return s.buffer.Write(p)
185+
}
186+
187+
// String returns the contents of the unread portion of the buffer
188+
// as a string. If the Buffer is a nil pointer, it returns "<nil>".
189+
func (s *Buffer) String() string {
190+
s.mutex.Lock()
191+
defer s.mutex.Unlock()
192+
return s.buffer.String()
193+
}

0 commit comments

Comments
 (0)