Skip to content

Commit

Permalink
Refactor tstune.Tuner to improve test coverage
Browse files Browse the repository at this point in the history
Replace the call to os.Stat with a call to a global osStatFn var
instead so that a dummy function can be substituted in for testing.
Also, move the initialization of ioHandler into its own function
for testing.
  • Loading branch information
RobAtticus committed Nov 30, 2018
1 parent b125c40 commit 44f1bcb
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 25 deletions.
4 changes: 4 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
coverage:
status:
project: off
patch: off
46 changes: 26 additions & 20 deletions pkg/tstune/tuner.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ const (
)

var (
fileExistsFn = fileExists
osStatFn = os.Stat

pgVersions = []string{"10", "9.6"}
)
Expand All @@ -78,6 +78,16 @@ type Tuner struct {
flags *TunerFlags
}

func (t *Tuner) initializeIOHandler(out io.Writer, outErr io.Writer) {
var p printer
if t.flags.UseColor {
p = &colorPrinter{outErr}
} else {
p = &noColorPrinter{outErr}
}
t.handler = &ioHandler{p: p, out: out, outErr: outErr}
}

// Run executes the tuning process given the provided flags and looks for input
// on the in io.Reader. Informational messages are written to outErr while
// actual recommendations are written to out.
Expand All @@ -86,23 +96,20 @@ func (t *Tuner) Run(flags *TunerFlags, in io.Reader, out io.Writer, outErr io.Wr
if t.flags == nil {
t.flags = &TunerFlags{}
}
var err error
// setup IO
var p printer
if t.flags.UseColor {
p = &colorPrinter{outErr}
} else {
p = &noColorPrinter{outErr}
t.initializeIOHandler(out, outErr)

ifErrHandle := func(err error) {
if err != nil {
t.handler.errorExit(err)
}
}
t.handler = &ioHandler{p: p, out: out, outErr: outErr}
var err error

// attempt to find the config file and open it for reading
fileName := t.flags.ConfPath
if len(fileName) == 0 {
fileName, err = getConfigFilePath(runtime.GOOS)
if err != nil {
t.handler.errorExit(err)
}
ifErrHandle(err)
}

file, err := os.Open(fileName)
Expand All @@ -124,12 +131,6 @@ func (t *Tuner) Run(flags *TunerFlags, in io.Reader, out io.Writer, outErr io.Wr
}
}

ifErrHandle := func(err error) {
if err != nil {
t.handler.errorExit(err)
}
}

// write backup

cfs, err := getConfigFileState(file)
Expand Down Expand Up @@ -177,20 +178,25 @@ func (t *Tuner) Run(flags *TunerFlags, in io.Reader, out io.Writer, outErr io.Wr
}
}

// fileExists is a simple check for stating if a file exists and if any error
// occurs it returns false.
func fileExists(name string) bool {
// for our purposes, any error is a problem, so assume it does not exist
if _, err := os.Stat(name); err != nil {
if _, err := osStatFn(name); err != nil {
return false
}
return true
}

// getConfigFilePath attempts to find the postgresql.conf file using path heuristics
// for different operating systems. If successful it returns the full path to
// the file; otherwise, it returns with an empty path and error.
func getConfigFilePath(os string) (string, error) {
tried := []string{}
try := func(format string, args ...interface{}) string {
fileName := fmt.Sprintf(format, args...)
tried = append(tried, fileName)
if fileExistsFn(fileName) {
if fileExists(fileName) {
return fileName
}
return ""
Expand Down
85 changes: 80 additions & 5 deletions pkg/tstune/tuner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"bytes"
"fmt"
"io"
"os"
"strings"
"testing"

Expand All @@ -16,6 +17,72 @@ func newTunerWithDefaultFlags(handler *ioHandler, cfs *configFileState) *Tuner {
return &Tuner{handler, cfs, &TunerFlags{}}
}

func TestTunerInitializeIOHandler(t *testing.T) {
tuner := &Tuner{nil, nil, &TunerFlags{}}
tuner.flags.UseColor = true
tuner.initializeIOHandler(os.Stdout, os.Stderr)

switch x := tuner.handler.p.(type) {
case *colorPrinter:
default:
t.Errorf("non-color printer for UseColor flag: got %T", x)
}

tuner.flags.UseColor = false
tuner.initializeIOHandler(os.Stdout, os.Stderr)

switch x := tuner.handler.p.(type) {
case *noColorPrinter:
default:
t.Errorf("color printer for UseColor=false flag: got %T", x)
}
}

func TestFileExists(t *testing.T) {
existsName := "exists.txt"
errorName := "error.txt"
cases := []struct {
desc string
filename string
want bool
}{
{
desc: "found file",
filename: existsName,
want: true,
},
{
desc: "not found file",
filename: "ghost.txt",
want: false,
},
{
desc: "error in stat",
filename: errorName,
want: false,
},
}

oldOSStatFn := osStatFn
osStatFn = func(name string) (os.FileInfo, error) {
if name == existsName {
return nil, nil
} else if name == errorName {
return nil, fmt.Errorf("this is an error")
} else {
return nil, os.ErrNotExist
}
}

for _, c := range cases {
if got := fileExists(c.filename); got != c.want {
t.Errorf("%s: incorrect result: got %v want %v", c.desc, got, c.want)
}
}

osStatFn = oldOSStatFn
}

func TestGetConfigFilePath(t *testing.T) {
cases := []struct {
desc string
Expand Down Expand Up @@ -66,6 +133,14 @@ func TestGetConfigFilePath(t *testing.T) {
wantFile: fmt.Sprintf(fileNameDebianFmt, "9.6"),
shouldErr: false,
},
{
desc: "linux - arch",
os: osLinux,
files: []string{fileNameArch},
wantFile: fileNameArch,
shouldErr: false,
},

{
desc: "linux - no",
os: osLinux,
Expand All @@ -75,15 +150,15 @@ func TestGetConfigFilePath(t *testing.T) {
},
}

oldFileExistsFn := fileExistsFn
oldOSStatFn := osStatFn
for _, c := range cases {
fileExistsFn = func(fn string) bool {
osStatFn = func(fn string) (os.FileInfo, error) {
for _, s := range c.files {
if fn == s {
return true
return nil, nil
}
}
return false
return nil, os.ErrNotExist
}
filename, err := getConfigFilePath(c.os)
if err != nil && !c.shouldErr {
Expand All @@ -100,7 +175,7 @@ func TestGetConfigFilePath(t *testing.T) {
t.Errorf("%s: incorrect filename: got %s want %s", c.desc, got, c.wantFile)
}
}
fileExistsFn = oldFileExistsFn
osStatFn = oldOSStatFn
}

type limitChecker struct {
Expand Down

0 comments on commit 44f1bcb

Please sign in to comment.