From fe0833bd0632e6ff426735145f74f836488882c0 Mon Sep 17 00:00:00 2001 From: pauhull <22707808+pauhull@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:12:50 +0100 Subject: [PATCH] test: make state config mockable --- cmd/hcloud/main.go | 5 +- internal/cmd/context/active.go | 4 +- internal/cmd/context/create.go | 7 +- internal/cmd/context/delete.go | 4 +- internal/cmd/context/list.go | 4 +- internal/cmd/context/use.go | 2 +- internal/hcapi2/mock/mock_gen.go | 1 + internal/hcapi2/mock/zz_config_mock.go | 182 ++++++++++++++++++ internal/state/config.go | 117 ----------- internal/state/config/config.go | 177 +++++++++++++++++ internal/state/{ => config}/config_unix.go | 2 +- internal/state/{ => config}/config_windows.go | 2 +- internal/state/state.go | 42 +--- internal/testutil/fixture.go | 9 +- 14 files changed, 393 insertions(+), 165 deletions(-) create mode 100644 internal/hcapi2/mock/zz_config_mock.go delete mode 100644 internal/state/config.go create mode 100644 internal/state/config/config.go rename internal/state/{ => config}/config_unix.go (94%) rename internal/state/{ => config}/config_windows.go (93%) diff --git a/cmd/hcloud/main.go b/cmd/hcloud/main.go index ddb41d37..a737c23f 100644 --- a/cmd/hcloud/main.go +++ b/cmd/hcloud/main.go @@ -6,6 +6,7 @@ import ( "github.com/hetznercloud/cli/internal/cli" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" ) func init() { @@ -17,10 +18,10 @@ func init() { func main() { configPath := os.Getenv("HCLOUD_CONFIG") if configPath == "" { - configPath = state.DefaultConfigPath() + configPath = config.DefaultConfigPath() } - cfg, err := state.ReadConfig(configPath) + cfg, err := config.ReadConfig(configPath) if err != nil { log.Fatalf("unable to read config file %q: %s\n", configPath, err) } diff --git a/internal/cmd/context/active.go b/internal/cmd/context/active.go index 44608f45..fdedeccd 100644 --- a/internal/cmd/context/active.go +++ b/internal/cmd/context/active.go @@ -25,8 +25,8 @@ func runActive(s state.State, cmd *cobra.Command, _ []string) error { if os.Getenv("HCLOUD_TOKEN") != "" { _, _ = fmt.Fprintln(os.Stderr, "Warning: HCLOUD_TOKEN is set. The active context will have no effect.") } - if cfg := s.Config(); cfg.ActiveContext != nil { - cmd.Println(cfg.ActiveContext.Name) + if ctx := s.Config().ActiveContext(); ctx != nil { + cmd.Println(ctx.Name) } return nil } diff --git a/internal/cmd/context/create.go b/internal/cmd/context/create.go index 92b6db5c..99bb8b93 100644 --- a/internal/cmd/context/create.go +++ b/internal/cmd/context/create.go @@ -12,6 +12,7 @@ import ( "golang.org/x/term" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" ) func newCreateCommand(s state.State) *cobra.Command { @@ -40,7 +41,7 @@ func runCreate(s state.State, cmd *cobra.Command, args []string) error { return errors.New("name already used") } - context := &state.ConfigContext{Name: name} + context := &config.Context{Name: name} var token string @@ -82,8 +83,8 @@ func runCreate(s state.State, cmd *cobra.Command, args []string) error { context.Token = token - cfg.Contexts = append(cfg.Contexts, context) - cfg.ActiveContext = context + cfg.SetContexts(append(cfg.Contexts(), context)) + cfg.SetActiveContext(context) if err := cfg.Write(); err != nil { return err diff --git a/internal/cmd/context/delete.go b/internal/cmd/context/delete.go index 89eca4be..4f4a0e95 100644 --- a/internal/cmd/context/delete.go +++ b/internal/cmd/context/delete.go @@ -30,9 +30,9 @@ func runDelete(s state.State, _ *cobra.Command, args []string) error { if context == nil { return fmt.Errorf("context not found: %v", name) } - if cfg.ActiveContext == context { + if cfg.ActiveContext() == context { _, _ = fmt.Fprintln(os.Stderr, "Warning: You are deleting the currently active context. Please select a new active context.") - cfg.ActiveContext = nil + cfg.SetActiveContext(nil) } cfg.RemoveContext(context) return cfg.Write() diff --git a/internal/cmd/context/list.go b/internal/cmd/context/list.go index 4d1ce092..49ccd824 100644 --- a/internal/cmd/context/list.go +++ b/internal/cmd/context/list.go @@ -56,13 +56,13 @@ func runList(s state.State, cmd *cobra.Command, _ []string) error { tw.WriteHeader(cols) } cfg := s.Config() - for _, context := range cfg.Contexts { + for _, context := range cfg.Contexts() { presentation := ContextPresentation{ Name: context.Name, Token: context.Token, Active: " ", } - if ctx := cfg.ActiveContext; ctx != nil && ctx.Name == context.Name { + if ctx := cfg.ActiveContext(); ctx != nil && ctx.Name == context.Name { presentation.Active = "*" } diff --git a/internal/cmd/context/use.go b/internal/cmd/context/use.go index f5d89f1d..b6a3ff7c 100644 --- a/internal/cmd/context/use.go +++ b/internal/cmd/context/use.go @@ -33,6 +33,6 @@ func runUse(s state.State, _ *cobra.Command, args []string) error { if context == nil { return fmt.Errorf("context not found: %v", name) } - cfg.ActiveContext = context + cfg.SetActiveContext(context) return cfg.Write() } diff --git a/internal/hcapi2/mock/mock_gen.go b/internal/hcapi2/mock/mock_gen.go index cbf54914..a99e0337 100644 --- a/internal/hcapi2/mock/mock_gen.go +++ b/internal/hcapi2/mock/mock_gen.go @@ -1,5 +1,6 @@ package hcapi2_mock +//go:generate mockgen -package hcapi2_mock -destination zz_config_mock.go github.com/hetznercloud/cli/internal/state/config Config //go:generate mockgen -package hcapi2_mock -destination zz_action_client_mock.go github.com/hetznercloud/cli/internal/hcapi2 ActionClient //go:generate mockgen -package hcapi2_mock -destination zz_certificate_client_mock.go github.com/hetznercloud/cli/internal/hcapi2 CertificateClient //go:generate mockgen -package hcapi2_mock -destination zz_datacenter_client_mock.go github.com/hetznercloud/cli/internal/hcapi2 DatacenterClient diff --git a/internal/hcapi2/mock/zz_config_mock.go b/internal/hcapi2/mock/zz_config_mock.go new file mode 100644 index 00000000..7f6ed517 --- /dev/null +++ b/internal/hcapi2/mock/zz_config_mock.go @@ -0,0 +1,182 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/hetznercloud/cli/internal/state/config (interfaces: Config) + +// Package hcapi2_mock is a generated GoMock package. +package hcapi2_mock + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" + config "github.com/hetznercloud/cli/internal/state/config" +) + +// MockConfig is a mock of Config interface. +type MockConfig struct { + ctrl *gomock.Controller + recorder *MockConfigMockRecorder +} + +// MockConfigMockRecorder is the mock recorder for MockConfig. +type MockConfigMockRecorder struct { + mock *MockConfig +} + +// NewMockConfig creates a new mock instance. +func NewMockConfig(ctrl *gomock.Controller) *MockConfig { + mock := &MockConfig{ctrl: ctrl} + mock.recorder = &MockConfigMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockConfig) EXPECT() *MockConfigMockRecorder { + return m.recorder +} + +// ActiveContext mocks base method. +func (m *MockConfig) ActiveContext() *config.Context { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ActiveContext") + ret0, _ := ret[0].(*config.Context) + return ret0 +} + +// ActiveContext indicates an expected call of ActiveContext. +func (mr *MockConfigMockRecorder) ActiveContext() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActiveContext", reflect.TypeOf((*MockConfig)(nil).ActiveContext)) +} + +// ContextByName mocks base method. +func (m *MockConfig) ContextByName(arg0 string) *config.Context { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ContextByName", arg0) + ret0, _ := ret[0].(*config.Context) + return ret0 +} + +// ContextByName indicates an expected call of ContextByName. +func (mr *MockConfigMockRecorder) ContextByName(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContextByName", reflect.TypeOf((*MockConfig)(nil).ContextByName), arg0) +} + +// ContextNames mocks base method. +func (m *MockConfig) ContextNames() []string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ContextNames") + ret0, _ := ret[0].([]string) + return ret0 +} + +// ContextNames indicates an expected call of ContextNames. +func (mr *MockConfigMockRecorder) ContextNames() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ContextNames", reflect.TypeOf((*MockConfig)(nil).ContextNames)) +} + +// Contexts mocks base method. +func (m *MockConfig) Contexts() []*config.Context { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Contexts") + ret0, _ := ret[0].([]*config.Context) + return ret0 +} + +// Contexts indicates an expected call of Contexts. +func (mr *MockConfigMockRecorder) Contexts() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Contexts", reflect.TypeOf((*MockConfig)(nil).Contexts)) +} + +// Endpoint mocks base method. +func (m *MockConfig) Endpoint() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Endpoint") + ret0, _ := ret[0].(string) + return ret0 +} + +// Endpoint indicates an expected call of Endpoint. +func (mr *MockConfigMockRecorder) Endpoint() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Endpoint", reflect.TypeOf((*MockConfig)(nil).Endpoint)) +} + +// Marshal mocks base method. +func (m *MockConfig) Marshal() ([]byte, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Marshal") + ret0, _ := ret[0].([]byte) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// Marshal indicates an expected call of Marshal. +func (mr *MockConfigMockRecorder) Marshal() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Marshal", reflect.TypeOf((*MockConfig)(nil).Marshal)) +} + +// RemoveContext mocks base method. +func (m *MockConfig) RemoveContext(arg0 *config.Context) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "RemoveContext", arg0) +} + +// RemoveContext indicates an expected call of RemoveContext. +func (mr *MockConfigMockRecorder) RemoveContext(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveContext", reflect.TypeOf((*MockConfig)(nil).RemoveContext), arg0) +} + +// SetActiveContext mocks base method. +func (m *MockConfig) SetActiveContext(arg0 *config.Context) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetActiveContext", arg0) +} + +// SetActiveContext indicates an expected call of SetActiveContext. +func (mr *MockConfigMockRecorder) SetActiveContext(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetActiveContext", reflect.TypeOf((*MockConfig)(nil).SetActiveContext), arg0) +} + +// SetContexts mocks base method. +func (m *MockConfig) SetContexts(arg0 []*config.Context) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetContexts", arg0) +} + +// SetContexts indicates an expected call of SetContexts. +func (mr *MockConfigMockRecorder) SetContexts(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetContexts", reflect.TypeOf((*MockConfig)(nil).SetContexts), arg0) +} + +// SetEndpoint mocks base method. +func (m *MockConfig) SetEndpoint(arg0 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "SetEndpoint", arg0) +} + +// SetEndpoint indicates an expected call of SetEndpoint. +func (mr *MockConfigMockRecorder) SetEndpoint(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetEndpoint", reflect.TypeOf((*MockConfig)(nil).SetEndpoint), arg0) +} + +// Write mocks base method. +func (m *MockConfig) Write() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Write") + ret0, _ := ret[0].(error) + return ret0 +} + +// Write indicates an expected call of Write. +func (mr *MockConfigMockRecorder) Write() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Write", reflect.TypeOf((*MockConfig)(nil).Write)) +} diff --git a/internal/state/config.go b/internal/state/config.go deleted file mode 100644 index 09b42fac..00000000 --- a/internal/state/config.go +++ /dev/null @@ -1,117 +0,0 @@ -package state - -import ( - "fmt" - "os" - "path/filepath" - - toml "github.com/pelletier/go-toml/v2" -) - -type Config struct { - Path string - Endpoint string - ActiveContext *ConfigContext - Contexts []*ConfigContext -} - -type ConfigContext struct { - Name string - Token string -} - -func (config *Config) Write() error { - data, err := MarshalConfig(config) - if err != nil { - return err - } - if err := os.MkdirAll(filepath.Dir(config.Path), 0777); err != nil { - return err - } - if err := os.WriteFile(config.Path, data, 0600); err != nil { - return err - } - return nil -} - -func (config *Config) ContextNames() []string { - if len(config.Contexts) == 0 { - return nil - } - names := make([]string, len(config.Contexts)) - for i, ctx := range config.Contexts { - names[i] = ctx.Name - } - return names -} - -func (config *Config) ContextByName(name string) *ConfigContext { - for _, c := range config.Contexts { - if c.Name == name { - return c - } - } - return nil -} - -func (config *Config) RemoveContext(context *ConfigContext) { - for i, c := range config.Contexts { - if c == context { - config.Contexts = append(config.Contexts[:i], config.Contexts[i+1:]...) - return - } - } -} - -type RawConfig struct { - ActiveContext string `toml:"active_context,omitempty"` - Contexts []RawConfigContext `toml:"contexts"` -} - -type RawConfigContext struct { - Name string `toml:"name"` - Token string `toml:"token"` -} - -func MarshalConfig(c *Config) ([]byte, error) { - if c == nil { - return []byte{}, nil - } - - var raw RawConfig - if c.ActiveContext != nil { - raw.ActiveContext = c.ActiveContext.Name - } - for _, context := range c.Contexts { - raw.Contexts = append(raw.Contexts, RawConfigContext{ - Name: context.Name, - Token: context.Token, - }) - } - return toml.Marshal(raw) -} - -func UnmarshalConfig(config *Config, data []byte) error { - var raw RawConfig - if err := toml.Unmarshal(data, &raw); err != nil { - return err - } - for _, rawContext := range raw.Contexts { - config.Contexts = append(config.Contexts, &ConfigContext{ - Name: rawContext.Name, - Token: rawContext.Token, - }) - } - if raw.ActiveContext != "" { - for _, c := range config.Contexts { - if c.Name == raw.ActiveContext { - config.ActiveContext = c - break - } - } - if config.ActiveContext == nil { - return fmt.Errorf("active context %s not found", raw.ActiveContext) - } - } - return nil -} diff --git a/internal/state/config/config.go b/internal/state/config/config.go new file mode 100644 index 00000000..83ef1e1b --- /dev/null +++ b/internal/state/config/config.go @@ -0,0 +1,177 @@ +package config + +import ( + "fmt" + "os" + "path/filepath" + + toml "github.com/pelletier/go-toml/v2" +) + +type Config interface { + Write() error + Marshal() ([]byte, error) + + ActiveContext() *Context + SetActiveContext(*Context) + Contexts() []*Context + SetContexts([]*Context) + Endpoint() string + SetEndpoint(string) + + ContextNames() []string + ContextByName(name string) *Context + RemoveContext(context *Context) +} + +type Context struct { + Name string + Token string +} + +type config struct { + path string + endpoint string + activeContext *Context `toml:"active_context,omitempty"` + contexts []*Context `toml:"contexts"` +} + +func ReadConfig(path string) (Config, error) { + cfg := &config{path: path} + + _, err := os.Stat(path) + if err != nil { + if os.IsNotExist(err) { + return cfg, nil + } + return cfg, err + } + + data, err := os.ReadFile(path) + if err != nil { + return nil, err + } + + if err = cfg.unmarshal(data); err != nil { + return nil, err + } + + return cfg, nil +} + +func (cfg *config) Write() error { + data, err := cfg.Marshal() + if err != nil { + return err + } + if err := os.MkdirAll(filepath.Dir(cfg.path), 0777); err != nil { + return err + } + if err := os.WriteFile(cfg.path, data, 0600); err != nil { + return err + } + return nil +} + +type rawConfig struct { + activeContext string + contexts []rawConfigContext +} + +type rawConfigContext struct { + Name string `toml:"name"` + Token string `toml:"token"` +} + +func (cfg *config) Marshal() ([]byte, error) { + + var raw rawConfig + if cfg.activeContext != nil { + raw.activeContext = cfg.activeContext.Name + } + for _, context := range cfg.contexts { + raw.contexts = append(raw.contexts, rawConfigContext{ + Name: context.Name, + Token: context.Token, + }) + } + return toml.Marshal(raw) +} + +func (cfg *config) ActiveContext() *Context { + return cfg.activeContext +} + +func (cfg *config) SetActiveContext(context *Context) { + cfg.activeContext = context +} + +func (cfg *config) Contexts() []*Context { + return cfg.contexts +} + +func (cfg *config) SetContexts(contexts []*Context) { + cfg.contexts = contexts +} + +func (cfg *config) Endpoint() string { + return cfg.endpoint +} + +func (cfg *config) SetEndpoint(endpoint string) { + cfg.endpoint = endpoint +} + +func (cfg *config) ContextNames() []string { + if len(cfg.contexts) == 0 { + return nil + } + names := make([]string, len(cfg.contexts)) + for i, ctx := range cfg.contexts { + names[i] = ctx.Name + } + return names +} + +func (cfg *config) ContextByName(name string) *Context { + for _, c := range cfg.contexts { + if c.Name == name { + return c + } + } + return nil +} + +func (cfg *config) RemoveContext(context *Context) { + for i, c := range cfg.contexts { + if c == context { + cfg.contexts = append(cfg.contexts[:i], cfg.contexts[i+1:]...) + return + } + } +} + +func (cfg *config) unmarshal(data []byte) error { + var raw rawConfig + if err := toml.Unmarshal(data, &raw); err != nil { + return err + } + for _, rawContext := range raw.contexts { + cfg.contexts = append(cfg.contexts, &Context{ + Name: rawContext.Name, + Token: rawContext.Token, + }) + } + if raw.activeContext != "" { + for _, c := range cfg.contexts { + if c.Name == raw.activeContext { + cfg.activeContext = c + break + } + } + if cfg.activeContext == nil { + return fmt.Errorf("active context %s not found", raw.activeContext) + } + } + return nil +} diff --git a/internal/state/config_unix.go b/internal/state/config/config_unix.go similarity index 94% rename from internal/state/config_unix.go rename to internal/state/config/config_unix.go index 291cc725..d6ce3a19 100644 --- a/internal/state/config_unix.go +++ b/internal/state/config/config_unix.go @@ -1,6 +1,6 @@ //go:build !windows -package state +package config import ( "os/user" diff --git a/internal/state/config_windows.go b/internal/state/config/config_windows.go similarity index 93% rename from internal/state/config_windows.go rename to internal/state/config/config_windows.go index 6dc7b2c6..fecd6abb 100644 --- a/internal/state/config_windows.go +++ b/internal/state/config/config_windows.go @@ -1,6 +1,6 @@ //go:build windows -package state +package config import ( "os" diff --git a/internal/state/state.go b/internal/state/state.go index 3bcbaac3..8a21cde7 100644 --- a/internal/state/state.go +++ b/internal/state/state.go @@ -6,6 +6,7 @@ import ( "os" "github.com/hetznercloud/cli/internal/hcapi2" + "github.com/hetznercloud/cli/internal/state/config" "github.com/hetznercloud/cli/internal/version" "github.com/hetznercloud/hcloud-go/v2/hcloud" ) @@ -17,7 +18,7 @@ type State interface { ActionWaiter Client() hcapi2.Client - Config() *Config + Config() config.Config } type state struct { @@ -28,19 +29,19 @@ type state struct { debug bool debugFilePath string client hcapi2.Client - config *Config + config config.Config } -func New(cfg *Config) (State, error) { +func New(cfg config.Config) (State, error) { var ( token string endpoint string ) - if cfg.ActiveContext != nil { - token = cfg.ActiveContext.Token + if ctx := cfg.ActiveContext(); ctx != nil { + token = ctx.Token } - if cfg.Endpoint != "" { - endpoint = cfg.Endpoint + if ep := cfg.Endpoint(); ep != "" { + endpoint = ep } s := &state{ @@ -55,34 +56,11 @@ func New(cfg *Config) (State, error) { return s, nil } -func ReadConfig(path string) (*Config, error) { - cfg := &Config{Path: path} - - _, err := os.Stat(path) - if err != nil { - if os.IsNotExist(err) { - return cfg, nil - } - return cfg, err - } - - data, err := os.ReadFile(path) - if err != nil { - return nil, err - } - - if err = UnmarshalConfig(cfg, data); err != nil { - return nil, err - } - - return cfg, nil -} - func (c *state) Client() hcapi2.Client { return c.client } -func (c *state) Config() *Config { +func (c *state) Config() config.Config { return c.config } @@ -101,7 +79,7 @@ func (c *state) readEnv() { } if s := os.Getenv("HCLOUD_CONTEXT"); s != "" && c.config != nil { if cfgCtx := c.config.ContextByName(s); cfgCtx != nil { - c.config.ActiveContext = cfgCtx + c.config.SetActiveContext(cfgCtx) c.token = cfgCtx.Token } else { log.Printf("warning: context %q specified in HCLOUD_CONTEXT does not exist\n", s) diff --git a/internal/testutil/fixture.go b/internal/testutil/fixture.go index f21b66e1..9ebe3c08 100644 --- a/internal/testutil/fixture.go +++ b/internal/testutil/fixture.go @@ -12,6 +12,7 @@ import ( "github.com/hetznercloud/cli/internal/hcapi2" hcapi2_mock "github.com/hetznercloud/cli/internal/hcapi2/mock" "github.com/hetznercloud/cli/internal/state" + "github.com/hetznercloud/cli/internal/state/config" ) // Fixture provides affordances for testing CLI commands. @@ -20,6 +21,7 @@ type Fixture struct { Client *hcapi2_mock.MockClient ActionWaiter *state.MockActionWaiter TokenEnsurer *state.MockTokenEnsurer + Config *hcapi2_mock.MockConfig } // NewFixture creates a new Fixture. @@ -31,6 +33,7 @@ func NewFixture(t *testing.T) *Fixture { Client: hcapi2_mock.NewMockClient(ctrl), ActionWaiter: state.NewMockActionWaiter(ctrl), TokenEnsurer: state.NewMockTokenEnsurer(ctrl), + Config: hcapi2_mock.NewMockConfig(ctrl), } } @@ -64,6 +67,7 @@ type fixtureState struct { state.ActionWaiter client hcapi2.Client + config config.Config } func (*fixtureState) WriteConfig() error { @@ -74,8 +78,8 @@ func (s *fixtureState) Client() hcapi2.Client { return s.client } -func (*fixtureState) Config() *state.Config { - return nil +func (s *fixtureState) Config() config.Config { + return s.config } // State returns a state.State implementation for testing purposes. @@ -85,5 +89,6 @@ func (f *Fixture) State() state.State { TokenEnsurer: f.TokenEnsurer, ActionWaiter: f.ActionWaiter, client: f.Client, + config: f.Config, } }