Skip to content

Commit

Permalink
Add tests for root cmd including bugfix for api-token arg. (#159)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerrit91 authored Aug 30, 2022
1 parent 0c270e2 commit 3e368eb
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 17 deletions.
22 changes: 16 additions & 6 deletions cmd/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ type test[R any] struct {
fsMocks func(fs afero.Fs, want R)
cmd func(want R) []string

disableMockClient bool // can switch off mock client creation

wantErr error
want R // for json and yaml
wantTable *string // for table printer
Expand Down Expand Up @@ -91,14 +93,22 @@ func (c *test[R]) newMockConfig(t *testing.T) (*client.MetalMockClient, *bytes.B
c.fsMocks(fs, c.want)
}

var out bytes.Buffer
var (
out bytes.Buffer
config = &config{
fs: fs,
client: client,
out: &out,
log: zaptest.NewLogger(t).Sugar(),
comp: &completion.Completion{},
}
)

return mock, &out, &config{
fs: fs,
out: &out,
client: client,
log: zaptest.NewLogger(t).Sugar(),
if c.disableMockClient {
config.client = nil
}

return mock, &out, config
}

func assertExhaustiveArgs(t *testing.T, args []string, exclude ...string) {
Expand Down
3 changes: 0 additions & 3 deletions cmd/firewall_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cmd

import (
"fmt"
"strings"
"testing"
"time"
Expand Down Expand Up @@ -301,8 +300,6 @@ ID AGE HOSTNAME PROJECT NETWORKS IPS PARTITION
"--tags", strings.Join(want.Tags, ","),
"--userdata", want.Allocation.UserData,
}

fmt.Println(args)
assertExhaustiveArgs(t, args, "file")
return args
},
Expand Down
9 changes: 3 additions & 6 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,12 @@ func newRootCmd(c *config) *cobra.Command {
Short: "a cli to manage entities in the metal-stack api",
SilenceUsage: true,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
viper.SetFs(c.fs)
must(viper.BindPFlags(cmd.Flags()))
must(viper.BindPFlags(cmd.PersistentFlags()))
// we cannot instantiate the config earlier because
// cobra flags do not work so early in the game
must(readConfigFile())
must(initConfigWithViperCtx(c))
},
}
Expand Down Expand Up @@ -130,13 +132,8 @@ metalctl machine list -o template --template "{{ .id }}:{{ .size.id }}"
rootCmd.AddCommand(newLogoutCmd(c))
rootCmd.AddCommand(newWhoamiCmd(c))
rootCmd.AddCommand(newContextCmd(c))

rootCmd.AddCommand(newUpdateCmd())

cobra.OnInitialize(func() {
must(readConfigFile())
})

return rootCmd
}

Expand Down Expand Up @@ -202,7 +199,7 @@ func initConfigWithViperCtx(c *config) error {
if hmacKey == "" && ctx.HMAC != nil {
hmacKey = *ctx.HMAC
}
apiToken := viper.GetString("apitoken")
apiToken := viper.GetString("api-token")

// if there is no api token explicitly specified we try to pull it out of the kubeconfig context
if apiToken == "" {
Expand Down
108 changes: 108 additions & 0 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package cmd

import (
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"

"github.com/metal-stack/metal-go/api/models"
"github.com/metal-stack/metal-lib/pkg/pointer"
"github.com/metal-stack/metal-lib/rest"
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_BasicRootCmdStuff(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if strings.HasPrefix(authHeader, "Bearer") {
assert.Equal(t, authHeader, "Bearer i-am-token")
} else if strings.HasPrefix(authHeader, "Metal-Admin") {
assert.Len(t, strings.Split(authHeader, " "), 2)
} else {
assert.Fail(t, "missing auth header")
}

w.Header().Add("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
_, err := w.Write(mustMarshal(t, &models.RestHealthResponse{
Status: pointer.Pointer(string(rest.HealthStatusHealthy)),
}))
assert.NoError(t, err)
}))
defer ts.Close()

tests := []*test[*rest.HealthResponse]{
{
name: "overwrite api-url and api-token from config-file",
fsMocks: func(fs afero.Fs, want *rest.HealthResponse) {
require.NoError(t, afero.WriteFile(fs, fmt.Sprintf("/etc/%s/config.yaml", binaryName), []byte(fmt.Sprintf(`---
api-url: "%s"
api-token: "i-am-token"
`, ts.URL)), 0755))
},
cmd: func(want *rest.HealthResponse) []string {
return []string{"health"}
},
disableMockClient: true,
want: &rest.HealthResponse{
Status: rest.HealthStatusHealthy,
},
},
{
name: "overwrite api-url and api-token from user-given config-file path",
fsMocks: func(fs afero.Fs, want *rest.HealthResponse) {
require.NoError(t, afero.WriteFile(fs, "/config.yaml", []byte(fmt.Sprintf(`---
api-url: "%s"
api-token: "i-am-token"
`, ts.URL)), 0755))
},
cmd: func(want *rest.HealthResponse) []string {
return []string{"health", "--config", "/config.yaml"}
},
disableMockClient: true,
want: &rest.HealthResponse{
Status: rest.HealthStatusHealthy,
},
},
{
name: "overwrite api-url and api-token from command line",
cmd: func(want *rest.HealthResponse) []string {
return []string{"health", "--api-url", ts.URL, "--api-token", "i-am-token"}
},
disableMockClient: true,
want: &rest.HealthResponse{
Status: rest.HealthStatusHealthy,
},
},
{
name: "overwrite api-url and api-token from environment",
cmd: func(want *rest.HealthResponse) []string {
t.Setenv("METALCTL_API_URL", ts.URL)
t.Setenv("METALCTL_API_TOKEN", "i-am-token")
return []string{"health"}
},
disableMockClient: true,
want: &rest.HealthResponse{
Status: rest.HealthStatusHealthy,
},
},
{
name: "use hmac",
cmd: func(want *rest.HealthResponse) []string {
t.Setenv("METALCTL_HMAC", "i-am-hmac")
return []string{"health"}
},
disableMockClient: true,
want: &rest.HealthResponse{
Status: rest.HealthStatusHealthy,
},
},
}
for _, tt := range tests {
tt.testCmd(t)
}
}
4 changes: 2 additions & 2 deletions pkg/api/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ var defaultCtx = Context{

func GetContexts() (*Contexts, error) {
var ctxs Contexts
cfgFile := viper.GetViper().ConfigFileUsed()
cfgFile := viper.ConfigFileUsed()
c, err := os.ReadFile(cfgFile)
if err != nil {
return nil, fmt.Errorf("unable to read config, please create a config.yaml in either: /etc/metalctl/, $HOME/.metalctl/ or in the current directory, see metalctl ctx -h for examples")
Expand All @@ -48,7 +48,7 @@ func WriteContexts(ctxs *Contexts) error {
if err != nil {
return err
}
cfgFile := viper.GetViper().ConfigFileUsed()
cfgFile := viper.ConfigFileUsed()
err = os.WriteFile(cfgFile, c, 0600)
if err != nil {
return err
Expand Down

0 comments on commit 3e368eb

Please sign in to comment.