From 34e949df32786c1a33880c52c9efee00558803db Mon Sep 17 00:00:00 2001 From: Chandra Pamuluri Date: Fri, 3 Mar 2023 09:26:28 -0600 Subject: [PATCH] E2E - config server tooling and test cases implementation --- test/e2e/config/config_server_test.go | 74 +++++++++++++++++++ test/e2e/config/config_suite_test.go | 3 +- test/e2e/config/config_test.go | 39 +++++----- test/e2e/context/context_lifecycle_helper.go | 14 ++++ .../framework/config_lifecycle_operations.go | 30 ++++++-- test/e2e/framework/framework.go | 10 ++- test/e2e/framework/output_handling.go | 9 ++- 7 files changed, 148 insertions(+), 31 deletions(-) create mode 100644 test/e2e/config/config_server_test.go diff --git a/test/e2e/config/config_server_test.go b/test/e2e/config/config_server_test.go new file mode 100644 index 000000000..383ddfdaa --- /dev/null +++ b/test/e2e/config/config_server_test.go @@ -0,0 +1,74 @@ +// Copyright 2023 VMware, Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// Package config_e2e_test provides config command specific E2E test cases +package config_e2e_test + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vmware-tanzu/tanzu-cli/test/e2e/context" + "github.com/vmware-tanzu/tanzu-cli/test/e2e/framework" +) + +const ContextNameConfigPrefix = "config-k8s-" + +// This test suite tests the 'tanzu config server' use cases +// As part of this suite, create a KIND cluster, and creates context's +// tests the 'tanzu config server list' and 'tanzu config server delete' commands +var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Config-Server]", func() { + var ( + tf *framework.Framework + clusterInfo *framework.ClusterInfo + contextNames []string + ) + + BeforeSuite(func() { + tf = framework.NewFramework() + // Create KIND cluster, which is used in test cases to create server's/context's + clusterInfo = context.CreateKindCluster(tf, "config-e2e-"+framework.RandomNumber(4)) + contextNames = make([]string, 0) + }) + Context("tanzu config server command test cases ", func() { + // Test case: Create context for k8s target with kubeconfig and its context as input + It("create context with kubeconfig and context", func() { + ctxName := ContextNameConfigPrefix + framework.RandomString(4) + err := tf.ContextCmd.CreateConextWithKubeconfig(ctxName, clusterInfo.KubeConfigPath, clusterInfo.ClusterContext) + Expect(err).To(BeNil(), "context should create without any error") + contextNames = append(contextNames, ctxName) + }) + // Test case: Create context for k8s target with "default" kubeconfig and its context only as input value + It("create context with kubeconfig and context", func() { + ctxName := "context-defaultConfig-" + framework.RandomString(4) + err := tf.ContextCmd.CreateContextWithDefaultKubeconfig(ctxName, clusterInfo.ClusterContext) + Expect(err).To(BeNil(), "context should create without any error") + contextNames = append(contextNames, ctxName) + }) + // Test case: test 'tanzu config server list' command, should list all contexts created as servers + It("list servers should have all added contexts", func() { + list, err := tf.Config.ConfigServerList() + Expect(err).To(BeNil(), "config server list command should list available servers") + Expect(len(list)).To(Equal(len(contextNames)), "list context should have all contexts (as servers) added in previous tests") + }) + // Test case: test 'tanzu config server delete' command, make sure to delete all context's created in previous test cases + It("delete server command", func() { + for _, ctx := range contextNames { + err := tf.Config.ConfigServerDelete(ctx) + Expect(err).To(BeNil(), "delete server should delete server without any error") + } + list := context.GetAvailableServers(tf, contextNames) + Expect(len(list)).To(Equal(0), "delete server should have deleted all given server names") + }) + // Test case: (negative test) test 'tanzu context delete' command for context name which is not exists + It("delete server which is not exists", func() { + err := tf.Config.ConfigServerDelete(framework.RandomString(4)) + Expect(err).ToNot(BeNil()) + }) + }) + AfterSuite(func() { + // delete the KIND cluster which was created in the suite setup + _, err := tf.KindCluster.DeleteCluster(clusterInfo.Name) + Expect(err).To(BeNil(), "kind cluster should be deleted without any error") + }) +}) diff --git a/test/e2e/config/config_suite_test.go b/test/e2e/config/config_suite_test.go index 04bdc0d89..d47b651d8 100644 --- a/test/e2e/config/config_suite_test.go +++ b/test/e2e/config/config_suite_test.go @@ -1,7 +1,8 @@ // Copyright 2023 VMware, Inc. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -package confige2e +// Package config_e2e_test provides config command specific E2E test cases +package config_e2e_test import ( "testing" diff --git a/test/e2e/config/config_test.go b/test/e2e/config/config_test.go index cc7d34fa5..80a463392 100644 --- a/test/e2e/config/config_test.go +++ b/test/e2e/config/config_test.go @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // Package config_e2e_test provides config command specific E2E test cases -package confige2e +package config_e2e_test import ( . "github.com/onsi/ginkgo" @@ -13,18 +13,24 @@ import ( const TRUE = "true" -var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Command-Config]", func() { +// This test suite tests `tanzu config` life cycle tests +// tests `tanzu config init` by deleting the existing config files +// tests `tanzu config init` and make sure previous set flags are not deleted +// tests `tanzu config set` and `tanzu config unset` commands +var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:config]", func() { var ( - tf *framework.Framework + tf *framework.Framework + randomFeatureFlag string ) BeforeEach(func() { tf = framework.NewFramework() + randomFeatureFlag = "features.global." + "e2e-test-" + framework.RandomString(4) }) Context("config feature flag operations", func() { When("new config flag set with value", func() { It("should set flag and unset flag successfully", func() { - randomFlagName := "e2e-test-" + framework.RandomString(4) - randomFeatureFlagPath := "features.global." + randomFlagName + flagName := "e2e-test-" + framework.RandomString(4) + randomFeatureFlagPath := "features.global." + flagName flagVal := TRUE err := tf.Config.ConfigSetFeatureFlag(randomFeatureFlagPath, flagVal) Expect(err).To(BeNil()) @@ -41,7 +47,7 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Command-Config]", func() Expect(val).Should(Equal("")) }) }) - When("config init called when config files not exists", func() { + When("config init called when config files not exists and test re-init use case", func() { It("should initialize configuration successfully", func() { // delete config files err := tf.Config.DeleteCLIConfigurationFiles() @@ -51,28 +57,27 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Command-Config]", func() Expect(err).To(BeNil()) // should create config files Expect(tf.Config.IsCLIConfigurationFilesExists()).To(BeTrue()) - + }) + It("should able to set new feature flag", func() { // set feature flag - randomFlagName := "e2e-test-" + framework.RandomString(4) - randomFeatureFlagPath := "features.global." + randomFlagName - flagVal := TRUE - err = tf.Config.ConfigSetFeatureFlag(randomFeatureFlagPath, flagVal) + err := tf.Config.ConfigSetFeatureFlag(randomFeatureFlag, TRUE) Expect(err).To(BeNil()) - val, err := tf.Config.ConfigGetFeatureFlag(randomFeatureFlagPath) + val, err := tf.Config.ConfigGetFeatureFlag(randomFeatureFlag) Expect(err).To(BeNil()) Expect(val).Should(Equal(TRUE)) - + }) + It("re-init and should not remove previous set flags", func() { // call init - err = tf.Config.ConfigInit() + err := tf.Config.ConfigInit() Expect(err).To(BeNil()) // second run of init should not remove the existing feature flag - val, err = tf.Config.ConfigGetFeatureFlag(randomFeatureFlagPath) + val, err := tf.Config.ConfigGetFeatureFlag(randomFeatureFlag) Expect(err).To(BeNil()) - Expect(val).Should(Equal("true")) + Expect(val).Should(Equal(TRUE)) // unset the feature flag - err = tf.Config.ConfigUnsetFeature(randomFeatureFlagPath) + err = tf.Config.ConfigUnsetFeature(randomFeatureFlag) Expect(err).To(BeNil()) }) }) diff --git a/test/e2e/context/context_lifecycle_helper.go b/test/e2e/context/context_lifecycle_helper.go index 0a3c43147..303da4555 100644 --- a/test/e2e/context/context_lifecycle_helper.go +++ b/test/e2e/context/context_lifecycle_helper.go @@ -43,3 +43,17 @@ func GetAvailableContexts(tf *framework.Framework, contextNames []string) []stri } return available } + +// GetAvailableServers takes list of servers and returns which are available in the 'tanzu config server list' command +func GetAvailableServers(tf *framework.Framework, serverNames []string) []string { + var available []string + list, err := tf.Config.ConfigServerList() + gomega.Expect(err).To(gomega.BeNil(), "server list should not return any error") + set := framework.SliceToSet(serverNames) + for _, server := range list { + if _, ok := set[server.Name]; ok { + available = append(available, server.Name) + } + } + return available +} diff --git a/test/e2e/framework/config_lifecycle_operations.go b/test/e2e/framework/config_lifecycle_operations.go index 89c7f5396..6cfd9cec9 100644 --- a/test/e2e/framework/config_lifecycle_operations.go +++ b/test/e2e/framework/config_lifecycle_operations.go @@ -4,6 +4,8 @@ package framework import ( + "encoding/json" + "fmt" "os" "path/filepath" "strings" @@ -11,6 +13,8 @@ import ( "github.com/pkg/errors" "gopkg.in/yaml.v3" + "github.com/vmware-tanzu/tanzu-plugin-runtime/log" + configapi "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" ) @@ -33,7 +37,7 @@ type ConfigLifecycleOps interface { // GetConfig gets the tanzu config GetConfig() (*configapi.ClientConfig, error) // ConfigServerList returns the server list - ConfigServerList() error + ConfigServerList() ([]Server, error) // ConfigServerDelete deletes given server from tanzu config ConfigServerDelete(serverName string) error // DeleteCLIConfigurationFiles deletes cli configuration files @@ -102,15 +106,29 @@ func (co *configOps) ConfigInit() (err error) { } // ConfigServerList returns the server list -// TODO: should return the servers info in proper format -func (co *configOps) ConfigServerList() (err error) { - _, _, err = co.Exec(ConfigServerList) - return +func (co *configOps) ConfigServerList() ([]Server, error) { + stdOut, _, err := co.Exec(ConfigServerList) + if err != nil { + log.Errorf("error while executing `config server list`, error:%s", err.Error()) + return nil, err + } + jsonStr := stdOut.String() + var list []Server + err = json.Unmarshal([]byte(jsonStr), &list) + if err != nil { + log.Errorf("failed to construct node from config server list output:'%s' error:'%s' ", jsonStr, err.Error()) + return nil, errors.Wrapf(err, "failed to construct node from config server list output:'%s'", jsonStr) + } + return list, nil } // ConfigServerDelete deletes a server from tanzu config func (co *configOps) ConfigServerDelete(serverName string) error { - _, _, err := co.Exec(ConfigServerDelete + serverName) + configDelCmd := fmt.Sprintf(ConfigServerDelete, serverName) + _, _, err := co.Exec(configDelCmd) + if err != nil { + log.Error(err, "error while running: "+configDelCmd) + } return err } diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index 5a5586870..659f371dd 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -23,7 +23,7 @@ const ( ConfigUnset = "tanzu config unset " ConfigInit = "tanzu config init" ConfigServerList = "tanzu config server list" - ConfigServerDelete = "tanzu config server delete " + ConfigServerDelete = "tanzu config server delete %s" // Plugin commands AddPluginSource = "tanzu plugin source add --name %s --type %s --uri %s" @@ -74,9 +74,11 @@ const ( TargetTypeK8s = "kubernetes" ) -var TestDirPath string -var TestPluginsDirPath string -var TestStandalonePluginsPath string +var ( + TestDirPath string + TestPluginsDirPath string + TestStandalonePluginsPath string +) // CLICoreDescribe annotates the test with the CLICore label. func CLICoreDescribe(text string, body func()) bool { diff --git a/test/e2e/framework/output_handling.go b/test/e2e/framework/output_handling.go index 7663e2038..1b6ce55b1 100644 --- a/test/e2e/framework/output_handling.go +++ b/test/e2e/framework/output_handling.go @@ -32,7 +32,10 @@ type ContextInfo struct { } `json:"clusterOpts"` } -type PluginCompatibilityConf struct { - PluginNames []string `json:"plugins"` - TestCentralRepoURL string `json:"test-central-repo-url"` +type Server struct { + Context string `json:"context"` + Endpoint string `json:"endpoint"` + Name string `json:"name"` + Path string `json:"path"` + Type string `json:"type"` }