github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/examples/helidonmetrics/helidon_metrics_test.go (about) 1 // Copyright (c) 2022, 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 helidonmetrics 5 6 import ( 7 "fmt" 8 "strings" 9 "time" 10 11 . "github.com/onsi/ginkgo/v2" 12 . "github.com/onsi/gomega" 13 "github.com/verrazzano/verrazzano/pkg/k8s/resource" 14 "github.com/verrazzano/verrazzano/pkg/k8sutil" 15 "github.com/verrazzano/verrazzano/tests/e2e/pkg" 16 dump "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/clusterdump" 17 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework" 18 "github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework/metrics" 19 v1 "k8s.io/api/core/v1" 20 "k8s.io/apimachinery/pkg/api/errors" 21 ) 22 23 const ( 24 longWaitTimeout = 20 * time.Minute 25 longPollingInterval = 20 * time.Second 26 shortPollingInterval = 10 * time.Second 27 shortWaitTimeout = 5 * time.Minute 28 29 ingress = "hello-helidon-ingress-rule" 30 helidonService = "hello-helidon-deployment" 31 ) 32 33 var ( 34 t = framework.NewTestFramework("helidonmetrics") 35 generatedNamespace = pkg.GenerateNamespace("helidon-metrics") 36 host = "" 37 kubeconfig string 38 metricsTest pkg.MetricsTest 39 ) 40 41 var beforeSuite = t.BeforeSuiteFunc(func() { 42 if !skipDeploy { 43 start := time.Now() 44 Eventually(func() (*v1.Namespace, error) { 45 nsLabels := map[string]string{ 46 "verrazzano-managed": "true", 47 "istio-injection": istioInjection} 48 return pkg.CreateNamespace(namespace, nsLabels) 49 }, shortWaitTimeout, shortPollingInterval).ShouldNot(BeNil()) 50 51 Eventually(func() error { 52 file, err := pkg.FindTestDataFile("examples/hello-helidon/hello-helidon-comp.yaml") 53 if err != nil { 54 return err 55 } 56 return resource.CreateOrUpdateResourceFromFileInGeneratedNamespace(file, namespace) 57 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred()) 58 Eventually(func() error { 59 file, err := pkg.FindTestDataFile("examples/hello-helidon/hello-helidon-app.yaml") 60 if err != nil { 61 return err 62 } 63 return resource.CreateOrUpdateResourceFromFileInGeneratedNamespace(file, namespace) 64 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred()) 65 66 beforeSuitePassed = true 67 metrics.Emit(t.Metrics.With("deployment_elapsed_time", time.Since(start).Milliseconds())) 68 } 69 70 t.Logs.Info("Helidon Example: check expected pods are running") 71 Eventually(func() bool { 72 result, err := pkg.PodsRunning(namespace, expectedPodsHelloHelidon) 73 if err != nil { 74 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", namespace, err)) 75 } 76 return result 77 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Helidon Example Failed to Deploy: Pods are not ready") 78 79 t.Logs.Info("Helidon Example: check expected Services are running") 80 Eventually(func() bool { 81 result, err := pkg.DoesServiceExist(namespace, helidonService) 82 if err != nil { 83 AbortSuite(fmt.Sprintf("Helidon Service %s is not running in the namespace: %v, error: %v", helidonService, namespace, err)) 84 } 85 return result 86 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Helidon Example Failed to Deploy: Services are not ready") 87 88 t.Logs.Info("Helidon Example: check expected VirtualService is ready") 89 Eventually(func() bool { 90 result, err := pkg.DoesVirtualServiceExist(namespace, ingress) 91 if err != nil { 92 AbortSuite(fmt.Sprintf("Helidon VirtualService %s is not running in the namespace: %v, error: %v", ingress, namespace, err)) 93 } 94 return result 95 }, shortWaitTimeout, longPollingInterval).Should(BeTrue(), "Helidon Example Failed to Deploy: VirtualService is not ready") 96 97 var err error 98 // Get the host from the Istio gateway resource. 99 start := time.Now() 100 t.Logs.Info("Helidon Example: check expected Gateway is ready") 101 Eventually(func() (string, error) { 102 host, err = k8sutil.GetHostnameFromGateway(namespace, "") 103 return host, err 104 }, shortWaitTimeout, shortPollingInterval).Should(Not(BeEmpty()), "Helidon Example: Gateway is not ready") 105 106 kubeconfig, err = k8sutil.GetKubeConfigLocation() 107 if err != nil { 108 AbortSuite(fmt.Sprintf("Failed to get the Kubeconfig location for the cluster: %v", err)) 109 } 110 metricsTest, err = pkg.NewMetricsTest(kubeconfig, map[string]string{}) 111 if err != nil { 112 AbortSuite(fmt.Sprintf("Failed to create the Metrics test object: %v", err)) 113 } 114 115 metrics.Emit(t.Metrics.With("get_host_name_elapsed_time", time.Since(start).Milliseconds())) 116 117 }) 118 119 var _ = BeforeSuite(beforeSuite) 120 121 var failed = false 122 var beforeSuitePassed = false 123 124 var _ = t.AfterEach(func() { 125 failed = failed || CurrentSpecReport().Failed() 126 }) 127 128 var afterSuite = t.AfterSuiteFunc(func() { 129 if failed || !beforeSuitePassed { 130 dump.ExecuteBugReport(namespace) 131 } 132 if !skipUndeploy { 133 start := time.Now() 134 // undeploy the application here 135 pkg.Log(pkg.Info, "Delete application") 136 Eventually(func() error { 137 file, err := pkg.FindTestDataFile("tests/e2e/examples/helidonmetrics/testdata/hello-helidon-app-metrics-disabled.yaml") 138 if err != nil { 139 return err 140 } 141 return resource.DeleteResourceFromFileInGeneratedNamespace(file, namespace) 142 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred()) 143 144 pkg.Log(pkg.Info, "Delete components") 145 Eventually(func() error { 146 file, err := pkg.FindTestDataFile("examples/hello-helidon/hello-helidon-comp.yaml") 147 if err != nil { 148 return err 149 } 150 return resource.DeleteResourceFromFileInGeneratedNamespace(file, namespace) 151 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred()) 152 153 pkg.Log(pkg.Info, "Wait for application pods to terminate") 154 Eventually(func() bool { 155 podsTerminated, _ := pkg.PodsNotRunning(namespace, expectedPodsHelloHelidon) 156 return podsTerminated 157 }, shortWaitTimeout, shortPollingInterval).Should(BeTrue()) 158 159 pkg.Log(pkg.Info, "Delete namespace") 160 Eventually(func() error { 161 return pkg.DeleteNamespace(namespace) 162 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred()) 163 164 pkg.Log(pkg.Info, "Wait for Finalizer to be removed") 165 Eventually(func() bool { 166 return pkg.CheckNamespaceFinalizerRemoved(namespace) 167 }, shortWaitTimeout, shortPollingInterval).Should(BeTrue()) 168 169 pkg.Log(pkg.Info, "Wait for namespace to be removed") 170 Eventually(func() bool { 171 _, err := pkg.GetNamespace(namespace) 172 return err != nil && errors.IsNotFound(err) 173 }, shortWaitTimeout, shortPollingInterval).Should(BeTrue()) 174 175 metrics.Emit(t.Metrics.With("undeployment_elapsed_time", time.Since(start).Milliseconds())) 176 } 177 }) 178 179 var _ = AfterSuite(afterSuite) 180 181 var ( 182 expectedPodsHelloHelidon = []string{"hello-helidon-deployment"} 183 waitTimeout = 10 * time.Minute 184 pollingInterval = 30 * time.Second 185 ) 186 187 var _ = t.Describe("Hello Helidon OAM App test", Label("f:app-lcm.oam", 188 "f:app-lcm.helidon-workload"), func() { 189 190 var host = "" 191 var err error 192 // Get the host from the Istio gateway resource. 193 // GIVEN the Istio gateway for the hello-helidon namespace 194 // WHEN GetHostnameFromGateway is called 195 // THEN return the host name found in the gateway. 196 t.BeforeEach(func() { 197 Eventually(func() (string, error) { 198 host, err = k8sutil.GetHostnameFromGateway(namespace, "") 199 return host, err 200 }, shortWaitTimeout, shortPollingInterval).Should(Not(BeEmpty())) 201 }) 202 203 // Verify Prometheus scrape targets 204 // GIVEN OAM hello-helidon app is deployed 205 // WHEN the appconfig is updated with metrics-trait.enabled=false 206 // THEN the application metrics target must be removed 207 t.Describe("for Metrics.", Label("f:observability.monitoring.prom"), FlakeAttempts(5), func() { 208 t.It("MetricsTrait can be disabled", func() { 209 pkg.Concurrently( 210 func() { 211 pkg.Log(pkg.Info, "Checking for scrape target existence") 212 Eventually(scrapeTargetExists, shortWaitTimeout, longPollingInterval).Should(BeTrue()) 213 }, 214 func() { 215 pkg.Log(pkg.Info, "Checking for service monitor existence") 216 Eventually(serviceMonitorExists, shortWaitTimeout, longPollingInterval).Should(BeTrue()) 217 }, 218 ) 219 pkg.Log(pkg.Info, "Disabling metrics trait") 220 Eventually(func() error { 221 file, err := pkg.FindTestDataFile("tests/e2e/examples/helidonmetrics/testdata/hello-helidon-app-metrics-disabled.yaml") 222 if err != nil { 223 return err 224 } 225 return resource.CreateOrUpdateResourceFromFileInGeneratedNamespace(file, namespace) 226 }, shortWaitTimeout, shortPollingInterval, "Failed to disable metrics").ShouldNot(HaveOccurred()) 227 pkg.Concurrently( 228 func() { 229 pkg.Log(pkg.Info, "Checking for scrape target to no longer exist") 230 Eventually(scrapeTargetExists, shortWaitTimeout, longPollingInterval).Should(BeFalse()) 231 }, 232 func() { 233 pkg.Log(pkg.Info, "Checking for service monitor to no longer exist") 234 Eventually(serviceMonitorExists, shortWaitTimeout, longPollingInterval).Should(BeFalse()) 235 }, 236 ) 237 }) 238 }) 239 }) 240 241 func serviceMonitorExists() bool { 242 smName := pkg.GetAppServiceMonitorName(namespace, "hello-helidon", "hello-helidon-component") 243 sm, err := pkg.GetServiceMonitor(namespace, smName) 244 if err != nil { 245 pkg.Log(pkg.Error, fmt.Sprintf("Failed to get the Service Monitor from the cluster: %v", err)) 246 return false 247 } 248 return sm != nil 249 } 250 251 func scrapeTargetExists() bool { 252 promSource, err := pkg.NewPrometheusSource(kubeconfig) 253 if err != nil { 254 pkg.Log(pkg.Error, fmt.Sprintf("Failed to produce a Prometheus source: %v", err)) 255 return false 256 } 257 targets, err := promSource.GetTargets() 258 if err != nil { 259 pkg.Log(pkg.Error, fmt.Sprintf("Failed to get Prometheus targets from the cluster: %v", err)) 260 return false 261 } 262 263 for _, t := range targets { 264 m := t.(map[string]interface{}) 265 scrapePool := m["scrapePool"].(string) 266 if strings.Contains(scrapePool, namespace) { 267 return true 268 } 269 } 270 return false 271 }