github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/examples/helidonconfig/helidon_config_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 helidonconfig 5 6 import ( 7 "fmt" 8 "os" 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 imagePullWaitTimeout = 40 * time.Minute 29 imagePullPollingInterval = 30 * time.Second 30 31 ingress = "helidon-config-ingress-rule" 32 helidonService = "helidon-config-deployment" 33 targetsVersion = "1.4.0" 34 ) 35 36 var ( 37 t = framework.NewTestFramework("helidonconfig") 38 generatedNamespace = pkg.GenerateNamespace("helidon-config") 39 kubeConfig = os.Getenv("KUBECONFIG") 40 host = "" 41 metricsTest pkg.MetricsTest 42 ) 43 var isMinVersion140 bool 44 45 var beforeSuite = t.BeforeSuiteFunc(func() { 46 if !skipDeploy { 47 start := time.Now() 48 Eventually(func() (*v1.Namespace, error) { 49 nsLabels := map[string]string{ 50 "verrazzano-managed": "true", 51 "istio-injection": istioInjection} 52 return pkg.CreateNamespace(namespace, nsLabels) 53 }, shortWaitTimeout, shortPollingInterval).ShouldNot(BeNil()) 54 55 Eventually(func() error { 56 file, err := pkg.FindTestDataFile("examples/helidon-config/helidon-config-comp.yaml") 57 if err != nil { 58 return err 59 } 60 return resource.CreateOrUpdateResourceFromFileInGeneratedNamespace(file, namespace) 61 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred()) 62 63 Eventually(func() error { 64 file, err := pkg.FindTestDataFile("examples/helidon-config/helidon-config-app.yaml") 65 if err != nil { 66 return err 67 } 68 return resource.CreateOrUpdateResourceFromFileInGeneratedNamespace(file, namespace) 69 }, shortWaitTimeout, shortPollingInterval, "Failed to create helidon-config application resource").ShouldNot(HaveOccurred()) 70 beforeSuitePassed = true 71 metrics.Emit(t.Metrics.With("deployment_elapsed_time", time.Since(start).Milliseconds())) 72 73 t.Logs.Info("Container image pull check") 74 Eventually(func() bool { 75 return pkg.ContainerImagePullWait(namespace, expectedPodsHelidonConfig) 76 }, imagePullWaitTimeout, imagePullPollingInterval).Should(BeTrue()) 77 } 78 kubeconfigPath, err := k8sutil.GetKubeConfigLocation() 79 if err != nil { 80 Fail(fmt.Sprintf("Failed to get default kubeconfig path: %s", err.Error())) 81 } 82 isMinVersion140, err = pkg.IsVerrazzanoMinVersion("1.4.0", kubeconfigPath) 83 if err != nil { 84 Fail(err.Error()) 85 } 86 87 // Verify helidon-config-deployment pod is running 88 // GIVEN OAM helidon-config app is deployed 89 // WHEN the component and appconfig are created 90 // THEN the expected pod must be running in the test namespace 91 t.Logs.Info("Helidon Config: check expected pods are running") 92 Eventually(func() bool { 93 result, err := pkg.PodsRunning(namespace, expectedPodsHelidonConfig) 94 if err != nil { 95 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", namespace, err)) 96 } 97 return result 98 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Helidon Config Failed to Deploy: Pods are not ready") 99 100 t.Logs.Info("Helidon Config: check expected Services are running") 101 Eventually(func() bool { 102 result, err := pkg.DoesServiceExist(namespace, helidonService) 103 if err != nil { 104 AbortSuite(fmt.Sprintf("Helidon Service %s is not running in the namespace: %v, error: %v", helidonService, namespace, err)) 105 } 106 return result 107 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Helidon Config Failed to Deploy: Services are not ready") 108 109 t.Logs.Info("Helidon Config: check expected VirtualService is ready") 110 Eventually(func() bool { 111 result, err := pkg.DoesVirtualServiceExist(namespace, ingress) 112 if err != nil { 113 AbortSuite(fmt.Sprintf("Helidon VirtualService %s is not running in the namespace: %v, error: %v", ingress, namespace, err)) 114 } 115 return result 116 }, shortWaitTimeout, longPollingInterval).Should(BeTrue(), "Helidon Config Failed to Deploy: VirtualService is not ready") 117 118 // Get the host from the Istio gateway resource. 119 start := time.Now() 120 t.Logs.Info("Helidon Config: check expected Gateway is ready") 121 Eventually(func() (string, error) { 122 host, err = k8sutil.GetHostnameFromGateway(namespace, "") 123 return host, err 124 }, shortWaitTimeout, shortPollingInterval).Should(Not(BeEmpty()), "Helidon Config: Gateway is not ready") 125 metrics.Emit(t.Metrics.With("get_host_name_elapsed_time", time.Since(start).Milliseconds())) 126 127 kubeconfig, err := k8sutil.GetKubeConfigLocation() 128 if err != nil { 129 AbortSuite(fmt.Sprintf("Failed to get the Kubeconfig location for the cluster: %v", err)) 130 } 131 metricsTest, err = pkg.NewMetricsTest(kubeconfig, map[string]string{}) 132 if err != nil { 133 AbortSuite(fmt.Sprintf("Failed to create the Metrics test object: %v", err)) 134 } 135 }) 136 137 var _ = BeforeSuite(beforeSuite) 138 139 var failed = false 140 var beforeSuitePassed = false 141 142 var _ = t.AfterEach(func() { 143 failed = failed || CurrentSpecReport().Failed() 144 }) 145 146 var afterSuite = t.AfterSuiteFunc(func() { 147 if failed || !beforeSuitePassed { 148 dump.ExecuteBugReport(namespace) 149 } 150 if !skipUndeploy { 151 start := time.Now() 152 // undeploy the application here 153 pkg.Log(pkg.Info, "Delete application") 154 Eventually(func() error { 155 file, err := pkg.FindTestDataFile("examples/helidon-config/helidon-config-app.yaml") 156 if err != nil { 157 return err 158 } 159 return resource.DeleteResourceFromFileInGeneratedNamespace(file, namespace) 160 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred()) 161 162 pkg.Log(pkg.Info, "Delete components") 163 Eventually(func() error { 164 file, err := pkg.FindTestDataFile("examples/helidon-config/helidon-config-comp.yaml") 165 if err != nil { 166 return err 167 } 168 return resource.DeleteResourceFromFileInGeneratedNamespace(file, namespace) 169 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred()) 170 171 pkg.Log(pkg.Info, "Wait for application pods to terminate") 172 Eventually(func() bool { 173 podsTerminated, _ := pkg.PodsNotRunning(namespace, expectedPodsHelidonConfig) 174 return podsTerminated 175 }, shortWaitTimeout, shortPollingInterval).Should(BeTrue()) 176 177 pkg.Log(pkg.Info, "Delete namespace") 178 Eventually(func() error { 179 return pkg.DeleteNamespace(namespace) 180 }, shortWaitTimeout, shortPollingInterval).ShouldNot(HaveOccurred()) 181 182 pkg.Log(pkg.Info, "Wait for Finalizer to be removed") 183 Eventually(func() bool { 184 return pkg.CheckNamespaceFinalizerRemoved(namespace) 185 }, shortWaitTimeout, shortPollingInterval).Should(BeTrue()) 186 187 pkg.Log(pkg.Info, "Wait for namespace to be removed") 188 Eventually(func() bool { 189 _, err := pkg.GetNamespace(namespace) 190 return err != nil && errors.IsNotFound(err) 191 }, shortWaitTimeout, shortPollingInterval).Should(BeTrue()) 192 193 metrics.Emit(t.Metrics.With("undeployment_elapsed_time", time.Since(start).Milliseconds())) 194 } 195 }) 196 197 var _ = AfterSuite(afterSuite) 198 199 var ( 200 expectedPodsHelidonConfig = []string{"helidon-config-deployment"} 201 waitTimeout = 10 * time.Minute 202 pollingInterval = 30 * time.Second 203 ) 204 205 var _ = t.Describe("Helidon Config OAM App test", Label("f:app-lcm.oam", 206 "f:app-lcm.helidon-workload"), func() { 207 208 var host = "" 209 var err error 210 // Get the host from the Istio gateway resource. 211 // GIVEN the Istio gateway for the helidon-config namespace 212 // WHEN GetHostnameFromGateway is called 213 // THEN return the host name found in the gateway. 214 t.BeforeEach(func() { 215 Eventually(func() (string, error) { 216 host, err = k8sutil.GetHostnameFromGateway(namespace, "") 217 return host, err 218 }, shortWaitTimeout, shortPollingInterval).Should(Not(BeEmpty())) 219 }) 220 221 // Verify Helidon Config app is working 222 // GIVEN OAM helidon-config app is deployed 223 // WHEN the component and appconfig with ingress trait are created 224 // THEN the application endpoint must be accessible 225 t.Describe("Ingress.", Label("f:mesh.ingress"), func() { 226 t.It("Access /config App Url.", func() { 227 url := fmt.Sprintf("https://%s/config", host) 228 kubeconfigPath, err := k8sutil.GetKubeConfigLocation() 229 Expect(err).ShouldNot(HaveOccurred()) 230 Eventually(func() (*pkg.HTTPResponse, error) { 231 return pkg.GetWebPageWithBasicAuth(url, host, "", "", kubeconfigPath) 232 }, longWaitTimeout, longPollingInterval).Should(And(pkg.HasStatus(200), pkg.BodyContains("HelloConfig World"))) 233 }) 234 }) 235 236 // Verify Prometheus scraped targets 237 // GIVEN OAM helidon-config app is deployed 238 // WHEN the component and appconfig without metrics-trait(using default) are created 239 // THEN the application scrape targets must be healthy 240 t.Describe("Metrics.", Label("f:observability.monitoring.prom"), func() { 241 t.It("Verify all scrape targets are healthy for the application", func() { 242 Eventually(func() (bool, error) { 243 var componentNames = []string{"helidon-config-component"} 244 return pkg.ScrapeTargetsHealthy(pkg.GetScrapePools(namespace, "helidon-config-appconf", componentNames, isMinVersion140)) 245 }, shortWaitTimeout, shortPollingInterval).Should(BeTrue()) 246 }) 247 }) 248 249 t.Context("Logging.", Label("f:observability.logging.es"), func() { 250 var indexName string 251 Eventually(func() error { 252 indexName, err = pkg.GetOpenSearchAppIndex(namespace) 253 return err 254 }, shortWaitTimeout, shortPollingInterval).Should(BeNil(), "Expected to get OpenSearch App Index") 255 256 // GIVEN an application with logging enabled 257 // WHEN the Opensearch index is retrieved 258 // THEN verify that it is found 259 t.It("Verify Opensearch index exists", func() { 260 Eventually(func() bool { 261 return pkg.LogIndexFound(indexName) 262 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find log index for helidon config") 263 }) 264 265 // GIVEN an application with logging enabled 266 // WHEN the log records are retrieved from the Opensearch index 267 // THEN verify that at least one recent log record is found 268 t.It("Verify recent Opensearch log record exists", func() { 269 Eventually(func() bool { 270 return pkg.LogRecordFound(indexName, time.Now().Add(-24*time.Hour), map[string]string{ 271 "kubernetes.labels.app_oam_dev\\/component": "helidon-config-component", 272 "kubernetes.labels.app_oam_dev\\/name": "helidon-config-appconf", 273 "kubernetes.container_name": "helidon-config-container", 274 }) 275 }, longWaitTimeout, longPollingInterval).Should(BeTrue(), "Expected to find a recent log record") 276 }) 277 }) 278 }) 279 280 func helidonConfigPodsRunning() bool { 281 result, err := pkg.PodsRunning(namespace, expectedPodsHelidonConfig) 282 if err != nil { 283 AbortSuite(fmt.Sprintf("One or more pods are not running in the namespace: %v, error: %v", namespace, err)) 284 } 285 return result 286 }