Skip to content

Commit

Permalink
E2E: plugin group life cycle e2e test cases and e2e framework tooling (
Browse files Browse the repository at this point in the history
…#116)

implementation

Co-authored-by: Chandra Pamuluri <cpamuluri@cpamuluri-a01.vmware.com>
  • Loading branch information
chandrareddyp and Chandra Pamuluri authored Mar 23, 2023
1 parent a2d376c commit b7f962b
Show file tree
Hide file tree
Showing 16 changed files with 447 additions and 161 deletions.
7 changes: 6 additions & 1 deletion test/e2e/config/config_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,30 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Config-Server]", func() {
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() {
By("create context with kubeconfig and context")
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() {
It("create context with default kubeconfig and context", func() {
By("create context with default kubeconfig and context")
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() {
By("list servers should have all added contexts")
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 this command deletes server entry by deleting all contexts created in previous test cases
It("delete server command", func() {
By("delete servers which are created in previous tests")
for _, ctx := range contextNames {
err := tf.Config.ConfigServerDelete(ctx)
Expect(err).To(BeNil(), "delete server should delete server without any error")
Expand All @@ -62,6 +66,7 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Config-Server]", func() {
})
// Test case: (negative test) test 'tanzu context delete' command for context name which is not exists
It("delete server which is not exists", func() {
By("delete server which is not exists")
err := tf.Config.ConfigServerDelete(framework.RandomString(4))
Expect(err).ToNot(BeNil())
})
Expand Down
13 changes: 11 additions & 2 deletions test/e2e/context/context_k8s_lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
. "github.com/onsi/gomega"

"github.com/vmware-tanzu/tanzu-cli/test/e2e/framework"
"github.com/vmware-tanzu/tanzu-plugin-runtime/config/types"
)

const ContextNameConfigPrefix = "context-config-k8s-"
Expand All @@ -32,40 +33,45 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Context-lifecycle-k8s]",
Context("Context lifecycle tests for k8s target", func() {
// Test case: Create context for k8s target with kubeconfig and its context as input
It("create context with kubeconfig and context", func() {
By("create context with kubeconfig and context")
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: (negative test) Create context for k8s target with incorrect kubeconfig file path and its context as input
It("create context with incorrect kubeconfig and context", func() {
By("create context with incorrect kubeconfig and context")
ctxName := ContextNameConfigPrefix + framework.RandomString(4)
err := tf.ContextCmd.CreateConextWithKubeconfig(ctxName, framework.RandomString(4), clusterInfo.ClusterContext)
Expect(err).ToNot(BeNil())
Expect(strings.Contains(err.Error(), framework.FailedToCreateContext)).To(BeTrue())
})
// Test case: (negative test) Create context for k8s target with kubeconfig file path and incorrect context as input
It("create context with kubeconfig and incorrect context", func() {
By("create context with kubeconfig and incorrect context")
ctxName := ContextNameConfigPrefix + framework.RandomString(4)
err := tf.ContextCmd.CreateConextWithKubeconfig(ctxName, clusterInfo.KubeConfigPath, framework.RandomString(4))
Expect(err).ToNot(BeNil())
Expect(strings.Contains(err.Error(), framework.FailedToCreateContext)).To(BeTrue())
})
// 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() {
By("create context with kubeconfig and context")
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)
active, err := tf.ContextCmd.GetActiveContext(framework.TargetTypeK8s)
active, err := tf.ContextCmd.GetActiveContext(string(types.TargetK8s))
Expect(err).To(BeNil(), "there should be a active context")
Expect(active).To(Equal(ctxName), "the active context should be recently added context")
})
// Test case: test 'tanzu context use' command with the specific context name (not the recently created one)
It("use context command", func() {
By("use context command")
err := tf.ContextCmd.UseContext(contextNames[0])
Expect(err).To(BeNil(), "use context should set context without any error")
active, err := tf.ContextCmd.GetActiveContext(framework.TargetTypeK8s)
active, err := tf.ContextCmd.GetActiveContext(string(types.TargetK8s))
Expect(err).To(BeNil(), "there should be a active context")
Expect(active).To(Equal(contextNames[0]), "the active context should be recently set context")
})
Expand All @@ -76,11 +82,13 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Context-lifecycle-k8s]",
})
// Test case: test 'tanzu context list' command, should list all contexts created
It("list context should have all added contexts", func() {
By("list context should have all added contexts")
list := GetAvailableContexts(tf, contextNames)
Expect(len(list)).To(Equal(len(contextNames)), "list context should have all contexts added in previous tests")
})
// Test case: test 'tanzu context delete' command, make sure to delete all context's created in previous test cases
It("delete context command", func() {
By("delete all contexts created in previous tests")
for _, ctx := range contextNames {
err := tf.ContextCmd.DeleteContext(ctx)
Expect(err).To(BeNil(), "delete context should delete context without any error")
Expand All @@ -90,6 +98,7 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Context-lifecycle-k8s]",
})
// Test case: (negative test) test 'tanzu context delete' command for context name which is not exists
It("delete context command", func() {
By("delete context command with random string")
err := tf.ContextCmd.DeleteContext(framework.RandomString(4))
Expect(err).ToNot(BeNil())
})
Expand Down
5 changes: 3 additions & 2 deletions test/e2e/context/tmc/context_tmc_lifecycle_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

context "github.com/vmware-tanzu/tanzu-cli/test/e2e/context"
"github.com/vmware-tanzu/tanzu-cli/test/e2e/framework"
types "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types"
)

const ContextNamePrefix = "context-endpoint-tmc-"
Expand Down Expand Up @@ -61,15 +62,15 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Context-lifecycle-tmc]",
err := tf.ContextCmd.CreateConextWithEndPointStaging(ctxName, clusterInfo.EndPoint)
Expect(err).To(BeNil(), "context should create without any error")
contextNames = append(contextNames, ctxName)
active, err := tf.ContextCmd.GetActiveContext(framework.TargetTypeTMC)
active, err := tf.ContextCmd.GetActiveContext(string(types.TargetTMC))
Expect(err).To(BeNil(), "there should be a active context")
Expect(active).To(Equal(ctxName), "the active context should be recently added context")
})
// Test case: test 'tanzu context use' command with the specific context name (not the recently created one)
It("use context command", func() {
err := tf.ContextCmd.UseContext(contextNames[0])
Expect(err).To(BeNil(), "use context should set context without any error")
active, err := tf.ContextCmd.GetActiveContext(framework.TargetTypeTMC)
active, err := tf.ContextCmd.GetActiveContext(string(types.TargetTMC))
Expect(err).To(BeNil(), "there should be a active context")
Expect(active).To(Equal(contextNames[0]), "the active context should be same as the context set by use context command")
})
Expand Down
3 changes: 3 additions & 0 deletions test/e2e/framework/cmd_exec_operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"fmt"
"os/exec"
"strings"

"github.com/vmware-tanzu/tanzu-plugin-runtime/log"
)

// CmdOps performs the Command line exec operations
Expand All @@ -31,6 +33,7 @@ func NewCmdOps() CmdOps {

// Exec the command, exit on error
func (co *cmdOps) Exec(command string) (stdOut, stdErr *bytes.Buffer, err error) {
log.Infof(ExecutingCommand, command)
cmdInput := strings.Split(command, " ")
cmdName := cmdInput[0]
cmdArgs := cmdInput[1:]
Expand Down
33 changes: 10 additions & 23 deletions test/e2e/framework/config_lifecycle_operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package framework

import (
"encoding/json"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -37,7 +36,7 @@ type ConfigLifecycleOps interface {
// GetConfig gets the tanzu config
GetConfig() (*configapi.ClientConfig, error)
// ConfigServerList returns the server list
ConfigServerList() ([]Server, error)
ConfigServerList() ([]*Server, error)
// ConfigServerDelete deletes given server from tanzu config
ConfigServerDelete(serverName string) error
// DeleteCLIConfigurationFiles deletes cli configuration files
Expand All @@ -48,18 +47,18 @@ type ConfigLifecycleOps interface {

// configOps is the implementation of ConfOps interface
type configOps struct {
CmdOps
cmdExe CmdOps
}

func NewConfOps() ConfigLifecycleOps {
return &configOps{
CmdOps: NewCmdOps(),
cmdExe: NewCmdOps(),
}
}

// GetConfig gets the tanzu config
func (co *configOps) GetConfig() (*configapi.ClientConfig, error) {
out, _, err := co.Exec(ConfigGet)
out, _, err := co.cmdExe.Exec(ConfigGet)
var cnf *configapi.ClientConfig
if err != nil {
return cnf, err
Expand All @@ -74,7 +73,7 @@ func (co *configOps) GetConfig() (*configapi.ClientConfig, error) {
// ConfigSetFeatureFlag sets the given tanzu config feature flag
func (co *configOps) ConfigSetFeatureFlag(path, value string) (err error) {
confSetCmd := ConfigSet + path + " " + value
_, _, err = co.Exec(confSetCmd)
_, _, err = co.cmdExe.Exec(confSetCmd)
return err
}

Expand All @@ -95,38 +94,26 @@ func (co *configOps) ConfigGetFeatureFlag(path string) (string, error) {
// ConfigUnsetFeature un-sets the tanzu config feature flag
func (co *configOps) ConfigUnsetFeature(path string) (err error) {
unsetFeatureCmd := ConfigUnset + path
_, _, err = co.Exec(unsetFeatureCmd)
_, _, err = co.cmdExe.Exec(unsetFeatureCmd)
return
}

// ConfigInit performs "tanzu config init"
func (co *configOps) ConfigInit() (err error) {
_, _, err = co.Exec(ConfigInit)
_, _, err = co.cmdExe.Exec(ConfigInit)
return
}

// ConfigServerList returns the server list
func (co *configOps) ConfigServerList() ([]Server, error) {
func (co *configOps) ConfigServerList() ([]*Server, error) {
ConfigServerListWithJSONOutput := ConfigServerList + JSONOutput
stdOut, _, err := co.Exec(ConfigServerListWithJSONOutput)
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
return ExecuteCmdAndBuildJSONOutput[Server](co.cmdExe, ConfigServerListWithJSONOutput)
}

// ConfigServerDelete deletes a server from tanzu config
func (co *configOps) ConfigServerDelete(serverName string) error {
configDelCmd := fmt.Sprintf(ConfigServerDelete, serverName)
_, _, err := co.Exec(configDelCmd)
_, _, err := co.cmdExe.Exec(configDelCmd)
if err != nil {
log.Error(err, "error while running: "+configDelCmd)
}
Expand Down
16 changes: 3 additions & 13 deletions test/e2e/framework/context_lifecycle_operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type ContextCmdOps interface {
// GetContext helps to run `context get` command
GetContext(contextName string) (ContextInfo, error)
// ListContext helps to run `context list` command
ListContext() ([]ContextListInfo, error)
ListContext() ([]*ContextListInfo, error)
// DeleteContext helps to run `context delete` command
DeleteContext(contextName string) error
// GetActiveContext returns current active context
Expand Down Expand Up @@ -62,18 +62,8 @@ func (cc *contextCmdOps) GetContext(contextName string) (ContextInfo, error) {
return contextInfo, nil
}

func (cc *contextCmdOps) ListContext() ([]ContextListInfo, error) {
out, _, err := cc.cmdExe.Exec(ListContextOutputInJSON)
if err != nil {
return nil, err
}
jsonStr := out.String()
var list []ContextListInfo
err = json.Unmarshal([]byte(jsonStr), &list)
if err != nil {
return nil, errors.Wrap(err, "failed to construct json node from context list output:"+jsonStr)
}
return list, nil
func (cc *contextCmdOps) ListContext() ([]*ContextListInfo, error) {
return ExecuteCmdAndBuildJSONOutput[ContextListInfo](cc.cmdExe, ListContextOutputInJSON)
}

func (cc *contextCmdOps) GetActiveContext(targetType string) (string, error) {
Expand Down
67 changes: 42 additions & 25 deletions test/e2e/framework/framework.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,23 @@ const (
ConfigServerDelete = "tanzu config server delete %s -y"

// Plugin commands
AddPluginSource = "tanzu plugin source add --name %s --type %s --uri %s"
UpdatePluginSource = "tanzu plugin source update %s --type %s --uri %s"
ListPluginSources = "tanzu plugin source list -o json"
DeletePluginSource = "tanzu plugin source delete %s"
ListPluginsCmdInJSON = "tanzu plugin list -o json"
SearchPluginsCmd = "tanzu plugin search"
InstallPluginCmd = "tanzu plugin install %s"
DescribePluginCmd = "tanzu plugin describe %s"
UninstallPLuginCmd = "tanzu plugin delete %s --yes"
CleanPluginsCmd = "tanzu plugin clean"
JSONOutput = " -o json"
TestPluginsPrefix = "test-plugin-"
PluginSubCommand = "tanzu %s"
PluginKey = "%s_%s_%s" // Plugins - Name_Target_Versions
AddPluginSource = "tanzu plugin source add --name %s --type %s --uri %s"
UpdatePluginSource = "tanzu plugin source update %s --type %s --uri %s"
ListPluginSourcesWithJSONOutputFlag = "tanzu plugin source list -o json"
DeletePluginSource = "tanzu plugin source delete %s"
ListPluginsCmdWithJSONOutputFlag = "tanzu plugin list -o json"
SearchPluginsCmd = "tanzu plugin search"
SearchPluginGroupsCmd = "tanzu plugin group search"
InstallPluginCmd = "tanzu plugin install %s"
InstallPluginFromGroupCmd = "tanzu plugin install %s --group %s"
InstallAllPluginsFromGroupCmd = "tanzu plugin install --group %s"
DescribePluginCmd = "tanzu plugin describe %s"
UninstallPLuginCmd = "tanzu plugin delete %s --yes"
CleanPluginsCmd = "tanzu plugin clean"
JSONOutput = " -o json"
TestPluginsPrefix = "test-plugin-"
PluginSubCommand = "tanzu %s"
PluginKey = "%s_%s_%s" // Plugins - Name_Target_Versions

// Central repository
CentralRepositoryPreReleaseRepoImage = "TANZU_CLI_PRE_RELEASE_REPO_IMAGE"
Expand Down Expand Up @@ -73,19 +76,26 @@ const (
StartDockerUbuntu = "sudo systemctl start docker"
StopDockerUbuntu = "sudo systemctl stop docker"

TMC = "tmc"
TKG = "tkg"
TestDir = ".tanzu-cli-e2e"
TestPluginsDir = ".e2e-test-plugins"
TargetTypeTMC = "mission-control"
TargetTypeK8s = "kubernetes"
SourceType = "oci"
GlobalTarget = "global"

// log info
ExecutingCommand = "Executing command: %s"

// Error messages
UnableToFindPluginForTarget = "unable to find plugin '%s' for target '%s'"
UnableToFindPlugin = "unable to find plugin '%s'"
InvalidTargetSpecified = "invalid target specified. Please specify correct value of `--target` or `-t` flag from 'global/kubernetes/k8s/mission-control/tmc'"
UnknownDiscoverySourceType = "unknown discovery source type"
DiscoverySourceNotFound = "cli discovery source not found"
UnableToFindPluginForTarget = "unable to find plugin '%s' for target '%s'"
UnableToFindPlugin = "unable to find plugin '%s'"
InvalidTargetSpecified = "invalid target specified. Please specify correct value of `--target` or `-t` flag from 'global/kubernetes/k8s/mission-control/tmc'"
InvalidTargetGlobal = "invalid target for plugin: global"
UnknownDiscoverySourceType = "unknown discovery source type"
DiscoverySourceNotFound = "cli discovery source not found"
ErrorLogForCommandWithErrAndStdErr = "error while executing command:'%s', error:'%s' stdErr:'%s'"
FailedToConstructJSONNodeFromOutputAndErrInfo = "failed to construct json node from output:'%s' error:'%s' "
FailedToConstructJSONNodeFromOutput = "failed to construct json node from output:'%s'"
)

var (
Expand All @@ -95,7 +105,10 @@ var (
)

// PluginsForLifeCycleTests is list of plugins (which are published in local central repo) used in plugin life cycle test cases
var PluginsForLifeCycleTests []PluginInfo
var PluginsForLifeCycleTests []*PluginInfo

// PluginGroupsForLifeCycleTests is list of plugin groups (which are published in local central repo) used in plugin group life cycle test cases
var PluginGroupsForLifeCycleTests []*PluginGroup

// CLICoreDescribe annotates the test with the CLICore label.
func CLICoreDescribe(text string, body func()) bool {
Expand Down Expand Up @@ -130,7 +143,11 @@ func init() {
TestPluginsDirPath = filepath.Join(TestDirPath, TestPluginsDir)
TestStandalonePluginsPath = filepath.Join(filepath.Join(filepath.Join(filepath.Join(TestDirPath, ".config"), "tanzu-plugins"), "discovery"), "standalone")
_ = CreateDir(TestStandalonePluginsPath)
// TODO:cpamuluri: need to move plugins info to configuration file with positive and negative use cases
PluginsForLifeCycleTests = make([]PluginInfo, 3)
PluginsForLifeCycleTests = []PluginInfo{{Name: "cluster", Target: "kubernetes", Version: "v9.9.9", Description: "cluster functionality"}, {Name: "cluster", Target: "mission-control", Version: "v9.9.9", Description: "cluster functionality"}, {Name: "pinniped-auth", Target: "global", Version: "v9.9.9", Description: "pinniped-auth functionality"}}
// TODO:cpamuluri: need to move plugins info to configuration file with positive and negative use cases - github issue: https://github.com/vmware-tanzu/tanzu-cli/issues/122
PluginsForLifeCycleTests = make([]*PluginInfo, 3)
PluginsForLifeCycleTests = []*PluginInfo{{Name: "cluster", Target: "kubernetes", Version: "v9.9.9", Description: "cluster functionality"}, {Name: "cluster", Target: "mission-control", Version: "v9.9.9", Description: "cluster functionality"}, {Name: "pinniped-auth", Target: "global", Version: "v9.9.9", Description: "pinniped-auth functionality"}}

// TODO:cpamuluri: need to move Plugin Groups to configuration file with positive and negative use cases - github issue: https://github.com/vmware-tanzu/tanzu-cli/issues/122
PluginGroupsForLifeCycleTests = make([]*PluginGroup, 2)
PluginGroupsForLifeCycleTests = []*PluginGroup{{Group: "vmware-tmc/v9.9.9"}, {Group: "vmware-tkg/v9.9.9"}}
}
Loading

0 comments on commit b7f962b

Please sign in to comment.