Skip to content

Commit f578db3

Browse files
committed
Improve test coverage
1 parent 55cf00b commit f578db3

File tree

11 files changed

+493
-103
lines changed

11 files changed

+493
-103
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,4 @@ coverage.out
77
.DS_Store
88
testdata/server/server
99
dist
10+
test-srv

Gopkg.lock

Lines changed: 11 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
OS := $(shell uname -s)
2-
TEST_PACKAGES := $(shell go list ./...)
3-
COVER_PACKAGES := $(shell go list ./... | paste -sd "," -)
2+
TEST_PACKAGES := $(shell go list ./... | grep -v cmd)
3+
COVER_PACKAGES := $(shell go list ./... | grep -v cmd | paste -sd "," -)
44
LINTER := $(shell command -v gometalinter 2> /dev/null)
55

66
.PHONY: setup

cmd/gaper/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ func main() {
2727
PollInterval: c.Int("poll-interval"),
2828
Extensions: c.StringSlice("extensions"),
2929
NoRestartOn: c.String("no-restart-on"),
30-
ExitOnSIGINT: true,
3130
}
3231
}
3332

@@ -38,7 +37,10 @@ func main() {
3837

3938
app.Action = func(c *cli.Context) {
4039
args := parseArgs(c)
41-
if err := gaper.Run(args); err != nil {
40+
chOSSiginal := make(chan os.Signal, 2)
41+
logger.Verbose(args.Verbose)
42+
43+
if err := gaper.Run(args, chOSSiginal); err != nil {
4244
logger.Error(err)
4345
os.Exit(1)
4446
}

gaper.go

Lines changed: 61 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package gaper
55
import (
66
"fmt"
77
"os"
8-
"os/exec"
98
"os/signal"
109
"path/filepath"
1110
"syscall"
@@ -23,6 +22,13 @@ var DefaultExtensions = []string{"go"}
2322
// DefaultPoolInterval is the time in ms used by the watcher to wait between scans
2423
var DefaultPoolInterval = 500
2524

25+
// No restart types
26+
var (
27+
NoRestartOnError = "error"
28+
NoRestartOnSuccess = "success"
29+
NoRestartOnExit = "exit"
30+
)
31+
2632
var logger = NewLogger("gaper")
2733

2834
// exit statuses
@@ -43,71 +49,53 @@ type Config struct {
4349
Extensions []string
4450
NoRestartOn string
4551
Verbose bool
46-
ExitOnSIGINT bool
52+
WorkingDirectory string
4753
}
4854

49-
// Run in the gaper high level API
50-
// It starts the whole gaper process watching for file changes or exit codes
55+
// Run starts the whole gaper process watching for file changes or exit codes
5156
// and restarting the program
52-
func Run(cfg *Config) error { // nolint: gocyclo
53-
var err error
54-
logger.Verbose(cfg.Verbose)
57+
func Run(cfg *Config, chOSSiginal chan os.Signal) error {
5558
logger.Debug("Starting gaper")
5659

57-
if len(cfg.BuildPath) == 0 {
58-
cfg.BuildPath = DefaultBuildPath
59-
}
60-
61-
cfg.BuildArgs, err = parseInnerArgs(cfg.BuildArgs, cfg.BuildArgsMerged)
62-
if err != nil {
63-
return err
64-
}
65-
66-
cfg.ProgramArgs, err = parseInnerArgs(cfg.ProgramArgs, cfg.ProgramArgsMerged)
67-
if err != nil {
60+
if err := setupConfig(cfg); err != nil {
6861
return err
6962
}
7063

71-
wd, err := os.Getwd()
64+
builder := NewBuilder(cfg.BuildPath, cfg.BinName, cfg.WorkingDirectory, cfg.BuildArgs)
65+
runner := NewRunner(os.Stdout, os.Stderr, filepath.Join(cfg.WorkingDirectory, builder.Binary()), cfg.ProgramArgs)
66+
watcher, err := NewWatcher(cfg.PollInterval, cfg.WatchItems, cfg.IgnoreItems, cfg.Extensions)
7267
if err != nil {
73-
return err
74-
}
75-
76-
if len(cfg.WatchItems) == 0 {
77-
cfg.WatchItems = append(cfg.WatchItems, cfg.BuildPath)
68+
return fmt.Errorf("watcher error: %v", err)
7869
}
7970

80-
builder := NewBuilder(cfg.BuildPath, cfg.BinName, wd, cfg.BuildArgs)
81-
runner := NewRunner(os.Stdout, os.Stderr, filepath.Join(wd, builder.Binary()), cfg.ProgramArgs)
71+
return run(cfg, chOSSiginal, builder, runner, watcher)
72+
}
8273

83-
if err = builder.Build(); err != nil {
74+
func run(cfg *Config, chOSSiginal chan os.Signal, builder Builder, runner Runner, watcher Watcher) error { // nolint: gocyclo
75+
if err := builder.Build(); err != nil {
8476
return fmt.Errorf("build error: %v", err)
8577
}
8678

87-
shutdown(runner, cfg.ExitOnSIGINT)
79+
// listen for OS signals
80+
signal.Notify(chOSSiginal, os.Interrupt, syscall.SIGTERM)
8881

89-
if _, err = runner.Run(); err != nil {
82+
if _, err := runner.Run(); err != nil {
9083
return fmt.Errorf("run error: %v", err)
9184
}
9285

93-
watcher, err := NewWatcher(cfg.PollInterval, cfg.WatchItems, cfg.IgnoreItems, cfg.Extensions)
94-
if err != nil {
95-
return fmt.Errorf("watcher error: %v", err)
96-
}
97-
9886
// flag to know if an exit was caused by a restart from a file changing
9987
changeRestart := false
10088

10189
go watcher.Watch()
10290
for {
10391
select {
104-
case event := <-watcher.Events:
92+
case event := <-watcher.Events():
10593
logger.Debug("Detected new changed file: ", event)
10694
changeRestart = true
10795
if err := restart(builder, runner); err != nil {
10896
return err
10997
}
110-
case err := <-watcher.Errors:
98+
case err := <-watcher.Errors():
11199
return fmt.Errorf("error on watching files: %v", err)
112100
case err := <-runner.Errors():
113101
logger.Debug("Detected program exit: ", err)
@@ -121,6 +109,14 @@ func Run(cfg *Config) error { // nolint: gocyclo
121109
if err = handleProgramExit(builder, runner, err, cfg.NoRestartOn); err != nil {
122110
return err
123111
}
112+
case signal := <-chOSSiginal:
113+
logger.Debug("Got signal: ", signal)
114+
115+
if err := runner.Kill(); err != nil {
116+
logger.Error("Error killing: ", err)
117+
}
118+
119+
return fmt.Errorf("OS signal: %v", signal)
124120
default:
125121
time.Sleep(time.Duration(cfg.PollInterval) * time.Millisecond)
126122
}
@@ -149,49 +145,53 @@ func restart(builder Builder, runner Runner) error {
149145
}
150146

151147
func handleProgramExit(builder Builder, runner Runner, err error, noRestartOn string) error {
152-
var exitStatus int
153-
if exiterr, ok := err.(*exec.ExitError); ok {
154-
status, oks := exiterr.Sys().(syscall.WaitStatus)
155-
if !oks {
156-
return fmt.Errorf("couldn't resolve exit status: %v", err)
157-
}
158-
159-
exitStatus = status.ExitStatus()
160-
}
148+
exitStatus := runner.ExitStatus(err)
161149

162150
// if "error", an exit code of 0 will still restart.
163-
if noRestartOn == "error" && exitStatus == exitStatusError {
151+
if noRestartOn == NoRestartOnError && exitStatus == exitStatusError {
164152
return nil
165153
}
166154

167155
// if "success", no restart only if exit code is 0.
168-
if noRestartOn == "success" && exitStatus == exitStatusSuccess {
156+
if noRestartOn == NoRestartOnSuccess && exitStatus == exitStatusSuccess {
169157
return nil
170158
}
171159

172160
// if "exit", no restart regardless of exit code.
173-
if noRestartOn == "exit" {
161+
if noRestartOn == NoRestartOnExit {
174162
return nil
175163
}
176164

177165
return restart(builder, runner)
178166
}
179167

180-
func shutdown(runner Runner, exitOnSIGINT bool) {
181-
c := make(chan os.Signal, 2)
182-
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
183-
go func() {
184-
s := <-c
185-
logger.Debug("Got signal: ", s)
168+
func setupConfig(cfg *Config) error {
169+
var err error
186170

187-
if err := runner.Kill(); err != nil {
188-
logger.Error("Error killing: ", err)
189-
}
171+
if len(cfg.BuildPath) == 0 {
172+
cfg.BuildPath = DefaultBuildPath
173+
}
190174

191-
if exitOnSIGINT {
192-
os.Exit(0)
193-
}
194-
}()
175+
cfg.BuildArgs, err = parseInnerArgs(cfg.BuildArgs, cfg.BuildArgsMerged)
176+
if err != nil {
177+
return err
178+
}
179+
180+
cfg.ProgramArgs, err = parseInnerArgs(cfg.ProgramArgs, cfg.ProgramArgsMerged)
181+
if err != nil {
182+
return err
183+
}
184+
185+
cfg.WorkingDirectory, err = os.Getwd()
186+
if err != nil {
187+
return err
188+
}
189+
190+
if len(cfg.WatchItems) == 0 {
191+
cfg.WatchItems = append(cfg.WatchItems, cfg.BuildPath)
192+
}
193+
194+
return nil
195195
}
196196

197197
func parseInnerArgs(args []string, argsm string) ([]string, error) {

0 commit comments

Comments
 (0)