github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/multicluster/examples/todo-list/todo_list_example_test.go (about)

     1  // Copyright (c) 2021, 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package todo_list
     5  
     6  import (
     7  	"fmt"
     8  	dump "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/clusterdump"
     9  	"net/http"
    10  	"os"
    11  	"strconv"
    12  	"time"
    13  
    14  	"github.com/verrazzano/verrazzano/pkg/k8s/resource"
    15  	"github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework"
    16  	"github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework/metrics"
    17  
    18  	. "github.com/onsi/ginkgo/v2"
    19  	. "github.com/onsi/gomega"
    20  	"github.com/verrazzano/verrazzano/pkg/k8sutil"
    21  	"github.com/verrazzano/verrazzano/tests/e2e/pkg"
    22  	"github.com/verrazzano/verrazzano/tests/e2e/pkg/weblogic"
    23  	m1 "k8s.io/api/core/v1"
    24  )
    25  
    26  const (
    27  	pollingInterval      = 5 * time.Second
    28  	waitTimeout          = 5 * time.Minute
    29  	longWaitTimeout      = 10 * time.Minute
    30  	longPollingInterval  = 20 * time.Second
    31  	consistentlyDuration = 1 * time.Minute
    32  	sourceDir            = "todo-list"
    33  	testNamespace        = "mc-todo-list"
    34  	testProjectName      = "todo-list"
    35  )
    36  
    37  var clusterName = os.Getenv("MANAGED_CLUSTER_NAME")
    38  var adminKubeconfig = os.Getenv("ADMIN_KUBECONFIG")
    39  var managedKubeconfig = os.Getenv("MANAGED_KUBECONFIG")
    40  var metricsTest pkg.MetricsTest
    41  
    42  // failed indicates whether any of the tests has failed
    43  var failed = false
    44  var beforeSuitePassed = false
    45  
    46  var t = framework.NewTestFramework("todo_list")
    47  
    48  var _ = t.AfterEach(func() {
    49  	failed = failed || CurrentSpecReport().Failed()
    50  })
    51  
    52  var beforeSuite = t.BeforeSuiteFunc(func() {
    53  	wlsUser := "weblogic"
    54  	wlsPass := pkg.GetRequiredEnvVarOrFail("WEBLOGIC_PSW")
    55  	dbPass := pkg.GetRequiredEnvVarOrFail("DATABASE_PSW")
    56  	regServ := pkg.GetRequiredEnvVarOrFail("OCR_REPO")
    57  	regUser := pkg.GetRequiredEnvVarOrFail("OCR_CREDS_USR")
    58  	regPass := pkg.GetRequiredEnvVarOrFail("OCR_CREDS_PSW")
    59  
    60  	// deploy the VerrazzanoProject
    61  	start := time.Now()
    62  	Eventually(func() error {
    63  		return DeployTodoListProject(adminKubeconfig, sourceDir)
    64  	}, waitTimeout, pollingInterval).ShouldNot(HaveOccurred())
    65  
    66  	// wait for the namespace to be created on the cluster before deploying app
    67  	Eventually(func() bool {
    68  		return TodoListNamespaceExists(adminKubeconfig, testNamespace)
    69  	}, waitTimeout, pollingInterval).Should(BeTrue())
    70  
    71  	// create Docker repository secret
    72  	Eventually(func() (*m1.Secret, error) {
    73  		return pkg.CreateDockerSecretInCluster(testNamespace, "tododomain-repo-credentials", regServ, regUser, regPass, adminKubeconfig)
    74  	}, shortWaitTimeout, shortPollingInterval).ShouldNot(BeNil())
    75  
    76  	// create WebLogic credentials secret
    77  	Eventually(func() (*m1.Secret, error) {
    78  		return pkg.CreateCredentialsSecretInCluster(testNamespace, "tododomain-weblogic-credentials", wlsUser, wlsPass, nil, adminKubeconfig)
    79  	}, shortWaitTimeout, shortPollingInterval).ShouldNot(BeNil())
    80  
    81  	// create database credentials secret
    82  	Eventually(func() (*m1.Secret, error) {
    83  		return pkg.CreateCredentialsSecretInCluster(testNamespace, "tododomain-jdbc-tododb", wlsUser, dbPass, map[string]string{"weblogic.domainUID": "tododomain"}, adminKubeconfig)
    84  	}, shortWaitTimeout, shortPollingInterval).ShouldNot(BeNil())
    85  
    86  	Eventually(func() error {
    87  		return DeployTodoListApp(adminKubeconfig, sourceDir)
    88  	}, waitTimeout, pollingInterval).ShouldNot(HaveOccurred())
    89  
    90  	var err error
    91  	metricsTest, err = pkg.NewMetricsTest(adminKubeconfig, map[string]string{}, managedKubeconfig)
    92  	if err != nil {
    93  		AbortSuite(fmt.Sprintf("Failed to create the Metrics test object: %v", err))
    94  	}
    95  
    96  	beforeSuitePassed = true
    97  	metrics.Emit(t.Metrics.With("deployment_elapsed_time", time.Since(start).Milliseconds()))
    98  })
    99  
   100  var _ = BeforeSuite(beforeSuite)
   101  
   102  var _ = t.Describe("In Multi-cluster, verify todo-list", Label("f:multicluster.mc-app-lcm"), func() {
   103  	t.Context("Admin Cluster", func() {
   104  		// GIVEN an admin cluster and at least one managed cluster
   105  		// WHEN the example application has been deployed to the admin cluster
   106  		// THEN expect that the multi-cluster resources have been created on the admin cluster
   107  		t.It("Has multi cluster resources", func() {
   108  			Eventually(func() bool {
   109  				return VerifyMCResources(adminKubeconfig, true, false, testNamespace)
   110  			}, waitTimeout, pollingInterval).Should(BeTrue())
   111  		})
   112  		// GIVEN an admin cluster
   113  		// WHEN the multi-cluster example application has been created on admin cluster but not placed there
   114  		// THEN expect that the app is not deployed to the admin cluster consistently for some length of time
   115  		t.It("Does not have application placed", func() {
   116  			Consistently(func() bool {
   117  				result, err := VerifyTodoListInCluster(adminKubeconfig, true, false, testProjectName, testNamespace)
   118  				if err != nil {
   119  					AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err))
   120  				}
   121  				return result
   122  			}, consistentlyDuration, pollingInterval).Should(BeTrue())
   123  		})
   124  	})
   125  
   126  	t.Context("Managed Cluster", func() {
   127  		// GIVEN an admin cluster and at least one managed cluster
   128  		// WHEN the example application has been deployed to the admin cluster
   129  		// THEN expect that the multi-cluster resources have been created on the managed cluster
   130  		t.It("Has multi cluster resources", func() {
   131  			Eventually(func() bool {
   132  				return VerifyMCResources(managedKubeconfig, false, true, testNamespace)
   133  			}, waitTimeout, pollingInterval).Should(BeTrue())
   134  		})
   135  		// GIVEN an admin cluster and at least one managed cluster
   136  		// WHEN the multi-cluster example application has been created on admin cluster and placed in managed cluster
   137  		// THEN expect that the app is deployed to the managed cluster
   138  		t.It("Has application placed", func() {
   139  			Eventually(func() bool {
   140  				result, err := VerifyTodoListInCluster(managedKubeconfig, false, true, testProjectName, testNamespace)
   141  				if err != nil {
   142  					AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err))
   143  				}
   144  				return result
   145  			}, longWaitTimeout, longPollingInterval).Should(BeTrue())
   146  		})
   147  	})
   148  
   149  	t.Context("Remaining Managed Clusters", func() {
   150  		clusterCountStr := os.Getenv("CLUSTER_COUNT")
   151  		if clusterCountStr == "" {
   152  			// skip tests
   153  			return
   154  		}
   155  		clusterCount, err := strconv.Atoi(clusterCountStr)
   156  		if err != nil {
   157  			// skip tests
   158  			return
   159  		}
   160  
   161  		kubeconfigDir := os.Getenv("KUBECONFIG_DIR")
   162  		for i := 3; i <= clusterCount; i++ {
   163  			kubeconfig := kubeconfigDir + "/" + fmt.Sprintf("%d", i) + "/kube_config"
   164  			It("Does not have multi cluster resources", func() {
   165  				Eventually(func() bool {
   166  					return VerifyMCResources(kubeconfig, false, false, testNamespace)
   167  				}, waitTimeout, pollingInterval).Should(BeTrue())
   168  			})
   169  			It("Does not have application placed", func() {
   170  				Eventually(func() bool {
   171  					result, err := VerifyTodoListInCluster(kubeconfig, false, false, testProjectName, testNamespace)
   172  					if err != nil {
   173  						AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", testNamespace, err))
   174  					}
   175  					return result
   176  				}, waitTimeout, pollingInterval).Should(BeTrue())
   177  			})
   178  		}
   179  	})
   180  
   181  	t.Context("for WebLogic components", func() {
   182  		// GIVEN the ToDoList app is deployed
   183  		// WHEN the servers in the WebLogic domain is ready
   184  		// THEN the domain.servers.status.health.overallHeath fields should be ok
   185  		t.It("Verify 'todo-domain' overall health is ok", func() {
   186  			Eventually(func() bool {
   187  				domain, err := weblogic.GetDomainInCluster(testNamespace, "todo-domain", managedKubeconfig)
   188  				if err != nil {
   189  					return false
   190  				}
   191  				healths, err := weblogic.GetHealthOfServers(domain)
   192  				if err != nil || healths[0] != weblogic.Healthy {
   193  					return false
   194  				}
   195  				return true
   196  			}, waitTimeout, pollingInterval).Should(BeTrue())
   197  		})
   198  	})
   199  
   200  	t.Context("for Ingress", Label("f:mesh.ingress"), func() {
   201  		var host = ""
   202  		var err error
   203  		// Get the host from the Istio gateway resource.
   204  		// GIVEN the Istio gateway for the todo-list namespace
   205  		// WHEN GetHostnameFromGateway is called
   206  		// THEN return the host name found in the gateway.
   207  		t.It("Get host from gateway.", func() {
   208  			Eventually(func() (string, error) {
   209  				host, err = k8sutil.GetHostnameFromGatewayInCluster(testNamespace, "", managedKubeconfig)
   210  				return host, err
   211  			}, waitTimeout, pollingInterval).Should(Not(BeEmpty()))
   212  		})
   213  
   214  		// Verify the application REST endpoint is working.
   215  		// GIVEN the ToDoList app is deployed
   216  		// WHEN the UI is accessed
   217  		// THEN the expected returned page should contain an expected value.
   218  		t.It("Verify '/todo' UI endpoint is working.", func() {
   219  			Eventually(func() (*pkg.HTTPResponse, error) {
   220  				url := fmt.Sprintf("https://%s/todo/", host)
   221  				return pkg.GetWebPageInCluster(url, host, managedKubeconfig)
   222  			}, waitTimeout, pollingInterval).Should(And(pkg.HasStatus(http.StatusOK), pkg.BodyContains("Derek")))
   223  		})
   224  	})
   225  
   226  	t.Context("for Logging", Label("f:observability.logging.es"), func() {
   227  		indexName, err := pkg.GetOpenSearchAppIndexWithKC(testNamespace, adminKubeconfig)
   228  		Expect(err).To(BeNil())
   229  		// GIVEN an admin cluster and at least one managed cluster
   230  		// WHEN the example application has been deployed to the admin cluster
   231  		// THEN expect the Opensearch index for the app exists on the admin cluster Opensearch
   232  		t.It("Verify Opensearch index exists on admin cluster", func() {
   233  			Eventually(func() bool {
   234  				return pkg.LogIndexFoundInCluster(indexName, adminKubeconfig)
   235  			}, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find log index for todo-list")
   236  		})
   237  	})
   238  
   239  	t.Context("for Prometheus Metrics", Label("f:observability.monitoring.prom"), func() {
   240  
   241  		t.It("Verify scrape_duration_seconds metrics exist for managed cluster", func() {
   242  			clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig)
   243  			Eventually(func() bool {
   244  				m := make(map[string]string)
   245  				m["namespace"] = testNamespace
   246  				m[clusterNameMetricsLabel] = clusterName
   247  				return metricsTest.MetricsExist("scrape_duration_seconds", m)
   248  			}, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find base_jvm_uptime_seconds metric")
   249  		})
   250  
   251  		t.It("Verify DNE scrape_duration_seconds metrics does not exist for managed cluster", func() {
   252  			clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig)
   253  			Eventually(func() bool {
   254  				m := make(map[string]string)
   255  				m["namespace"] = testNamespace
   256  				m[clusterNameMetricsLabel] = "DNE"
   257  				return metricsTest.MetricsExist("scrape_duration_seconds", m)
   258  			}, longWaitTimeout, longPollingInterval).Should(BeFalse(), "Not expected to find base_jvm_uptime_seconds metric")
   259  		})
   260  
   261  		t.It("Verify container_cpu_cfs_periods_total metrics exist for managed cluster", func() {
   262  			clusterNameMetricsLabel, _ := pkg.GetClusterNameMetricLabel(adminKubeconfig)
   263  			Eventually(func() bool {
   264  				m := make(map[string]string)
   265  				m["namespace"] = testNamespace
   266  				m[clusterNameMetricsLabel] = clusterName
   267  				return metricsTest.MetricsExist("container_cpu_cfs_periods_total", m)
   268  			}, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find container_cpu_cfs_periods_total metric")
   269  		})
   270  	})
   271  
   272  	t.Context("Delete resources", func() {
   273  		t.It("on admin cluster", func() {
   274  			Eventually(func() error {
   275  				return cleanUp(adminKubeconfig)
   276  			}, waitTimeout, pollingInterval).ShouldNot(HaveOccurred())
   277  		})
   278  
   279  		t.It("Verify deletion on admin cluster", func() {
   280  			Eventually(func() bool {
   281  				return VerifyTodoListDeleteOnAdminCluster(adminKubeconfig, false, testNamespace, testProjectName)
   282  			}, waitTimeout, pollingInterval).Should(BeTrue())
   283  		})
   284  
   285  		t.It("Verify automatic deletion on managed cluster", func() {
   286  			Eventually(func() bool {
   287  				return VerifyTodoListDeleteOnManagedCluster(managedKubeconfig, testNamespace, testProjectName)
   288  			}, waitTimeout, pollingInterval).Should(BeTrue())
   289  		})
   290  
   291  		t.It("Delete test namespace on managed cluster", func() {
   292  			Eventually(func() error {
   293  				return pkg.DeleteNamespaceInCluster(testNamespace, managedKubeconfig)
   294  			}, waitTimeout, pollingInterval).ShouldNot(HaveOccurred())
   295  		})
   296  
   297  		t.It("Delete test namespace on admin cluster", func() {
   298  			Eventually(func() error {
   299  				return pkg.DeleteNamespaceInCluster(testNamespace, adminKubeconfig)
   300  			}, waitTimeout, pollingInterval).ShouldNot(HaveOccurred())
   301  		})
   302  	})
   303  })
   304  
   305  var afterSuite = t.AfterSuiteFunc(func() {
   306  	if failed || !beforeSuitePassed {
   307  		err := dump.ExecuteBugReport(testNamespace)
   308  		if err != nil {
   309  			return
   310  		}
   311  	}
   312  })
   313  
   314  var _ = AfterSuite(afterSuite)
   315  
   316  func cleanUp(kubeconfigPath string) error {
   317  	start := time.Now()
   318  	file, err := pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/mc-todo-list-application.yaml", sourceDir))
   319  	if err != nil {
   320  		return err
   321  	}
   322  	if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil {
   323  		return fmt.Errorf("failed to delete multi-cluster todo-list application resource: %v", err)
   324  	}
   325  
   326  	file, err = pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/todo-list-components.yaml", sourceDir))
   327  	if err != nil {
   328  		return err
   329  	}
   330  	if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil {
   331  		return fmt.Errorf("failed to delete multi-cluster todo-list component resources: %v", err)
   332  	}
   333  
   334  	file, err = pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/tododb-secret.yaml", sourceDir))
   335  	if err != nil {
   336  		return err
   337  	}
   338  	if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil {
   339  		return fmt.Errorf("failed to delete multi-cluster todo-list component resources: %v", err)
   340  	}
   341  
   342  	file, err = pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/weblogic-domain-secret.yaml", sourceDir))
   343  	if err != nil {
   344  		return err
   345  	}
   346  	if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil {
   347  		return fmt.Errorf("failed to delete multi-cluster todo-list component resources: %v", err)
   348  	}
   349  
   350  	file, err = pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/docker-registry-secret.yaml", sourceDir))
   351  	if err != nil {
   352  		return err
   353  	}
   354  	if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil {
   355  		return fmt.Errorf("failed to delete multi-cluster todo-list component resources: %v", err)
   356  	}
   357  
   358  	file, err = pkg.FindTestDataFile(fmt.Sprintf("examples/multicluster/%s/verrazzano-project.yaml", sourceDir))
   359  	if err != nil {
   360  		return err
   361  	}
   362  	if err := resource.DeleteResourceFromFileInCluster(file, kubeconfigPath); err != nil {
   363  		return fmt.Errorf("failed to delete todo-list project resource: %v", err)
   364  	}
   365  	metrics.Emit(t.Metrics.With("undeployment_elapsed_time", time.Since(start).Milliseconds()))
   366  	return nil
   367  }