diff --git a/test/e2e/context/tmc/context_tmc_lifecycle_test.go b/test/e2e/context/tmc/context_tmc_lifecycle_test.go index e8514e3fa..12e986aaa 100644 --- a/test/e2e/context/tmc/context_tmc_lifecycle_test.go +++ b/test/e2e/context/tmc/context_tmc_lifecycle_test.go @@ -63,7 +63,7 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Context-lifecycle-tmc]", // Test case: b. Create context for TMC target with TMC cluster URL as endpoint It("create tmc context with endpoint", func() { ctxName := ContextNamePrefix + framework.RandomString(4) - err := tf.ContextCmd.CreateContextWithEndPointStaging(ctxName, clusterInfo.EndPoint) + _, err := tf.ContextCmd.CreateContextWithEndPointStaging(ctxName, clusterInfo.EndPoint) Expect(err).To(BeNil(), "context should create without any error") Expect(framework.IsContextExists(tf, ctxName)).To(BeTrue(), fmt.Sprintf(ContextShouldExistsAsCreated, ctxName)) contextNames = append(contextNames, ctxName) @@ -71,7 +71,7 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Context-lifecycle-tmc]", // Test case: c. (negative test) Create context for TMC target with TMC cluster "incorrect" URL as endpoint It("create tmc context with incorrect endpoint", func() { ctxName := ContextNamePrefix + framework.RandomString(4) - err := tf.ContextCmd.CreateContextWithEndPointStaging(ctxName, framework.RandomString(4)) + _, err := tf.ContextCmd.CreateContextWithEndPointStaging(ctxName, framework.RandomString(4)) Expect(err).ToNot(BeNil()) Expect(strings.Contains(err.Error(), framework.FailedToCreateContext)).To(BeTrue()) Expect(framework.IsContextExists(tf, ctxName)).To(BeFalse(), fmt.Sprintf(ContextShouldNotExists, ctxName)) @@ -80,7 +80,7 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Context-lifecycle-tmc]", It("create tmc context with endpoint and with incorrect api token", func() { os.Setenv(framework.TanzuAPIToken, framework.RandomString(4)) ctxName := framework.RandomString(4) - err := tf.ContextCmd.CreateContextWithEndPointStaging(ctxName, clusterInfo.EndPoint) + _, err := tf.ContextCmd.CreateContextWithEndPointStaging(ctxName, clusterInfo.EndPoint) os.Setenv(framework.TanzuAPIToken, clusterInfo.APIKey) Expect(err).ToNot(BeNil()) Expect(strings.Contains(err.Error(), framework.FailedToCreateContext)).To(BeTrue()) @@ -89,7 +89,7 @@ var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Context-lifecycle-tmc]", // Test case: e. Create context for TMC target with TMC cluster URL as endpoint, and validate the active context, should be recently create context It("create tmc context with endpoint and check active context", func() { ctxName := ContextNamePrefix + framework.RandomString(4) - err := tf.ContextCmd.CreateContextWithEndPointStaging(ctxName, clusterInfo.EndPoint) + _, err := tf.ContextCmd.CreateContextWithEndPointStaging(ctxName, clusterInfo.EndPoint) Expect(err).To(BeNil(), "context should create without any error") Expect(framework.IsContextExists(tf, ctxName)).To(BeTrue(), fmt.Sprintf(ContextShouldExistsAsCreated, ctxName)) contextNames = append(contextNames, ctxName) diff --git a/test/e2e/framework/context_create_operations.go b/test/e2e/framework/context_create_operations.go index 7a4650cee..d21862ad1 100644 --- a/test/e2e/framework/context_create_operations.go +++ b/test/e2e/framework/context_create_operations.go @@ -16,7 +16,8 @@ type ContextCreateOps interface { // CreateContextWithEndPoint creates a context with a given endpoint URL CreateContextWithEndPoint(contextName, endpoint string) error // CreateContextWithEndPointStaging creates a context with a given endpoint URL for staging - CreateContextWithEndPointStaging(contextName, endpoint string) error + // returns stdout and error + CreateContextWithEndPointStaging(contextName, endpoint string) (string, error) // CreateContextWithKubeconfig creates a context with the given kubeconfig file path and a context from the kubeconfig file CreateContextWithKubeconfig(contextName, kubeconfigPath, kubeContext string) error // CreateContextWithDefaultKubeconfig creates a context with the default kubeconfig file and a given input context name if it exists in the default kubeconfig file @@ -45,15 +46,15 @@ func (cc *contextCreateOps) CreateContextWithEndPoint(contextName, endpoint stri return err } -func (cc *contextCreateOps) CreateContextWithEndPointStaging(contextName, endpoint string) error { +func (cc *contextCreateOps) CreateContextWithEndPointStaging(contextName, endpoint string) (string, error) { createContextCmd := fmt.Sprintf(CreateContextWithEndPointStaging, endpoint, contextName) out, _, err := cc.cmdExe.Exec(createContextCmd) if err != nil { log.Info(fmt.Sprintf(FailedToCreateContextWithStdout, out.String())) - return errors.Wrap(err, fmt.Sprintf(FailedToCreateContextWithStdout, out.String())) + return out.String(), errors.Wrap(err, fmt.Sprintf(FailedToCreateContextWithStdout, out.String())) } log.Infof(ContextCreated, contextName) - return err + return out.String(), err } func (cc *contextCreateOps) CreateContextWithKubeconfig(contextName, kubeconfigPath, kubeContext string) error { diff --git a/test/e2e/framework/framework.go b/test/e2e/framework/framework.go index 979750ae8..97806e4f7 100644 --- a/test/e2e/framework/framework.go +++ b/test/e2e/framework/framework.go @@ -164,6 +164,7 @@ func CLICoreDescribe(text string, body func()) bool { // Framework has all helper functions to write CLI e2e test cases type Framework struct { + Exec CmdOps CliOps Config ConfigLifecycleOps KindCluster ClusterOps diff --git a/test/e2e/framework/output_handling.go b/test/e2e/framework/output_handling.go index 79a348d25..ece795db5 100644 --- a/test/e2e/framework/output_handling.go +++ b/test/e2e/framework/output_handling.go @@ -58,3 +58,13 @@ type Server struct { Path string `json:"path"` Type string `json:"type"` } + +type TMCPluginsCRD struct { + PluginsInfo struct { + Plugins []struct { + Name string `yaml:"name"` + Description string `yaml:"description"` + RecommendedVersion string `yaml:"recommendedVersion"` + } `yaml:"plugins"` + } `yaml:"pluginsInfo"` +} diff --git a/test/e2e/plugin_sync/plugin_sync_lifecycle_suite_test.go b/test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_suite_test.go similarity index 96% rename from test/e2e/plugin_sync/plugin_sync_lifecycle_suite_test.go rename to test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_suite_test.go index d0d5e3542..6387daf65 100644 --- a/test/e2e/plugin_sync/plugin_sync_lifecycle_suite_test.go +++ b/test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_suite_test.go @@ -1,8 +1,8 @@ // Copyright 2023 VMware, Inc. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// pluginsynce2e provides plugin sync command specific E2E test cases -package pluginsynce2e +// pluginsynce2ek8s provides plugin sync command specific E2E test cases +package pluginsynce2ek8s import ( "fmt" @@ -19,7 +19,7 @@ import ( func TestPluginSyncLifecycle(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Plugin-Sync-Lifecycle E2E Test Suite") + RunSpecs(t, "Plugin-Sync-k8s-Lifecycle E2E Test Suite") } var ( diff --git a/test/e2e/plugin_sync/plugin_sync_lifecycle_test.go b/test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_test.go similarity index 99% rename from test/e2e/plugin_sync/plugin_sync_lifecycle_test.go rename to test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_test.go index 31539568f..919a110fd 100644 --- a/test/e2e/plugin_sync/plugin_sync_lifecycle_test.go +++ b/test/e2e/plugin_sync/k8s/plugin_sync_k8s_lifecycle_test.go @@ -1,8 +1,8 @@ // Copyright 2023 VMware, Inc. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// pluginsynce2e provides plugin sync command specific E2E test cases -package pluginsynce2e +// pluginsynce2ek8s provides plugin sync command specific E2E test cases +package pluginsynce2ek8s import ( "fmt" diff --git a/test/e2e/plugin_sync/tmc/config/routes.json b/test/e2e/plugin_sync/tmc/config/routes.json new file mode 100644 index 000000000..5c13a6ffa --- /dev/null +++ b/test/e2e/plugin_sync/tmc/config/routes.json @@ -0,0 +1,3 @@ +{ + "/v1alpha1/system/binaries/plugins": "/plugins" +} diff --git a/test/e2e/plugin_sync/tmc/plugin_sync_tmc_lifecycle_suite_test.go b/test/e2e/plugin_sync/tmc/plugin_sync_tmc_lifecycle_suite_test.go new file mode 100644 index 000000000..2aece8573 --- /dev/null +++ b/test/e2e/plugin_sync/tmc/plugin_sync_tmc_lifecycle_suite_test.go @@ -0,0 +1,137 @@ +// Copyright 2023 VMware, Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// pluginsynce2etmc provides plugin sync command specific E2E test cases +package pluginsynce2etmc + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vmware-tanzu/tanzu-cli/test/e2e/framework" + helper "github.com/vmware-tanzu/tanzu-cli/test/e2e/plugin_lifecycle" +) + +func TestPluginSyncLifecycle(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Plugin-Sync-TMC-Lifecycle E2E Test Suite") +} + +var ( + tf *framework.Framework + e2eTestLocalCentralRepoURL string + pluginsSearchList []*framework.PluginInfo + pluginGroups []*framework.PluginGroup + pluginGroupToPluginListMap map[string][]*framework.PluginInfo + routesFilePath, serverFilePath, tmcConfigDir string +) + +const routesMapping = "{\"/v1alpha1/system/binaries/plugins\": \"/pluginsInfo\"}" +const routesFile = "routes.json" +const serverFile = "server.json" +const CRDFilePath = "../framework/config/cli.tanzu.vmware.com_cliplugins.yaml" +const numberOfPluginsToInstall = 3 +const startRestAPIMockServerCMD = "docker run --init --rm -d -p 80:80 --name %s -v %s:/data/ clue/json-server %s --routes %s" +const stopRestAPIMockServerCMD = "docker container stop %s" +const restAPIMockContainerName = "restAPIMockServer" +const ContextNamePrefix = "tmc-sync-" +const mockServerEndpoint = "http://localhost:80" + +// BeforeSuite initializes and set up the environment to execute the plugin life cycle and plugin group life cycle end-to-end test cases +var _ = BeforeSuite(func() { + tf = framework.NewFramework() + + // remove this + os.Setenv(framework.TanzuAPIToken, "8bczHt0X4G5rPoVzFnkgM8p5s7YE5FngQ9sqCqc6UrQWBTGMyPP_Jsu6k7xATffV") + os.Setenv(framework.TanzuCliE2ETestLocalCentralRepositoryURL, "localhost:9876/tanzu-cli/plugins/central:small") + os.Setenv("TANZU_CLI_PLUGIN_DISCOVERY_IMAGE_SIGNATURE_VERIFICATION_SKIP_LIST", "localhost:9876/tanzu-cli/plugins/central:small") + + // check E2E test central repo URL (TANZU_CLI_E2E_TEST_LOCAL_CENTRAL_REPO_URL) + e2eTestLocalCentralRepoURL = os.Getenv(framework.TanzuCliE2ETestLocalCentralRepositoryURL) + Expect(e2eTestLocalCentralRepoURL).NotTo(BeEmpty(), fmt.Sprintf("environment variable %s should set with local central repository URL", framework.TanzuCliE2ETestLocalCentralRepositoryURL)) + // set E2E test central repo URL to TANZU_CLI_PRE_RELEASE_REPO_IMAGE + os.Setenv(framework.CentralRepositoryPreReleaseRepoImage, e2eTestLocalCentralRepoURL) + // check + Expect(os.Getenv(framework.TanzuAPIToken)).NotTo(BeEmpty(), fmt.Sprintf("environment variable %s should set with TMC API Token", framework.TanzuAPIToken)) + + pwd, err := os.Getwd() + Expect(err).To(BeNil(), "should not get any error for getting working directory") + tmcConfigDir = filepath.Join(pwd, "config") + routesFilePath = filepath.Join(tmcConfigDir, routesFile) + serverFilePath = filepath.Join(tmcConfigDir, serverFile) + + /* + tmcConfigDir = filepath.Join(framework.FullPathForTempDir, "tmc") + _ = framework.CreateDir(tmcConfigDir) + */ + + // search plugin groups and make sure there plugin groups available + pluginGroups = helper.SearchAllPluginGroups(tf) + + // check all required plugin groups (framework.PluginGroupsForLifeCycleTests) need for life cycle test are available in plugin group search output + Expect(framework.IsAllPluginGroupsExists(pluginGroups, framework.PluginGroupsForLifeCycleTests)).Should(BeTrue(), "all required plugin groups for life cycle tests should exists in plugin group search output") + + // search plugins and make sure there are plugins available + pluginsSearchList = helper.SearchAllPlugins(tf) + Expect(len(pluginsSearchList)).Should(BeNumerically(">", 0)) + + // check all required plugins (framework.PluginsForLifeCycleTests) for plugin life cycle e2e are available in plugin search output + framework.CheckAllPluginsExists(pluginsSearchList, framework.PluginsForLifeCycleTests) + + pluginGroupToPluginListMap = framework.MapPluginsToPluginGroups(pluginsSearchList, framework.PluginGroupsForLifeCycleTests) + for pluginGroupLatest := range framework.PluginGroupsLatestToOldVersions { + framework.CopyPluginsBetweenPluginGroupsAndUpdatePluginsVersion(pluginGroupToPluginListMap, pluginGroupLatest, framework.PluginGroupsLatestToOldVersions[pluginGroupLatest], strings.Split(framework.PluginGroupsLatestToOldVersions[pluginGroupLatest], "/")[1]) + } + + // check for every plugin group (in framework.PluginGroupsForLifeCycleTests) there should be plugins available + for pg := range pluginGroupToPluginListMap { + Expect(len(pluginGroupToPluginListMap[pg])).Should(BeNumerically(">", 0), "there should be at least one plugin available for each plugin group in plugin group life cycle list") + } +}) + +// AfterSuite deletes the temp directory created during test cases execution +var _ = AfterSuite(func() { + err := os.RemoveAll(framework.FullPathForTempDir) // delete an entire directory + Expect(err).To(BeNil(), "should not get any error while deleting temp directory") +}) + +func ApplyConfigOnKindCluster(tf *framework.Framework, clusterInfo *framework.ClusterInfo, confFilePaths []string) { + for _, pluginCRFilePaths := range confFilePaths { + err := tf.KindCluster.ApplyConfig(clusterInfo.ClusterKubeContext, pluginCRFilePaths) + Expect(err).To(BeNil(), "should not get any error for config apply") + } +} + +func WriteToFileInJSONFormat(crd framework.TMCPluginsCRD, filePath string) error { + content, err := json.Marshal(crd) + if err != nil { + return err + } + err = ioutil.WriteFile(filePath, content, 0644) + if err != nil { + return err + } + return nil +} + +func StartRESTAPIMockServer(tf *framework.Framework, configPath, serverFileName, routesFileName, containerName string) error { + err := StopRestAPIMockServer(tf, containerName) + //const startRestAPIMockServerCMD = "docker run --init --rm -d -p 80:80 --name %s -v %s:/data/ clue/json-server %s --routes %s" + cmd := fmt.Sprintf(startRestAPIMockServerCMD, containerName, configPath, serverFileName, routesFileName) + _, _, err = tf.Exec.Exec(cmd) + return err +} + +func StopRestAPIMockServer(tf *framework.Framework, containerName string) error { + cmd := fmt.Sprintf(stopRestAPIMockServerCMD, containerName) + _, _, err := tf.Exec.Exec(cmd) + return err +} diff --git a/test/e2e/plugin_sync/tmc/plugin_sync_tmc_lifecycle_test.go b/test/e2e/plugin_sync/tmc/plugin_sync_tmc_lifecycle_test.go new file mode 100644 index 000000000..4a999c240 --- /dev/null +++ b/test/e2e/plugin_sync/tmc/plugin_sync_tmc_lifecycle_test.go @@ -0,0 +1,379 @@ +// Copyright 2023 VMware, Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +// pluginsynce2etmc provides plugin sync command specific E2E test cases +package pluginsynce2etmc + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + + "github.com/vmware-tanzu/tanzu-cli/test/e2e/framework" + "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" +) + +// docker run --init --rm -d -p 80:80 --name mockserver -v /Users/cpamuluri/tkg/tasks/mockerServer/http:/data/ clue/json-server server.json --routes routes.json +// docker container stop mockserver +var _ = framework.CLICoreDescribe("[Tests:E2E][Feature:Plugin-Group-lifecycle]", func() { + + // Use case 1: create a KIND cluster, don't apply CRD and CRs, create context, make sure no plugins are installed + // a. create k8s context for the KIND cluster + // b. create context and validate current active context + // c. list plugins and make sure no plugins installed + // d. delete current context and KIND cluster + Context("plugin install from group: install a plugin from a specific plugin group", func() { + var contextName string + var err error + // Test case: a. mock tmc endpoint with empty response and star the mock rest api server + It("start REST API mock server", func() { + //(tf *framework.Framework, configPath, serverFileName, routesFileName, containerName string + err := StartRESTAPIMockServer(tf, tmcConfigDir, serverFilePath, routesFilePath, restAPIMockContainerName) + Expect(err).To(BeNil(), "there should not be any error while starting rest api mock server") + }) + // Test case: b. create context and validate current active context + It("create context with kubeconfig and context", func() { + By("create context with kubeconfig and context") + ctxName := ContextNamePrefix + framework.RandomString(4) + _, err = tf.ContextCmd.CreateContextWithEndPointStaging(ctxName, mockServerEndpoint) + Expect(err).To(BeNil(), "context should create without any error") + active, err := tf.ContextCmd.GetActiveContext(string(types.TargetTMC)) + Expect(err).To(BeNil(), "there should be a active context") + Expect(active).To(Equal(contextName), "the active context should be recently added context") + }) + /* + // Test case: c. list plugins and make sure no plugins installed + It("list plugins and check number plugins should be same as installed in previous test", func() { + pluginsList, err := tf.PluginCmd.ListPluginsForGivenContext(contextName, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsList)).Should(Equal(0), "there should not be any context specific plugins") + }) + // Test case: d. delete current context and KIND cluster + It("delete current context and the KIND cluster", func() { + err = tf.ContextCmd.DeleteContext(contextName) + Expect(err).To(BeNil(), "context should be deleted without error") + _, err := tf.KindCluster.DeleteCluster(clusterInfo.Name) + Expect(err).To(BeNil(), "kind cluster should be deleted without any error") + }) + */ + }) + /* + // Use case 2: Create kind cluster, apply CRD and CRs, create context, should install all plugins, uninstall the specific plugin, and perform plugin sync: + // Steps: + // a. create KIND cluster, apply CRD + // b. apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins + // c. create context and make sure context has created + // d. list plugins and validate plugins info, make sure all plugins installed for which CR's has applied to KIND cluster + // e. uninstall one of the installed plugin, make sure plugin is uninstalled, + // run plugin sync, make sure the uninstalled plugin has installed again. + // f. delete current context and KIND cluster + + Context("Use case: Install KIND Cluster, Apply CRD, Apply specific plugin CRs, create context and validate plugin sync", func() { + var clusterInfo *framework.ClusterInfo + var pluginCRFilePaths []string + var pluginsInfoForCRsApplied, installedPluginsList []*framework.PluginInfo + var contextName string + var err error + // Test case: a. create KIND cluster, apply CRD + It("create KIND cluster", func() { + // Create KIND cluster, which is used in test cases to create context's + clusterInfo, err = framework.CreateKindCluster(tf, "sync-e2e-"+framework.RandomNumber(4)) + Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") + }) + // Test case: b. apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins + It("apply CRD and CRs to KIND cluster", func() { + ApplyConfigOnKindCluster(tf, clusterInfo, append(make([]string, 0), CRDFilePath)) + + pluginsToGenerateCRs, ok := pluginGroupToPluginListMap[framework.PluginGroupsForLifeCycleTests[0].Group] + Expect(ok).To(BeTrue(), "plugin group is not exist in the map") + Expect(len(pluginsToGenerateCRs) > numberOfPluginsToInstall).To(BeTrue(), "we don't have enough plugins in local test central repo") + pluginsInfoForCRsApplied, pluginCRFilePaths, err = framework.CreateTemporaryCRsForPluginsInGivenPluginGroup(pluginsToGenerateCRs[:numberOfPluginsToInstall]) + Expect(err).To(BeNil(), "should not get any error while generating CR files") + ApplyConfigOnKindCluster(tf, clusterInfo, pluginCRFilePaths) + }) + + // Test case: c. create context and make sure context has created + It("create context with kubeconfig and context", func() { + By("create context with kubeconfig and context") + contextName = "sync-e2e-" + framework.RandomString(4) + err := tf.ContextCmd.CreateContextWithKubeconfig(contextName, clusterInfo.KubeConfigPath, clusterInfo.ClusterKubeContext) + Expect(err).To(BeNil(), "context should create without any error") + active, err := tf.ContextCmd.GetActiveContext(string(types.TargetK8s)) + Expect(err).To(BeNil(), "there should be a active context") + Expect(active).To(Equal(contextName), "the active context should be recently added context") + }) + // Test case: d. list plugins and validate plugins info, make sure all plugins are installed for which CRs were present on the cluster + It("list plugins and validate plugins being installed after context being created", func() { + installedPluginsList, err = tf.PluginCmd.ListPluginsForGivenContext(contextName, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(installedPluginsList)).Should(Equal(len(pluginsInfoForCRsApplied)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(installedPluginsList, pluginsInfoForCRsApplied)).Should(BeTrue(), " plugins being installed and plugins info for which CRs applied should be same") + }) + + // Test case: e. uninstall one of the installed plugin, make sure plugin is uninstalled, + // run plugin sync, make sure the uninstalled plugin has installed again. + It("Uninstall one of the installed plugin", func() { + pluginToUninstall := pluginsInfoForCRsApplied[0] + err := tf.PluginCmd.UninstallPlugin(pluginToUninstall.Name, pluginToUninstall.Target) + Expect(err).To(BeNil(), "should not get any error for plugin uninstall") + + latestPluginsInstalledList := pluginsInfoForCRsApplied[1:] + allPluginsList, err := tf.PluginCmd.ListPluginsForGivenContext(contextName, false) + Expect(err).To(BeNil(), "should not get any error for plugin list") + installedPluginsList = framework.GetInstalledPlugins(allPluginsList) + Expect(framework.IsPluginExists(allPluginsList, framework.GetGivenPluginFromTheGivenPluginList(allPluginsList, pluginToUninstall), framework.NotInstalled)).To(BeTrue(), "uninstalled plugin should be listed as not installed") + Expect(len(installedPluginsList)).Should(Equal(len(latestPluginsInstalledList)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(installedPluginsList, latestPluginsInstalledList)).Should(BeTrue(), " plugins being installed and plugins info for which CRs applied should be same") + + _, err = tf.PluginCmd.Sync() + Expect(err).To(BeNil(), "should not get any error for plugin sync") + + installedPluginsList, err = tf.PluginCmd.ListPluginsForGivenContext(contextName, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(installedPluginsList)).Should(Equal(len(pluginsInfoForCRsApplied)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(installedPluginsList, pluginsInfoForCRsApplied)).Should(BeTrue(), "plugins being installed and plugins info for which CRs applied should be same") + }) + // f. delete current context and the KIND cluster + It("delete current context and the KIND cluster", func() { + err = tf.ContextCmd.DeleteContext(contextName) + Expect(err).To(BeNil(), "context should be deleted without error") + _, err := tf.KindCluster.DeleteCluster(clusterInfo.Name) + Expect(err).To(BeNil(), "kind cluster should be deleted without any error") + }) + }) + + // Use case 3: Test plugin sync when central repo does not have all plugin CRs being applied in KIND cluster + // Steps: + // a. create KIND cluster + // b. apply CRD (cluster resource definition) and CRs (cluster resource) for a few plugins which are available in the central repo and CRs for plugins which are not available in the central repo + // c. create context and make sure context has been created + // d. list plugins and validate plugins info, make sure all plugins installed for which CRs have applied to the KIND cluster and are available in the central repo + // e. run plugin sync and validate the plugin list + // f. delete the KIND cluster + + Context("Use case: Install KIND Cluster, Apply CRD, Apply specific plugin CRs, create context and validate plugin sync", func() { + var clusterInfo *framework.ClusterInfo + var pluginCRFilePaths, pluginWithIncorrectVerCRFilePaths []string + var pluginsInfoForCRsApplied, pluginsWithIncorrectVer, pluginsList []*framework.PluginInfo + var contextName string + var err error + // Test case: a. create KIND cluster + It("create KIND cluster", func() { + // Create KIND cluster, which is used in test cases to create context's + clusterInfo, err = framework.CreateKindCluster(tf, "sync-e2e-"+framework.RandomNumber(4)) + Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") + }) + // Test case: b. apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins which are available in centra repo + // and CR's for plugins which are not available in central repo + It("apply CRD and CRs to KIND cluster", func() { + ApplyConfigOnKindCluster(tf, clusterInfo, append(make([]string, 0), CRDFilePath)) + pluginsToGenerateCRs, ok := pluginGroupToPluginListMap[framework.PluginGroupsForLifeCycleTests[0].Group] + Expect(ok).To(BeTrue(), "plugin group is not exist in the map") + Expect(len(pluginsToGenerateCRs) > numberOfPluginsToInstall).To(BeTrue(), "we don't have enough plugins in local test central repo") + pluginsInfoForCRsApplied, pluginCRFilePaths, err = framework.CreateTemporaryCRsForPluginsInGivenPluginGroup(pluginsToGenerateCRs[:numberOfPluginsToInstall]) + Expect(err).To(BeNil(), "should not get any error while generating CR files") + + pluginWithIncorrectVersion := *pluginsToGenerateCRs[numberOfPluginsToInstall] + pluginWithIncorrectVersion.Version = pluginWithIncorrectVersion.Version + framework.RandomNumber(2) + pluginsWithIncorrectVer, pluginWithIncorrectVerCRFilePaths, err = framework.CreateTemporaryCRsForPluginsInGivenPluginGroup(append(make([]*framework.PluginInfo, 0), &pluginWithIncorrectVersion)) + Expect(err).To(BeNil(), "should not get any error while generating CR files") + + ApplyConfigOnKindCluster(tf, clusterInfo, pluginCRFilePaths) + ApplyConfigOnKindCluster(tf, clusterInfo, pluginWithIncorrectVerCRFilePaths) + }) + + // Test case: c. create context and make sure context has created + It("create context with kubeconfig and context", func() { + By("create context with kubeconfig and context") + contextName = "sync-e2e-" + framework.RandomString(4) + err := tf.ContextCmd.CreateContextWithKubeconfig(contextName, clusterInfo.KubeConfigPath, clusterInfo.ClusterKubeContext) + Expect(err).To(BeNil(), "context should create without any error") + active, err := tf.ContextCmd.GetActiveContext(string(types.TargetK8s)) + Expect(err).To(BeNil(), "there should be a active context") + Expect(active).To(Equal(contextName), "the active context should be recently added context") + }) + // Test case: d. list plugins and validate plugins info, make sure all plugins installed for which CR's has applied to KIND cluster and available in central repo + It("list plugins and validate plugins being installed after context being created", func() { + pluginsList, err = tf.PluginCmd.ListPluginsForGivenContext(contextName, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsList)).Should(Equal(len(pluginsInfoForCRsApplied)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(pluginsList, pluginsInfoForCRsApplied)).Should(BeTrue(), " plugins being installed and plugins info for which CRs applied should be same") + }) + + // Test case: e. run plugin sync and validate the plugin list + It("Uninstall one of the installed plugin", func() { + _, err = tf.PluginCmd.Sync() + Expect(err.Error()).To(ContainSubstring(fmt.Sprintf(framework.UnableToFindPluginForTarget, pluginsWithIncorrectVer[0].Name, pluginsWithIncorrectVer[0].Target))) + + pluginsList, err = tf.PluginCmd.ListPluginsForGivenContext(contextName, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsList)).Should(Equal(len(pluginsInfoForCRsApplied)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(pluginsList, pluginsInfoForCRsApplied)).Should(BeTrue(), "plugins being installed and plugins info for which CRs applied should be same") + }) + // f. delete the KIND cluster + It("delete the KIND cluster", func() { + err = tf.ContextCmd.DeleteContext(contextName) + Expect(err).To(BeNil(), "context should be deleted without error") + _, err := tf.KindCluster.DeleteCluster(clusterInfo.Name) + Expect(err).To(BeNil(), "kind cluster should be deleted without any error") + }) + }) + + // Use case 4: test delete context use case, it should uninstall plugins installed for the context + // Steps: + // a. create KIND cluster + // b. apply CRD (cluster resource definition) and CRs (cluster resource) for few plugins + // c. create context and make sure context gets created, list plugins, make sure all + // plugins installed for which CRs are applied in KIND cluster + // d. delete the context, make sure all context specific plugins are uninstalled + // e. delete the KIND cluster + + Context("Use case: Install KIND Cluster, Apply CRD, Apply specific plugin CRs, create context and validate plugin sync", func() { + var clusterInfo *framework.ClusterInfo + var pluginCRFilePaths []string + var pluginsInfoForCRsApplied, pluginsList []*framework.PluginInfo + var contextName string + var err error + // Test case: a. create KIND cluster + It("create KIND cluster", func() { + // Create KIND cluster, which is used in test cases to create context's + clusterInfo, err = framework.CreateKindCluster(tf, "sync-e2e-"+framework.RandomNumber(4)) + Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") + }) + // Test case: b. apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins which are available in centra repo + // and CR's for plugins which are not available in central repo + It("apply CRD and CRs to KIND cluster", func() { + ApplyConfigOnKindCluster(tf, clusterInfo, append(make([]string, 0), CRDFilePath)) + pluginsToGenerateCRs, ok := pluginGroupToPluginListMap[framework.PluginGroupsForLifeCycleTests[0].Group] + Expect(ok).To(BeTrue(), "plugin group is not exist in the map") + Expect(len(pluginsToGenerateCRs) > numberOfPluginsToInstall).To(BeTrue(), "we don't have enough plugins in local test central repo") + pluginsInfoForCRsApplied, pluginCRFilePaths, err = framework.CreateTemporaryCRsForPluginsInGivenPluginGroup(pluginsToGenerateCRs[:numberOfPluginsToInstall]) + Expect(err).To(BeNil(), "should not get any error while generating CR files") + ApplyConfigOnKindCluster(tf, clusterInfo, pluginCRFilePaths) + }) + + // Test case: c. create context and make sure context has created, list plugins, make sure all plugins installed for which CR's are applied in KIND cluster + It("create context and validate installed plugins list, should installed all plugins for which CRs has applied in KIND cluster", func() { + By("create context with kubeconfig and context") + contextName = "sync-e2e-" + framework.RandomString(4) + err = tf.ContextCmd.CreateContextWithKubeconfig(contextName, clusterInfo.KubeConfigPath, clusterInfo.ClusterKubeContext) + Expect(err).To(BeNil(), "context should create without any error") + pluginsList, err = tf.PluginCmd.ListPluginsForGivenContext(contextName, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsList)).Should(Equal(len(pluginsInfoForCRsApplied)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(pluginsList, pluginsInfoForCRsApplied)).Should(BeTrue(), " plugins being installed and plugins info for which CRs applied should be same") + }) + // Test case: d. delete the context, make sure all context specific plugins are uninstalled + It("delete context, validate installed plugins list, should uninstalled all context plugins", func() { + err = tf.ContextCmd.DeleteContext(contextName) + Expect(err).To(BeNil(), "there should be no error for delete context") + + pluginsList, err = tf.PluginCmd.ListPluginsForGivenContext(contextName, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsList)).Should(Equal(0), "all context plugins should be uninstalled as context delete") + }) + + // Test case: e. delete the KIND cluster + It("delete the KIND cluster", func() { + Expect(err).To(BeNil(), "context should be deleted without error") + _, err := tf.KindCluster.DeleteCluster(clusterInfo.Name) + Expect(err).To(BeNil(), "kind cluster should be deleted without any error") + }) + }) + + // Use case 5: test switch context use case, make installed plugins should be updated as per the context + // Steps: + // a. create KIND clusters + // b. for both clusters, apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins + // c. for cluster one, create random context and validate the plugin list should show all plugins for which CRs are applied + // d. for cluster two, create random context and validate the plugin list should show all plugins for which CRs are applied + // e. switch context's, make sure installed plugins also updated + // f. delete the KIND clusters + + Context("Use case: Install KIND Cluster, Apply CRD, Apply specific plugin CRs, create context and validate plugin sync", func() { + var clusterOne, clusterTwo *framework.ClusterInfo + var pluginCRFilePathsClusterOne, pluginCRFilePathsClusterTwo []string + var pluginsInfoForCRsAppliedClusterOne, pluginsListClusterOne []*framework.PluginInfo + var pluginsInfoForCRsAppliedClusterTwo, pluginsListClusterTwo []*framework.PluginInfo + var contextNameClusterOne, contextNameClusterTwo string + var err error + + // Test case: a. create KIND clusters + It("create KIND cluster", func() { + // Create KIND cluster, which is used in test cases to create context's + clusterOne, err = framework.CreateKindCluster(tf, "sync-e2e-"+framework.RandomNumber(4)) + Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") + clusterTwo, err = framework.CreateKindCluster(tf, "sync-e2e-"+framework.RandomNumber(4)) + Expect(err).To(BeNil(), "should not get any error for KIND cluster creation") + }) + // Test case: b. for both clusters, apply CRD (cluster resource definition) and CR's (cluster resource) for few plugins + It("apply CRD and CRs to KIND cluster", func() { + ApplyConfigOnKindCluster(tf, clusterOne, append(make([]string, 0), CRDFilePath)) + pluginsToGenerateCRs, ok := pluginGroupToPluginListMap[framework.PluginGroupsForLifeCycleTests[0].Group] + Expect(ok).To(BeTrue(), "plugin group is not exist in the map") + Expect(len(pluginsToGenerateCRs) > numberOfPluginsToInstall*2).To(BeTrue(), "we don't have enough plugins in local test central repo") + + pluginsInfoForCRsAppliedClusterOne, pluginCRFilePathsClusterOne, err = framework.CreateTemporaryCRsForPluginsInGivenPluginGroup(pluginsToGenerateCRs[:numberOfPluginsToInstall]) + Expect(err).To(BeNil(), "should not get any error while generating CR files") + ApplyConfigOnKindCluster(tf, clusterOne, pluginCRFilePathsClusterOne) + + ApplyConfigOnKindCluster(tf, clusterTwo, append(make([]string, 0), CRDFilePath)) + pluginsInfoForCRsAppliedClusterTwo, pluginCRFilePathsClusterTwo, err = framework.CreateTemporaryCRsForPluginsInGivenPluginGroup(pluginsToGenerateCRs[numberOfPluginsToInstall : numberOfPluginsToInstall*2]) + Expect(err).To(BeNil(), "should not get any error while generating CR files") + ApplyConfigOnKindCluster(tf, clusterTwo, pluginCRFilePathsClusterTwo) + }) + + // Test case: c. for cluster one, create random context and validate the plugin list should show all plugins for which CRs are applied + It("create context and validate installed plugins list, should installed all plugins for which CRs has applied in KIND cluster", func() { + By("create context with kubeconfig and context") + contextNameClusterOne = "sync-e2e-" + framework.RandomString(4) + err = tf.ContextCmd.CreateContextWithKubeconfig(contextNameClusterOne, clusterOne.KubeConfigPath, clusterOne.ClusterKubeContext) + Expect(err).To(BeNil(), "context should create without any error") + pluginsListClusterOne, err = tf.PluginCmd.ListPluginsForGivenContext(contextNameClusterOne, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsListClusterOne)).Should(Equal(len(pluginsInfoForCRsAppliedClusterOne)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(pluginsListClusterOne, pluginsInfoForCRsAppliedClusterOne)).Should(BeTrue(), " plugins being installed and plugins info for which CRs applied should be same") + }) + + // Test case: d. for cluster two, create random context and validate the plugin list should show all plugins for which CRs are applied + It("create context and validate installed plugins list, should installed all plugins for which CRs has applied in KIND cluster", func() { + By("create context with kubeconfig and context") + contextNameClusterTwo = "sync-e2e-" + framework.RandomString(4) + err = tf.ContextCmd.CreateContextWithKubeconfig(contextNameClusterTwo, clusterTwo.KubeConfigPath, clusterTwo.ClusterKubeContext) + Expect(err).To(BeNil(), "context should create without any error") + pluginsListClusterTwo, err = tf.PluginCmd.ListPluginsForGivenContext(contextNameClusterTwo, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsListClusterTwo)).Should(Equal(len(pluginsInfoForCRsAppliedClusterTwo)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(pluginsListClusterTwo, pluginsInfoForCRsAppliedClusterTwo)).Should(BeTrue(), " plugins being installed and plugins info for which CRs applied should be same") + }) + + // Test case: e. switch context's, make sure installed plugins also updated + It("switch context, make sure installed plugins also updated", func() { + err = tf.ContextCmd.UseContext(contextNameClusterTwo) + Expect(err).To(BeNil(), "there should not be any error for use context") + pluginsListClusterTwo, err = tf.PluginCmd.ListPluginsForGivenContext(contextNameClusterTwo, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsListClusterTwo)).Should(Equal(len(pluginsInfoForCRsAppliedClusterTwo)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(pluginsListClusterTwo, pluginsInfoForCRsAppliedClusterTwo)).Should(BeTrue(), " plugins being installed and plugins info for which CRs applied should be same") + + err = tf.ContextCmd.UseContext(contextNameClusterOne) + Expect(err).To(BeNil(), "there should not be any error for use context") + pluginsListClusterOne, err = tf.PluginCmd.ListPluginsForGivenContext(contextNameClusterOne, true) + Expect(err).To(BeNil(), "should not get any error for plugin list") + Expect(len(pluginsListClusterOne)).Should(Equal(len(pluginsInfoForCRsAppliedClusterOne)), "number of plugins should be same as number of plugins CRs applied") + Expect(framework.CheckAllPluginsExists(pluginsListClusterOne, pluginsInfoForCRsAppliedClusterOne)).Should(BeTrue(), " plugins being installed and plugins info for which CRs applied should be same") + }) + + // Test case: f. delete the KIND clusters + It("delete the KIND cluster", func() { + err = tf.ContextCmd.DeleteContext(contextNameClusterOne) + Expect(err).To(BeNil(), "context should be deleted without error") + err = tf.ContextCmd.DeleteContext(contextNameClusterTwo) + Expect(err).To(BeNil(), "context should be deleted without error") + _, err = tf.KindCluster.DeleteCluster(clusterOne.Name) + Expect(err).To(BeNil(), "kind cluster should be deleted without any error") + _, err = tf.KindCluster.DeleteCluster(clusterTwo.Name) + Expect(err).To(BeNil(), "kind cluster should be deleted without any error") + }) + }) + */ +})