Add missing Manifest validations to EnsureComplete

The EnsureComplete method needs to perform various validations on a
Config object. This commit adds the missing validations for Manifests.

Change-Id: Ib562a67eefbbf19eb64444c4a811d946a9c8e170
This commit is contained in:
Ian Howell 2020-01-17 09:30:28 -06:00 committed by Dmitry Ukov
parent 7089223607
commit f0a14cb4fd
2 changed files with 146 additions and 39 deletions

View File

@ -269,31 +269,59 @@ func (c *Config) reconcileCurrentContext() {
} }
} }
// This is called by users of the config to make sure that they have // EnsureComplete verifies that a Config object is ready to use.
// A complete configuration before they try to use it. // A complete Config object meets the following criteria:
// What is a Complete configuration: // * At least 1 Cluster is defined
// Should be : // * At least 1 AuthInfo (user) is defined
// At least 1 cluster defined // * At least 1 Context is defined
// At least 1 authinfo (user) defined // * At least 1 Manifest is defined
// At least 1 context defined // * The CurrentContext is set
// The current context properly associated with an existsing context // * The CurrentContext identifies an existing Context
// At least one Manifest defined // * The CurrentContext identifies an existing Manifest
//
func (c *Config) EnsureComplete() error { func (c *Config) EnsureComplete() error {
if len(c.Clusters) == 0 { if len(c.Clusters) == 0 {
return errors.New("Config: At least one cluster needs to be defined") return ErrMissingConfig{
What: "At least one cluster needs to be defined",
}
} }
if len(c.AuthInfos) == 0 { if len(c.AuthInfos) == 0 {
return errors.New("Config: At least one Authentication Information (User) needs to be defined") return ErrMissingConfig{
What: "At least one Authentication Information (User) needs to be defined",
}
} }
if len(c.Contexts) == 0 { if len(c.Contexts) == 0 {
return errors.New("Config: At least one Context needs to be defined") return ErrMissingConfig{
What: "At least one Context needs to be defined",
}
} }
if c.CurrentContext == "" || c.Contexts[c.CurrentContext] == nil { if len(c.Manifests) == 0 {
return errors.New("Config: Current Context is not defined, or it doesnt identify a defined Context") return ErrMissingConfig{
What: "At least one Manifest needs to be defined",
}
} }
if c.CurrentContext == "" {
return ErrMissingConfig{
What: "Current Context is not defined",
}
}
currentContext, found := c.Contexts[c.CurrentContext]
if !found {
return ErrMissingConfig{
What: fmt.Sprintf("Current Context (%s) does not identify a defined Context", c.CurrentContext),
}
}
if _, found := c.Manifests[currentContext.Manifest]; !found {
return ErrMissingConfig{
What: fmt.Sprintf("Current Context (%s) does not identify a defined Manifest", c.CurrentContext),
}
}
return nil return nil
} }

View File

@ -229,33 +229,112 @@ func TestPersistConfig(t *testing.T) {
} }
func TestEnsureComplete(t *testing.T) { func TestEnsureComplete(t *testing.T) {
conf := InitConfig(t) // This test is intentionally verbose. Since a user of EnsureComplete
// does not need to know about the order of validation, each test
conf.CurrentContext = "def_ephemeral" // object passed into EnsureComplete should have exactly one issue, and
assert.NoError(t, conf.EnsureComplete()) // be otherwise valid
tests := []struct {
// Trigger no CurrentContext Error name string
conf.CurrentContext = "" config Config
err := conf.EnsureComplete() expectedErr error
assert.EqualError(t, err, "Config: Current Context is not defined, or it doesnt identify a defined Context") }{
{
// Trigger Contexts Error name: "no clusters defined",
for key := range conf.Contexts { config: Config{
delete(conf.Contexts, key) Clusters: map[string]*ClusterPurpose{},
AuthInfos: map[string]*AuthInfo{"testAuthInfo": {}},
Contexts: map[string]*Context{"testContext": {Manifest: "testManifest"}},
Manifests: map[string]*Manifest{"testManifest": {}},
CurrentContext: "testContext",
},
expectedErr: ErrMissingConfig{What: "At least one cluster needs to be defined"},
},
{
name: "no users defined",
config: Config{
Clusters: map[string]*ClusterPurpose{"testCluster": {}},
AuthInfos: map[string]*AuthInfo{},
Contexts: map[string]*Context{"testContext": {Manifest: "testManifest"}},
Manifests: map[string]*Manifest{"testManifest": {}},
CurrentContext: "testContext",
},
expectedErr: ErrMissingConfig{What: "At least one Authentication Information (User) needs to be defined"},
},
{
name: "no contexts defined",
config: Config{
Clusters: map[string]*ClusterPurpose{"testCluster": {}},
AuthInfos: map[string]*AuthInfo{"testAuthInfo": {}},
Contexts: map[string]*Context{},
Manifests: map[string]*Manifest{"testManifest": {}},
CurrentContext: "testContext",
},
expectedErr: ErrMissingConfig{What: "At least one Context needs to be defined"},
},
{
name: "no manifests defined",
config: Config{
Clusters: map[string]*ClusterPurpose{"testCluster": {}},
AuthInfos: map[string]*AuthInfo{"testAuthInfo": {}},
Contexts: map[string]*Context{"testContext": {Manifest: "testManifest"}},
Manifests: map[string]*Manifest{},
CurrentContext: "testContext",
},
expectedErr: ErrMissingConfig{What: "At least one Manifest needs to be defined"},
},
{
name: "current context not defined",
config: Config{
Clusters: map[string]*ClusterPurpose{"testCluster": {}},
AuthInfos: map[string]*AuthInfo{"testAuthInfo": {}},
Contexts: map[string]*Context{"testContext": {Manifest: "testManifest"}},
Manifests: map[string]*Manifest{"testManifest": {}},
CurrentContext: "",
},
expectedErr: ErrMissingConfig{What: "Current Context is not defined"},
},
{
name: "no context for current context",
config: Config{
Clusters: map[string]*ClusterPurpose{"testCluster": {}},
AuthInfos: map[string]*AuthInfo{"testAuthInfo": {}},
Contexts: map[string]*Context{"DIFFERENT_CONTEXT": {Manifest: "testManifest"}},
Manifests: map[string]*Manifest{"testManifest": {}},
CurrentContext: "testContext",
},
expectedErr: ErrMissingConfig{What: "Current Context (testContext) does not identify a defined Context"},
},
{
name: "no manifest for current context",
config: Config{
Clusters: map[string]*ClusterPurpose{"testCluster": {}},
AuthInfos: map[string]*AuthInfo{"testAuthInfo": {}},
Contexts: map[string]*Context{"testContext": {Manifest: "testManifest"}},
Manifests: map[string]*Manifest{"DIFFERENT_MANIFEST": {}},
CurrentContext: "testContext",
},
expectedErr: ErrMissingConfig{What: "Current Context (testContext) does not identify a defined Manifest"},
},
{
name: "complete config",
config: Config{
Clusters: map[string]*ClusterPurpose{"testCluster": {}},
AuthInfos: map[string]*AuthInfo{"testAuthInfo": {}},
Contexts: map[string]*Context{"testContext": {Manifest: "testManifest"}},
Manifests: map[string]*Manifest{"testManifest": {}},
CurrentContext: "testContext",
},
expectedErr: nil,
},
} }
err = conf.EnsureComplete()
assert.EqualError(t, err, "Config: At least one Context needs to be defined")
// Trigger Authentication Information for _, tt := range tests {
for key := range conf.AuthInfos { tt := tt
delete(conf.AuthInfos, key) t.Run(tt.name, func(subTest *testing.T) {
actualErr := tt.config.EnsureComplete()
assert.Equal(subTest, tt.expectedErr, actualErr)
})
} }
err = conf.EnsureComplete()
assert.EqualError(t, err, "Config: At least one Authentication Information (User) needs to be defined")
conf = NewConfig()
err = conf.EnsureComplete()
assert.Error(t, err, "A new config object should not be complete")
} }
func TestPurge(t *testing.T) { func TestPurge(t *testing.T) {