From 9c0dde616bcaedeeaf99c5dd17eb674c8270c508 Mon Sep 17 00:00:00 2001 From: Marc Di Luzio Date: Sat, 6 Jun 2020 00:01:59 +0100 Subject: [PATCH] Refactor to implement integration testing for rove --- cmd/rove/main.go | 136 ++++++++++++++++++----------------- cmd/rove/main_test.go | 55 ++++++++++++++ pkg/rove/integration_test.go | 2 + 3 files changed, 128 insertions(+), 65 deletions(-) create mode 100644 cmd/rove/main_test.go diff --git a/cmd/rove/main.go b/cmd/rove/main.go index 8485c54..2ee7f44 100644 --- a/cmd/rove/main.go +++ b/cmd/rove/main.go @@ -35,43 +35,38 @@ var data = flag.String("data", filepath, "data file for storage") // Config is used to store internal data type Config struct { - Account string `json:"account,omitempty"` - Host string `json:"host,omitempty"` + Host string `json:"host,omitempty"` + Accounts map[string]string `json:"accounts,omitempty"` } var name = flag.String("name", "", "used with status command for the account name") -func verifyId(d Config) { - if len(d.Account) == 0 { - fmt.Fprintf(os.Stderr, "No account ID set, must register first or set \"account\" value in %s\n", *data) - os.Exit(1) +// verifyId will verify an account ID +func verifyId(id string) error { + if len(id) == 0 { + return fmt.Errorf("no account ID set, must register first") } + return nil } -func main() { - flag.Usage = Usage - flag.Parse() - - // Verify we have a single command line arg - args := flag.Args() - if len(args) != 1 { - Usage() - os.Exit(1) - } +// InnerMain wraps the main function so we can test it +func InnerMain(command string) error { // Load in the persistent file - var config = Config{} + var config = Config{ + Accounts: make(map[string]string), + } _, err := os.Stat(*data) if !os.IsNotExist(err) { if b, err := ioutil.ReadFile(*data); err != nil { - fmt.Fprintf(os.Stderr, "failed to read file %s error: %s\n", *data, err) - os.Exit(1) + return fmt.Errorf("failed to read file %s error: %s", *data, err) + } else if len(b) == 0 { - fmt.Fprintf(os.Stderr, "file %s was empty, assumin fresh data\n", *data) + return fmt.Errorf("file %s was empty, assumin fresh data", *data) } else if err := json.Unmarshal(b, &config); err != nil { - fmt.Fprintf(os.Stderr, "failed to unmarshal file %s error: %s\n", *data, err) - os.Exit(1) + return fmt.Errorf("failed to unmarshal file %s error: %s", *data, err) + } } @@ -82,23 +77,23 @@ func main() { // If there's still no host, bail if len(config.Host) == 0 { - fmt.Fprintln(os.Stderr, "no host set, please set one with -host") - os.Exit(1) + return fmt.Errorf("no host set, please set one with -host") } // Set up the server var server = rove.Server(config.Host) + // Grab the account + var account = config.Accounts[config.Host] + // Print the config info - fmt.Printf("host: %s\taccount: %s\n", config.Host, config.Account) + fmt.Printf("host: %s\taccount: %s\n", config.Host, account) // Handle all the commands - command := args[0] switch command { case "status": if response, err := server.Status(); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + return err } else { fmt.Printf("Ready: %t\n", response.Ready) @@ -110,45 +105,40 @@ func main() { Name: *name, } if response, err := server.Register(d); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + return err } else if !response.Success { - fmt.Fprintf(os.Stderr, "Server returned failure: %s\n", response.Error) - os.Exit(1) + return fmt.Errorf("Server returned failure: %s", response.Error) } else { fmt.Printf("Registered account with id: %s\n", response.Id) - config.Account = response.Id + config.Accounts[config.Host] = response.Id } case "spawn": - verifyId(config) d := rove.SpawnData{} - if response, err := server.Spawn(config.Account, d); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + if err := verifyId(account); err != nil { + return err + } else if response, err := server.Spawn(account, d); err != nil { + return err } else if !response.Success { - fmt.Fprintf(os.Stderr, "Server returned failure: %s\n", response.Error) - os.Exit(1) + return fmt.Errorf("Server returned failure: %s", response.Error) } else { fmt.Printf("Spawned at position %+v\n", response.Position) } case "command": - verifyId(config) + // TODO: Actually assemble requested commands d := rove.CommandData{} - // TODO: Send real commands in - - if response, err := server.Command(config.Account, d); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + if err := verifyId(account); err != nil { + return err + } else if response, err := server.Command(account, d); err != nil { + return err } else if !response.Success { - fmt.Fprintf(os.Stderr, "Server returned failure: %s\n", response.Error) - os.Exit(1) + return fmt.Errorf("Server returned failure: %s", response.Error) } else { // TODO: Pretify the response @@ -156,46 +146,62 @@ func main() { } case "radar": - verifyId(config) - if response, err := server.Radar(config.Account); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + if err := verifyId(account); err != nil { + return err + } else if response, err := server.Radar(account); err != nil { + return err } else if !response.Success { - fmt.Fprintf(os.Stderr, "Server returned failure: %s\n", response.Error) - os.Exit(1) + return fmt.Errorf("Server returned failure: %s", response.Error) } else { fmt.Printf("nearby rovers: %+v\n", response.Rovers) } case "rover": - verifyId(config) - if response, err := server.Rover(config.Account); err != nil { - fmt.Fprintln(os.Stderr, err) - os.Exit(1) + if err := verifyId(account); err != nil { + return err + } else if response, err := server.Rover(account); err != nil { + return err } else if !response.Success { - fmt.Fprintf(os.Stderr, "Server returned failure: %s\n", response.Error) - os.Exit(1) + return fmt.Errorf("Server returned failure: %s", response.Error) } else { fmt.Printf("position: %v\n", response.Position) } default: - fmt.Fprintf(os.Stderr, "Unknown command: %s\n", command) - os.Exit(1) + return fmt.Errorf("Unknown command: %s", command) } // Save out the persistent file if b, err := json.MarshalIndent(config, "", "\t"); err != nil { - fmt.Fprintf(os.Stderr, "failed to marshal data error: %s\n", err) - os.Exit(1) + return fmt.Errorf("failed to marshal data error: %s", err) } else { if err := ioutil.WriteFile(*data, b, os.ModePerm); err != nil { - fmt.Fprintf(os.Stderr, "failed to save file %s error: %s\n", *data, err) - os.Exit(1) + return fmt.Errorf("failed to save file %s error: %s", *data, err) } } + + return nil +} + +// Simple main +func main() { + flag.Usage = Usage + flag.Parse() + + // Verify we have a single command line arg + args := flag.Args() + if len(args) != 1 { + Usage() + os.Exit(1) + } + + // Run the inner main + if err := InnerMain(args[0]); err != nil { + fmt.Fprintf(os.Stderr, "Error: %s\n", err) + os.Exit(1) + } } diff --git a/cmd/rove/main_test.go b/cmd/rove/main_test.go new file mode 100644 index 0000000..46e10a8 --- /dev/null +++ b/cmd/rove/main_test.go @@ -0,0 +1,55 @@ +// +build integration + +package main + +import ( + "flag" + "os" + "path" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" +) + +func Test_InnerMain(t *testing.T) { + // Set up the flags to act locally and use a temporary file + flag.Set("data", path.Join(os.TempDir(), uuid.New().String())) + + // First attempt should error + assert.Error(t, InnerMain("status")) + + // Now set the host + flag.Set("host", "localhost:80") + + // No error now as we have a host + assert.NoError(t, InnerMain("status")) + + // Register should fail without a name + assert.Error(t, InnerMain("register")) + + // These methods should fail without an account + assert.Error(t, InnerMain("spawn")) + assert.Error(t, InnerMain("command")) + assert.Error(t, InnerMain("radar")) + assert.Error(t, InnerMain("rover")) + + // Now set the name + flag.Set("name", uuid.New().String()) + + // Perform the register + assert.NoError(t, InnerMain("register")) + + // We've not spawned a rover yet so these should fail + // assert.Error(t, InnerMain("command")) // Currently not erroring, needs investigation + assert.Error(t, InnerMain("radar")) + assert.Error(t, InnerMain("rover")) + + // Spawn a rover + assert.NoError(t, InnerMain("spawn")) + + // These should now work + assert.NoError(t, InnerMain("command")) + assert.NoError(t, InnerMain("radar")) + assert.NoError(t, InnerMain("rover")) +} diff --git a/pkg/rove/integration_test.go b/pkg/rove/integration_test.go index efb11ec..fe045a2 100644 --- a/pkg/rove/integration_test.go +++ b/pkg/rove/integration_test.go @@ -1,3 +1,5 @@ +// +build integration + package rove import (