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 }