Skip to content

Commit 4e7f799

Browse files
Inject io.Writer for fmt to write to. So much easier to handle in tests
1 parent 608d5e2 commit 4e7f799

File tree

3 files changed

+47
-40
lines changed

3 files changed

+47
-40
lines changed

ctlcmds.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,7 @@
2121

2222
package main
2323

24-
import (
25-
"fmt"
26-
"strings"
27-
)
24+
import "strings"
2825

2926
// ctlCmd Defines methods common for svctl meta-commands, i.e. ones
3027
// that are not sent to runit, but executed locally.
@@ -91,9 +88,9 @@ func (c *ctlCmdHelp) Run(ctl *ctl, params []string) bool {
9188
for _, param := range params[1:] {
9289
cmd := cmdMatch(param)
9390
if cmd == nil {
94-
fmt.Printf("%s: unable to find action\n", param)
91+
ctl.printf("%s: unable to find action\n", param)
9592
} else {
96-
fmt.Println(cmd.Help())
93+
ctl.println(cmd.Help())
9794
}
9895
}
9996
return false

svctl.go

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,13 @@ func (s *status) Errored() bool {
146146
type ctl struct {
147147
line *liner.State
148148
basedir string
149+
stdout io.Writer
149150
}
150151

151152
// newCtl Creates new ctl instance.
152153
// Initializes input prompt, reads history, reads $SVDIR.
153-
func newCtl() *ctl {
154-
c := &ctl{line: liner.NewLiner()}
154+
func newCtl(stdout io.Writer) *ctl {
155+
c := &ctl{line: liner.NewLiner(), stdout: stdout}
155156

156157
fn, _ := xdg.DataFile("svctl/hist")
157158
if f, err := os.Open(fn); err == nil {
@@ -207,6 +208,14 @@ func (c *ctl) completer(line string, pos int) (h string, compl []string, t strin
207208
return
208209
}
209210

211+
func (c *ctl) printf(format string, a ...interface{}) {
212+
fmt.Fprintf(c.stdout, format, a...)
213+
}
214+
215+
func (c *ctl) println(a ...interface{}) {
216+
fmt.Fprintln(c.stdout, a...)
217+
}
218+
210219
// serviceName Returns name of the service, i.e. directory chain relative to current base.
211220
func (c *ctl) serviceName(dir string) string {
212221
if name, err := filepath.Rel(c.basedir, dir); err == nil {
@@ -256,7 +265,7 @@ func (c *ctl) Status(id string, toLog bool) {
256265
}
257266
for _, status := range statuses {
258267
status.Offsets = statuses[0].Offsets
259-
fmt.Println(status)
268+
c.println(status)
260269
}
261270
}
262271

@@ -281,12 +290,12 @@ func (c *ctl) ctl(action []byte, service string, start uint64, wg *sync.WaitGrou
281290

282291
status := newStatus(service, c.serviceName(service))
283292
if status.Errored() {
284-
fmt.Println(status)
293+
c.println(status)
285294
return
286295
}
287296
if status.CheckControl(action) {
288297
if err := c.control(action, service); err != nil {
289-
fmt.Println(err)
298+
c.println(err)
290299
return
291300
}
292301
}
@@ -296,13 +305,13 @@ func (c *ctl) ctl(action []byte, service string, start uint64, wg *sync.WaitGrou
296305
for {
297306
select {
298307
case <-timeout:
299-
fmt.Print("TIMEOUT: ")
308+
c.printf("TIMEOUT: ")
300309
c.Status(service, false)
301310
return
302311
case <-tick:
303312
status := newStatus(service, c.serviceName(service))
304313
if status.Check(action, start) {
305-
fmt.Println(status)
314+
c.println(status)
306315
return
307316
}
308317
}
@@ -326,7 +335,7 @@ func (c *ctl) Ctl(cmdStr string) bool {
326335
return ctlCmd.Run(c, params)
327336
}
328337
if cmd == nil {
329-
fmt.Printf("%s: unable to find action\n", params[0])
338+
c.printf("%s: unable to find action\n", params[0])
330339
return false
331340
}
332341
action := cmd.Action()
@@ -341,7 +350,7 @@ func (c *ctl) Ctl(cmdStr string) bool {
341350
}
342351
services := c.Services(param, false)
343352
if len(services) == 0 {
344-
fmt.Printf("%s: unable to find service\n", param)
353+
c.printf("%s: unable to find service\n", param)
345354
continue
346355
}
347356
for _, service := range services {
@@ -359,7 +368,7 @@ func (c *ctl) Ctl(cmdStr string) bool {
359368
func (c *ctl) Run() bool {
360369
cmd, err := c.line.Prompt("svctl> ")
361370
if err == io.EOF {
362-
fmt.Println()
371+
c.println()
363372
return true
364373
} else if err != nil {
365374
log.Printf("error reading prompt contents: %s\n", err)
@@ -370,7 +379,7 @@ func (c *ctl) Run() bool {
370379

371380
// main Creates svctl entry point, prints all processes statuses and launches event loop.
372381
func main() {
373-
ctl := newCtl()
382+
ctl := newCtl(os.Stdout)
374383
defer ctl.Close()
375384
ctl.Status("*", true)
376385
for !ctl.Run() {

svctl_test.go

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
package main
2323

2424
import (
25-
"bufio"
2625
"fmt"
2726
"io/ioutil"
2827
"os"
@@ -54,6 +53,21 @@ func equal(s1, s2 []string) bool {
5453
return true
5554
}
5655

56+
type stdout struct {
57+
value []string
58+
}
59+
60+
func (s *stdout) Write(p []byte) (n int, err error) {
61+
s.value = append(s.value, string(p)[:len(p)-1])
62+
return len(p), nil
63+
}
64+
65+
func (s *stdout) ReadString() string {
66+
v := s.value[0]
67+
s.value = s.value[1:]
68+
return v
69+
}
70+
5771
func createRunitDir() string {
5872
dir, err := ioutil.TempDir("", "svctl_tests")
5973
fatal(err)
@@ -67,8 +81,7 @@ type runitRunner struct {
6781
runsvdir *exec.Cmd
6882
zs map[string]int
6983

70-
stdout *bufio.Reader
71-
realStdout *os.File
84+
stdout *stdout
7285
}
7386

7487
func newRunitRunner() *runitRunner {
@@ -77,14 +90,9 @@ func newRunitRunner() *runitRunner {
7790
r := &runitRunner{
7891
basedir: path.Join(dir, "_testdata"),
7992
zs: map[string]int{"r0": 0, "r1": 0, "o": 0},
93+
stdout: &stdout{},
8094
}
8195

82-
stdr, stdw, err := os.Pipe()
83-
fatal(err)
84-
r.stdout = bufio.NewReader(stdr)
85-
r.realStdout = os.Stdout
86-
os.Stdout = stdw
87-
8896
r.runsvdir = exec.Command("runsvdir", "-P", r.basedir)
8997
fatal(r.runsvdir.Start())
9098
// Make sure runsvdir has enough time to scan the directories
@@ -97,17 +105,11 @@ func (r *runitRunner) Close() {
97105
r.runsvdir.Process.Signal(syscall.SIGHUP)
98106
r.runsvdir.Process.Wait()
99107
os.RemoveAll(path.Dir(r.basedir))
100-
os.Stdout.Close()
101-
os.Stdout = r.realStdout
102108
}
103109

104110
func (r *runitRunner) Assert(t *testing.T, cmd *cmdDef) {
105111
for _, service := range cmd.services {
106-
stdout, err := r.stdout.ReadString('\n')
107-
if err != nil {
108-
t.Errorf("ERROR READING `stdout`: `%s`", err)
109-
continue
110-
}
112+
stdout := r.stdout.ReadString()
111113
pieces := strings.Split(stdout, " ")
112114
if !contains(cmd.services, pieces[0]) {
113115
t.Errorf(
@@ -172,12 +174,7 @@ func (r *runitRunner) Assert(t *testing.T, cmd *cmdDef) {
172174
}
173175

174176
func (r *runitRunner) AssertError(t *testing.T, msg string) {
175-
stdout, err := r.stdout.ReadString('\n')
176-
if err != nil {
177-
t.Errorf("ERROR READING `stdout`: `%s`", err)
178-
return
179-
}
180-
stdout = stdout[:len(stdout)-1]
177+
stdout := r.stdout.ReadString()
181178
if stdout != msg {
182179
t.Errorf("ERROR IN STATUS: `%s` != `%s`", stdout, msg)
183180
}
@@ -192,7 +189,11 @@ type cmdDef struct {
192189

193190
func TestCmd(t *testing.T) {
194191
runit := newRunitRunner()
195-
svctl := ctl{basedir: runit.basedir, line: liner.NewLiner()}
192+
svctl := ctl{
193+
line: liner.NewLiner(),
194+
basedir: runit.basedir,
195+
stdout: runit.stdout,
196+
}
196197

197198
// Tests for correct usage.
198199
cmds := []cmdDef{

0 commit comments

Comments
 (0)