diff --git a/docs/devel/e2e-tests.md b/docs/devel/e2e-tests.md index b0d0860d851..6d457f59311 100644 --- a/docs/devel/e2e-tests.md +++ b/docs/devel/e2e-tests.md @@ -58,6 +58,7 @@ Updated: 5/3/2016 - [Testing against local clusters](#testing-against-local-clusters) - [Version-skewed and upgrade testing](#version-skewed-and-upgrade-testing) - [Kinds of tests](#kinds-of-tests) + - [Viper configuration and hierarchichal test parameters.](#viper-configuration-and-hierarchichal-test-parameters) - [Conformance tests](#conformance-tests) - [Defining Conformance Subset](#defining-conformance-subset) - [Continuous Integration](#continuous-integration) @@ -511,6 +512,20 @@ breaking changes, it does *not* block the merge-queue, and thus should run in some separate test suites owned by the feature owner(s) (see [Continuous Integration](#continuous-integration) below). +### Viper configuration and hierarchichal test parameters. + +The future of e2e test configuration idioms will be increasingly defined using viper, and decreasingly via flags. + +Flags in general fall apart once tests become sufficiently complicated. So, even if we could use another flag library, it wouldn't be ideal. + +To use viper, rather than flags, to configure your tests: + +- Just add "e2e.json" to the current directory you are in, and define parameters in it... i.e. `"kubeconfig":"/tmp/x"`. + +Note that advanced testing parameters, and hierarchichally defined parameters, are only defined in viper, to see what they are, you can dive into [TestContextType](../../test/e2e/framework/test_context.go). + +In time, it is our intent to add or autogenerate a sample viper configuration that includes all e2e parameters, to ship with kubernetes. + ### Conformance tests Finally, `[Conformance]` tests represent a subset of the e2e-tests we expect to diff --git a/hack/verify-flags/known-flags.txt b/hack/verify-flags/known-flags.txt index 3c38601c76a..9a845ffa1ae 100644 --- a/hack/verify-flags/known-flags.txt +++ b/hack/verify-flags/known-flags.txt @@ -533,3 +533,4 @@ windows-line-endings www-prefix zone-name garbage-collector-enabled +viper-config diff --git a/test/e2e/cadvisor.go b/test/e2e/cadvisor.go index 56f110e1349..c369ea52466 100644 --- a/test/e2e/cadvisor.go +++ b/test/e2e/cadvisor.go @@ -27,10 +27,23 @@ import ( . "github.com/onsi/ginkgo" ) -const ( - maxRetries = 6 - sleepDuration = 10 * time.Second -) +// returns maxRetries, sleepDuration +func readConfig() (int, time.Duration) { + // Read in configuration settings, reasonable defaults. + retry := framework.TestContext.Cadvisor.MaxRetries + if framework.TestContext.Cadvisor.MaxRetries == 0 { + retry = 6 + framework.Logf("Overriding default retry value of zero to %d", retry) + } + + sleepDurationMS := framework.TestContext.Cadvisor.SleepDurationMS + if sleepDurationMS == 0 { + sleepDurationMS = 10000 + framework.Logf("Overriding default milliseconds value of zero to %d", sleepDurationMS) + } + + return retry, time.Duration(sleepDurationMS) * time.Millisecond +} var _ = framework.KubeDescribe("Cadvisor", func() { @@ -47,7 +60,7 @@ func CheckCadvisorHealthOnAllNodes(c *client.Client, timeout time.Duration) { nodeList, err := c.Nodes().List(api.ListOptions{}) framework.ExpectNoError(err) var errors []error - retries := maxRetries + maxRetries, sleepDuration := readConfig() for { errors = []error{} for _, node := range nodeList.Items { @@ -63,7 +76,7 @@ func CheckCadvisorHealthOnAllNodes(c *client.Client, timeout time.Duration) { if len(errors) == 0 { return } - if retries--; retries <= 0 { + if maxRetries--; maxRetries <= 0 { break } framework.Logf("failed to retrieve kubelet stats -\n %v", errors) diff --git a/test/e2e/framework/test_context.go b/test/e2e/framework/test_context.go index 7b61d877f86..f725904caf6 100644 --- a/test/e2e/framework/test_context.go +++ b/test/e2e/framework/test_context.go @@ -21,7 +21,6 @@ import ( "os" "time" - glog "github.com/golang/glog" "github.com/onsi/ginkgo/config" "github.com/spf13/viper" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd" @@ -78,6 +77,18 @@ type TestContextType struct { FeatureGates string // Node e2e specific test context NodeTestContextType + + // Viper-only parameters. These will in time replace all flags. + // Example: Create a file 'e2e.json' with the following: + // "Cadvisor":{ + // "MaxRetries":"6" + // } + + Viper string + Cadvisor struct { + MaxRetries int + SleepDurationMS int + } } // NodeTestContextType is part of TestContextType, it is shared by all node e2e test. @@ -134,6 +145,7 @@ func RegisterCommonFlags() { flag.StringVar(&TestContext.ReportPrefix, "report-prefix", "", "Optional prefix for JUnit XML reports. Default is empty, which doesn't prepend anything to the default name.") flag.StringVar(&TestContext.ReportDir, "report-dir", "", "Path to the directory where the JUnit XML reports should be saved. Default is empty, which doesn't generate these reports.") flag.StringVar(&TestContext.FeatureGates, "feature-gates", "", "A set of key=value pairs that describe feature gates for alpha/experimental features.") + flag.StringVar(&TestContext.Viper, "viper-config", "e2e", "The name of the viper config i.e. 'e2e' will read values from 'e2e.json' locally. All e2e parameters are meant to be configurable by viper.") } // Register flags specific to the cluster e2e test suite. @@ -190,25 +202,35 @@ func RegisterNodeFlags() { // Enable viper configuration management of flags. func ViperizeFlags() { - // Add viper in a minimal way. - // Flag interop isnt possible, since 'go test' coupling to flag.Parse. - viper.SetConfigName("e2e") - viper.AddConfigPath(".") - viper.ReadInConfig() // TODO @jayunit100: Maybe a more elegant viper-flag integration for the future? // For now, we layer it on top, because 'flag' deps of 'go test' make pflag wrappers // fragile, seeming to force 'flag' to have deep awareness of pflag params. RegisterCommonFlags() RegisterClusterFlags() + flag.Parse() - viperFlagSetter := func(f *flag.Flag) { - if viper.IsSet(f.Name) { - glog.V(4).Infof("[viper config] Overwriting, found a settting for %v %v", f.Name, f.Value) - f.Value.Set(viper.GetString(f.Name)) - } - } - // Each flag that we've declared can be set via viper. - flag.VisitAll(viperFlagSetter) + // Add viper in a minimal way. + // Flag interop isnt possible, since 'go test' coupling to flag.Parse. + // This must be done after common flags are registered, since Viper is a flag option. + viper.SetConfigName(TestContext.Viper) + viper.AddConfigPath(".") + viper.ReadInConfig() + + viper.Unmarshal(&TestContext) + + /** This can be used to overwrite a flag value. + * + * viperFlagSetter := func(f *flag.Flag) { + * if viper.IsSet(f.Name) { + * glog.V(4).Infof("[viper config] Overwriting, found a settting for %v %v", f.Name, f.Value) + * viper.Unmarshal(&TestContext) + * // f.Value.Set(viper.GetString(f.Name)) + * } + * } + * // Each flag that we've declared can be set via viper. + * flag.VisitAll(viperFlagSetter) + * + */ }