Skip to content

Commit 799d077

Browse files
authored
Improve test coverage for cmd package (#53)
* add test for runServerCmd * update NewDependencies test tp return err if dependencies are not valid * return err if dependencies are not valid * create new cobra command with SetupSignalHandler * refactor server Start with SetupSignalHandler for testable code * add test for root cmd * refactor root cmd * add test for setupSignalHandler * implement SetupSignalHandler * add newRunCmdWithOpts to rootCmd with SetupSignalHandler * add test for LifeCycleHook * refactor if-else statement * remove signals package and import it from sigs.k8s.io/controller-runtime * add version cmd to root * remove TDD cycle comments
1 parent 28e6dc1 commit 799d077

File tree

16 files changed

+561
-149
lines changed

16 files changed

+561
-149
lines changed

cmd/root.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,24 @@ package cmd
22

33
import (
44
"github.com/spf13/cobra"
5+
"sigs.k8s.io/controller-runtime/pkg/manager/signals"
56
)
67

7-
var rootCmd = &cobra.Command{
8-
Use: "darkroom",
9-
Short: "Darkroom is an Image Proxy on your image source",
8+
// newRootCmd represents the base command when called without any subcommands.
9+
func newRootCmd() *cobra.Command {
10+
cmd := &cobra.Command{
11+
Use: "darkroom",
12+
Short: "Darkroom is an Image Proxy on your image source",
13+
}
14+
cmd.AddCommand(newRunCmdWithOpts(runCmdOpts{
15+
SetupSignalHandler: signals.SetupSignalHandler,
16+
}))
17+
cmd.AddCommand(newVersionCmd())
18+
return cmd
1019
}
1120

12-
func init() {
13-
rootCmd.AddCommand(serverCmd)
14-
rootCmd.AddCommand(newVersionCmd())
15-
}
16-
17-
// Run function lets you run the commands
18-
func Run(args []string) error {
19-
rootCmd.SetArgs(args)
20-
return rootCmd.Execute()
21+
// Execute adds all child commands to the root command and sets flags appropriately.
22+
// This is called by main.main(). It only needs to happen once to the rootCmd.
23+
func Execute() error {
24+
return newRootCmd().Execute()
2125
}

cmd/root_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package cmd
2+
3+
import (
4+
"github.com/stretchr/testify/assert"
5+
"testing"
6+
)
7+
8+
func TestRootCmd(t *testing.T) {
9+
err := Execute()
10+
assert.NoError(t, err)
11+
}

cmd/server.go

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,36 @@
11
package cmd
22

33
import (
4-
"github.com/gojek/darkroom/pkg/logger"
54
"github.com/gojek/darkroom/pkg/router"
65
"github.com/gojek/darkroom/pkg/server"
76
"github.com/gojek/darkroom/pkg/service"
87
"github.com/spf13/cobra"
98
)
109

11-
var serverCmd = &cobra.Command{
12-
Use: "server",
13-
Short: "Start the app server",
14-
Run: serverCmdF,
10+
type runCmdOpts struct {
11+
SetupSignalHandler func() (stopCh <-chan struct{})
1512
}
1613

17-
func serverCmdF(cmd *cobra.Command, args []string) {
18-
defer func() {
19-
if e := recover(); e != nil {
20-
logger.Errorf("failed to start the app due to error: %s", e)
21-
}
22-
}()
23-
startServer()
24-
}
25-
26-
func startServer() {
27-
handler := router.NewRouter(service.NewDependencies())
28-
s := server.NewServer(server.WithHandler(handler))
29-
s.Start()
14+
func newRunCmdWithOpts(opts runCmdOpts) *cobra.Command {
15+
args := struct {
16+
port int
17+
}{}
18+
cmd := &cobra.Command{
19+
Use: "server",
20+
Short: "Start the app server",
21+
RunE: func(cmd *cobra.Command, _ []string) error {
22+
deps, err := service.NewDependencies()
23+
if err != nil {
24+
return err
25+
}
26+
handler := router.NewRouter(deps)
27+
s := server.NewServer(server.Options{
28+
Handler: handler,
29+
Port: args.port,
30+
})
31+
return s.Start(opts.SetupSignalHandler())
32+
},
33+
}
34+
cmd.PersistentFlags().IntVarP(&args.port, "port", "p", 3000, "server port")
35+
return cmd
3036
}

cmd/server_test.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"github.com/gojek/darkroom/pkg/config"
6+
"github.com/stretchr/testify/assert"
7+
"net/http"
8+
"testing"
9+
"time"
10+
)
11+
12+
func TestRunServer(t *testing.T) {
13+
errCh := make(chan error)
14+
stopCh := make(chan struct{})
15+
diagnosticsPort := 9999
16+
v := config.Viper()
17+
v.Set("source.kind", "WebFolder")
18+
v.Set("source.baseURL", "https://example.com/path/to/folder")
19+
config.Update()
20+
21+
cmd := newRunCmdWithOpts(runCmdOpts{
22+
SetupSignalHandler: func() <-chan struct{} {
23+
return stopCh
24+
},
25+
})
26+
cmd.SetArgs([]string{"-p", fmt.Sprintf("%d", diagnosticsPort)})
27+
28+
go func() {
29+
defer close(errCh)
30+
errCh <- cmd.Execute()
31+
}()
32+
33+
assert.True(t, assert.Eventually(t, func() bool {
34+
resp, err := http.Get(fmt.Sprintf("http://localhost:%d/ping", diagnosticsPort))
35+
if err != nil {
36+
return false
37+
}
38+
defer func() {
39+
_ = resp.Body.Close()
40+
}()
41+
return resp.StatusCode == http.StatusOK
42+
}, 5*time.Second, 100*time.Millisecond), "failed to run server")
43+
44+
close(stopCh)
45+
46+
assert.NoError(t, <-errCh)
47+
}
48+
49+
func TestRunServerWithInvalidPort(t *testing.T) {
50+
errCh := make(chan error)
51+
stopCh := make(chan struct{})
52+
v := config.Viper()
53+
v.Set("source.kind", "WebFolder")
54+
v.Set("source.baseURL", "https://example.com/path/to/folder")
55+
config.Update()
56+
57+
cmd := newRunCmdWithOpts(runCmdOpts{
58+
SetupSignalHandler: func() <-chan struct{} {
59+
return stopCh
60+
},
61+
})
62+
cmd.SetArgs([]string{"-p", fmt.Sprintf("%d", -9000)})
63+
64+
go func() {
65+
defer close(errCh)
66+
errCh <- cmd.Execute()
67+
}()
68+
69+
assert.Error(t, <-errCh)
70+
}
71+
72+
func TestRunServerWithInvalidDependencies(t *testing.T) {
73+
errCh := make(chan error)
74+
stopCh := make(chan struct{})
75+
v := config.Viper()
76+
v.Set("source.kind", "")
77+
v.Set("source.baseURL", "")
78+
config.Update()
79+
80+
cmd := newRunCmdWithOpts(runCmdOpts{
81+
SetupSignalHandler: func() <-chan struct{} {
82+
return stopCh
83+
},
84+
})
85+
86+
go func() {
87+
defer close(errCh)
88+
errCh <- cmd.Execute()
89+
}()
90+
91+
assert.EqualError(t, <-errCh, "handler dependencies are not valid")
92+
}

go.mod

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,10 @@ require (
1818
github.com/rcrowley/go-metrics v0.0.0-20190706150252-9beb055b7962 // indirect
1919
github.com/smartystreets/assertions v1.0.0 // indirect
2020
github.com/smartystreets/goconvey v0.0.0-20190710185942-9d28bd7c0945 // indirect
21-
github.com/spf13/afero v1.2.2 // indirect
2221
github.com/spf13/cobra v0.0.5
2322
github.com/spf13/jwalterweatherman v1.1.0 // indirect
2423
github.com/spf13/viper v1.4.0
25-
github.com/stretchr/objx v0.2.0 // indirect
26-
github.com/stretchr/testify v1.3.0
24+
github.com/stretchr/testify v1.6.1
2725
go.uber.org/zap v1.10.0
28-
golang.org/x/net v0.0.0-20190628185345-da137c7871d7 // indirect
29-
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7 // indirect
30-
golang.org/x/text v0.3.2 // indirect
26+
sigs.k8s.io/controller-runtime v0.6.1
3127
)

0 commit comments

Comments
 (0)