Skip to content

Commit

Permalink
refactored --help usage. Also added additional flags unit tests (wip)…
Browse files Browse the repository at this point in the history
…. Updated dockerfile to run daemon in foreground with a fg command
  • Loading branch information
ctomkow committed Aug 16, 2019
1 parent 74a9fef commit 1437ab7
Show file tree
Hide file tree
Showing 6 changed files with 157 additions and 32 deletions.
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ RUN go get "github.com/takama/daemon" && \
go get "github.com/go-sql-driver/mysql" && \
go get "golang.org/x/crypto/ssh"

# compile
COPY . /go/src/github.com/ctomkow/tto
RUN go install

Expand All @@ -32,4 +33,4 @@ RUN mkdir -p /etc/tto && \
mkdir -p /opt/tto
RUN /go/bin/tto install

CMD ["/go/bin/tto"]
CMD ["/go/bin/tto", "fg"]
18 changes: 11 additions & 7 deletions configuration/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,25 @@ package configuration

import (
"errors"
"os"
"flag"
)

type Command struct {
Install bool
Remove bool
Start bool
Stop bool
Status bool
Status bool
Fg bool
}

func (cmd *Command) MakeCmd() error {

if len(os.Args) > 1 {
cmds := os.Args[1]
switch cmds {
if len(flag.Args()) > 1 {
return errors.New("only one command allowed, or flags should be before the command. See --help for more info")
}

switch flag.Arg(0) {
case "install":
cmd.Install = true
case "remove":
Expand All @@ -31,10 +34,11 @@ func (cmd *Command) MakeCmd() error {
cmd.Stop = true
case "status":
cmd.Status = true
case "fg":
cmd.Fg = true
default:
return errors.New("invalid command: " + cmds)
return errors.New("invalid command: " + flag.Arg(0))
}
}

return nil
}
44 changes: 32 additions & 12 deletions configuration/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,35 @@
package configuration

import (
"os"
"flag"
"testing"
)

var argTests = []struct {
input string
var testArgs = []struct {
input []string
expected bool
}{
{"install", true},
{"remove", true},
{"start", true},
{"stop", true},
{"status", true},
{[]string{"install"}, true},
{[]string{"remove"}, true},
{[]string{"start"}, true},
{[]string{"stop"}, true},
{[]string{"status"}, true},
{[]string{"fg"}, true},
{[]string{"derp"}, false},
{[]string{"dum", "dum"}, false},
{[]string{""}, false},
}

func TestCommand_MakeCmd(t *testing.T) {

cmd := new(Command)

for _, argTest := range argTests {
os.Args = []string{"tto", argTest.input}
for _, argTest := range testArgs {

_ = flag.CommandLine.Parse(argTest.input)
err := cmd.MakeCmd()

switch argTest.input {
switch argTest.input[0] {
case "install":
if argTest.expected != cmd.Install {
t.Errorf("Input arg test failed; found, expected: %t, %t", cmd.Install, argTest.expected)
Expand All @@ -48,11 +53,26 @@ func TestCommand_MakeCmd(t *testing.T) {
if argTest.expected != cmd.Status {
t.Errorf("Input arg test failed; found, expected: %t, %t", cmd.Status, argTest.expected)
}
case "fg":
if argTest.expected != cmd.Fg {
t.Errorf("Input arg test failed; found, expected: %t, %t", cmd.Fg, argTest.expected)
}
case "derp":
if err == nil {
t.Errorf("Input arg test failed; found, expected: %#v, %s", err, "nil err")
}
case "dum":
if err == nil {
t.Errorf("Input arg test failed; found, expected: %#v, %s", err, "nil err")
}
case "":
if err == nil {
t.Errorf("Input arg test failed; found, expected: %#v, %s", err, "nil err")
}
default:
if err == nil {
t.Errorf("Input arg test failed; found, expected: %t, %t", cmd.Status, argTest.expected)
}
}

}
}
37 changes: 28 additions & 9 deletions configuration/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,38 @@ package configuration

import (
"flag"
"github.com/golang/glog"
"fmt"
)

// parse -conf flag and return as pointer
func CliFlags() *string {
func ParseFlags() {

// override glog default logging to stderr so daemon managers can read the logs (docker, systemd)
flag.Parse()
}

// set -conf flag and return pointer
func SetConfFlag() *string {

// default conf file
confFlagPtr := flag.String("conf", "conf.json", "name of conf file.")

return confFlagPtr
}

func SetUserUsage(usage string, commands string, flags string) {

flag.Usage = func() {
fmt.Println(usage)
fmt.Print(flags)
fmt.Print(commands)
}
}

func SetLogToStderr() error {

// override glog default logging. Set to stderr so daemon managers can read the logs (docker, systemd)
if err := flag.Set("logtostderr", "true"); err != nil {
glog.Fatal(err)
return err
}
// default conf file
confFilePtr := flag.String("conf", "conf.json", "name of conf file.")

flag.Parse()
return confFilePtr
return nil
}
50 changes: 50 additions & 0 deletions configuration/flags_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Craig Tomkow
// August 16, 2019

package configuration

import (
"flag"
//"os"
"testing"
)

func Test_ParseFlags(t *testing.T) {

ParseFlags()
}

func Test_SetConfFlag(t *testing.T) {

SetConfFlag()

flagPtr := flag.Lookup("conf")
if flagPtr == nil {
t.Errorf("Set conf flag failed; found, expected: %#v, %s", flagPtr, "not nil ptr")
}
}

// TODO: test is currently broken. It doesn't test failure scenarios at all. I thought flag.Usage sends to stderr...
func Test_SetUserUsage(t *testing.T) {

SetUserUsage("usage", "commands", "flags")
flag.Usage()

/*
var errBuff []byte
numOfBytes, _ := os.Stderr.Read(errBuff)
if numOfBytes == 0 {
t.Errorf("Usage test failed; found, expected: %d, %s", numOfBytes, "not zero")
}
*/
}

func Test_SetLogToStderr(t *testing.T) {

if err := SetLogToStderr(); err != nil {
t.Errorf("Set log to stderr test failed; found, expected: %#v, %s", err, "nil err")
}
}
37 changes: 34 additions & 3 deletions tto.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,39 @@ const (
// name of the service
name = "tto"
description = "3-2-1 go!"
usage = "Usage: [flags] (install | remove | start | stop | status | fg)"
flags =
`
--help
prints this message
--conf string
custom named configuration file. default is conf.json
`
commands =
`
install
creates a daemon manager script depending on the service manager (SysV, Systemd, runit)
remove
deletes the daemon manager script that was installed
start
runs the daemon in the background
stop
gracefully stops the daemon
status
displays whether the daemon is running or not
fg
runs the program in the foreground. Needed for process managers to manage the app (docker, supervisord)
`
)

func main() {

configFile := configuration.CliFlags()
if err := configuration.SetLogToStderr(); err != nil {
glog.Fatal(err)
}
configFile := configuration.SetConfFlag()
configuration.SetUserUsage(usage, commands, flags)
configuration.ParseFlags()

var cmd = new(configuration.Command)
if err := cmd.MakeCmd(); err != nil {
Expand Down Expand Up @@ -52,8 +80,6 @@ func main() {

func (srv *Service) Manage(cmd *configuration.Command, configFile *string) (string, error) {

usage := "usage: tto install | remove | start | stop | status"

if cmd.Install {
return srv.Install()

Expand All @@ -69,6 +95,11 @@ func (srv *Service) Manage(cmd *configuration.Command, configFile *string) (stri
} else if cmd.Status {
return srv.Status()

} else if cmd.Fg {
// pass through
glog.Info("running in foreground")
} else {
glog.Fatal(usage)
}

var conf = new(configuration.Config)
Expand Down

0 comments on commit 1437ab7

Please sign in to comment.