github.com/redhat-appstudio/e2e-tests@v0.0.0-20230619105049-9a422b2094d7/tests/e2e-demos/e2e-demo.go (about)

     1  package e2e
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	. "github.com/onsi/ginkgo/v2"
     8  	. "github.com/onsi/gomega"
     9  	appservice "github.com/redhat-appstudio/application-api/api/v1alpha1"
    10  	"github.com/redhat-appstudio/e2e-tests/pkg/constants"
    11  	"github.com/redhat-appstudio/e2e-tests/pkg/framework"
    12  	"github.com/redhat-appstudio/e2e-tests/pkg/utils"
    13  	e2eConfig "github.com/redhat-appstudio/e2e-tests/tests/e2e-demos/config"
    14  	"github.com/spf13/viper"
    15  	appsv1 "k8s.io/api/apps/v1"
    16  	v1 "k8s.io/api/core/v1"
    17  	"k8s.io/apimachinery/pkg/api/errors"
    18  	"k8s.io/utils/pointer"
    19  )
    20  
    21  const (
    22  	// Environment name used for e2e-tests demos
    23  	EnvironmentName string = "development"
    24  
    25  	// Secret Name created by spi to interact with github
    26  	SPIGithubSecretName string = "e2e-github-secret"
    27  
    28  	// Environment name used for e2e-tests demos
    29  	SPIQuaySecretName string = "e2e-quay-secret"
    30  )
    31  
    32  var _ = framework.E2ESuiteDescribe(Label("e2e-demo"), func() {
    33  	defer GinkgoRecover()
    34  	var outputContainerImage = ""
    35  	var timeout, interval time.Duration
    36  	var namespace string
    37  
    38  	// Initialize the application struct
    39  	application := &appservice.Application{}
    40  	component := &appservice.Component{}
    41  	snapshot := &appservice.Snapshot{}
    42  	env := &appservice.Environment{}
    43  	fw := &framework.Framework{}
    44  
    45  	// Initialize the e2e demo configuration
    46  	configTestFile := viper.GetString("config-suites")
    47  	GinkgoWriter.Printf("Starting e2e-demo test suites from config: %s\n", configTestFile)
    48  
    49  	configTest, err := e2eConfig.LoadTestGeneratorConfig(configTestFile)
    50  	Expect(err).NotTo(HaveOccurred())
    51  
    52  	for _, appTest := range configTest.Tests {
    53  		appTest := appTest
    54  
    55  		Describe(appTest.Name, Ordered, func() {
    56  			BeforeAll(func() {
    57  				if appTest.Skip {
    58  					Skip(fmt.Sprintf("test skipped %s", appTest.Name))
    59  				}
    60  
    61  				// Initialize the tests controllers
    62  				fw, err = framework.NewFramework(utils.GetGeneratedNamespace("e2e-demos"))
    63  				Expect(err).NotTo(HaveOccurred())
    64  				namespace = fw.UserNamespace
    65  				Expect(namespace).NotTo(BeEmpty())
    66  
    67  				// collect SPI ResourceQuota metrics (temporary)
    68  				err := fw.AsKubeAdmin.CommonController.GetResourceQuotaInfo("e2e-demo", namespace, "appstudio-crds-spi")
    69  				Expect(err).NotTo(HaveOccurred())
    70  
    71  				suiteConfig, _ := GinkgoConfiguration()
    72  				GinkgoWriter.Printf("Parallel processes: %d\n", suiteConfig.ParallelTotal)
    73  				GinkgoWriter.Printf("Running on namespace: %s\n", namespace)
    74  				GinkgoWriter.Printf("User: %s\n", fw.UserName)
    75  
    76  				githubCredentials := `{"access_token":"` + utils.GetEnv(constants.GITHUB_TOKEN_ENV, "") + `"}`
    77  
    78  				_ = fw.AsKubeDeveloper.SPIController.InjectManualSPIToken(namespace, fmt.Sprintf("https://github.com/%s", utils.GetEnv(constants.GITHUB_E2E_ORGANIZATION_ENV, "redhat-appstudio-qe")), githubCredentials, v1.SecretTypeBasicAuth, SPIGithubSecretName)
    79  			})
    80  
    81  			// Remove all resources created by the tests
    82  			AfterAll(func() {
    83  				// collect SPI ResourceQuota metrics (temporary)
    84  				err := fw.AsKubeAdmin.CommonController.GetResourceQuotaInfo("e2e-demo", namespace, "appstudio-crds-spi")
    85  				Expect(err).NotTo(HaveOccurred())
    86  
    87  				if !CurrentSpecReport().Failed() {
    88  					Expect(fw.AsKubeDeveloper.HasController.DeleteAllComponentsInASpecificNamespace(namespace, 30*time.Second)).To(Succeed())
    89  					Expect(fw.AsKubeAdmin.HasController.DeleteAllApplicationsInASpecificNamespace(namespace, 30*time.Second)).To(Succeed())
    90  					Expect(fw.AsKubeAdmin.HasController.DeleteAllSnapshotEnvBindingsInASpecificNamespace(namespace, 30*time.Second)).To(Succeed())
    91  					Expect(fw.AsKubeAdmin.ReleaseController.DeleteAllSnapshotsInASpecificNamespace(namespace, 30*time.Second)).To(Succeed())
    92  					Expect(fw.AsKubeAdmin.GitOpsController.DeleteAllEnvironmentsInASpecificNamespace(namespace, 30*time.Second)).To(Succeed())
    93  					Expect(fw.AsKubeAdmin.TektonController.DeleteAllPipelineRunsInASpecificNamespace(namespace)).To(Succeed())
    94  					Expect(fw.AsKubeAdmin.GitOpsController.DeleteAllGitOpsDeploymentInASpecificNamespace(namespace, 30*time.Second)).To(Succeed())
    95  					Expect(fw.SandboxController.DeleteUserSignup(fw.UserName)).NotTo(BeFalse())
    96  				}
    97  			})
    98  
    99  			// Create an application in a specific namespace
   100  			It("creates an application", func() {
   101  				GinkgoWriter.Printf("Parallel process %d\n", GinkgoParallelProcess())
   102  				createdApplication, err := fw.AsKubeDeveloper.HasController.CreateHasApplication(appTest.ApplicationName, namespace)
   103  				Expect(err).NotTo(HaveOccurred())
   104  				Expect(createdApplication.Spec.DisplayName).To(Equal(appTest.ApplicationName))
   105  				Expect(createdApplication.Namespace).To(Equal(namespace))
   106  			})
   107  
   108  			// Check the application health and check if a devfile was generated in the status
   109  			It("checks if application is healthy", func() {
   110  				Eventually(func() string {
   111  					appstudioApp, err := fw.AsKubeDeveloper.HasController.GetHasApplication(appTest.ApplicationName, namespace)
   112  					Expect(err).NotTo(HaveOccurred())
   113  					application = appstudioApp
   114  
   115  					return application.Status.Devfile
   116  				}, 3*time.Minute, 100*time.Millisecond).Should(Not(BeEmpty()), "Error creating gitOps repository")
   117  
   118  				Eventually(func() bool {
   119  					gitOpsRepository := utils.ObtainGitOpsRepositoryName(application.Status.Devfile)
   120  
   121  					return fw.AsKubeDeveloper.CommonController.Github.CheckIfRepositoryExist(gitOpsRepository)
   122  				}, 5*time.Minute, 1*time.Second).Should(BeTrue(), "Has controller didn't create gitops repository")
   123  			})
   124  
   125  			// Create an environment in a specific namespace
   126  			It("creates an environment", func() {
   127  				env, err = fw.AsKubeDeveloper.IntegrationController.CreateEnvironment(namespace, EnvironmentName)
   128  				Expect(err).NotTo(HaveOccurred())
   129  			})
   130  
   131  			for _, componentTest := range appTest.Components {
   132  				componentTest := componentTest
   133  				cdq := &appservice.ComponentDetectionQuery{}
   134  				if componentTest.Type == "private" {
   135  					It("injects manually SPI token", func() {
   136  						// Inject spi tokens to work with private components
   137  						if componentTest.ContainerSource != "" {
   138  							// More info about manual token upload for quay.io here: https://github.com/redhat-appstudio/service-provider-integration-operator/pull/115
   139  							oauthCredentials := `{"access_token":"` + utils.GetEnv(constants.QUAY_OAUTH_TOKEN_ENV, "") + `", "username":"` + utils.GetEnv(constants.QUAY_OAUTH_USER_ENV, "") + `"}`
   140  
   141  							_ = fw.AsKubeAdmin.SPIController.InjectManualSPIToken(namespace, componentTest.ContainerSource, oauthCredentials, v1.SecretTypeDockerConfigJson, SPIQuaySecretName)
   142  						}
   143  					})
   144  				}
   145  
   146  				It("creates componentdetectionquery", func() {
   147  					if componentTest.Type == "private" {
   148  						cdq, err = fw.AsKubeDeveloper.HasController.CreateComponentDetectionQuery(componentTest.Name, namespace, componentTest.GitSourceUrl, componentTest.GitSourceRevision, componentTest.GitSourceContext, SPIGithubSecretName, false)
   149  						Expect(err).NotTo(HaveOccurred())
   150  						Expect(len(cdq.Status.ComponentDetected)).To(Equal(1), "Expected length of the detected Components was not 1")
   151  
   152  					} else {
   153  						cdq, err = fw.AsKubeDeveloper.HasController.CreateComponentDetectionQuery(componentTest.Name, namespace, componentTest.GitSourceUrl, componentTest.GitSourceRevision, componentTest.GitSourceContext, "", false)
   154  						Expect(err).NotTo(HaveOccurred())
   155  						Expect(len(cdq.Status.ComponentDetected)).To(Equal(1), "Expected length of the detected Components was not 1")
   156  					}
   157  				})
   158  
   159  				// Components for now can be imported from gitUrl, container image or a devfile
   160  				if componentTest.ContainerSource != "" {
   161  					It(fmt.Sprintf("creates component %s from %s container source", componentTest.Name, componentTest.Type), func() {
   162  						component, err = fw.AsKubeDeveloper.HasController.CreateComponent(application.Name, componentTest.Name, namespace, "", "", componentTest.ContainerSource, outputContainerImage, SPIQuaySecretName, true)
   163  						Expect(err).NotTo(HaveOccurred())
   164  					})
   165  				} else if componentTest.GitSourceUrl != "" {
   166  					It(fmt.Sprintf("creates component %s from %s git source %s", componentTest.Name, componentTest.Type, componentTest.GitSourceUrl), func() {
   167  						for _, compDetected := range cdq.Status.ComponentDetected {
   168  							if componentTest.Type == "private" {
   169  								component, err = fw.AsKubeDeveloper.HasController.CreateComponentFromStub(compDetected, namespace, "", SPIGithubSecretName, appTest.ApplicationName)
   170  								Expect(err).NotTo(HaveOccurred())
   171  							} else if componentTest.Type == "public" {
   172  								component, err = fw.AsKubeDeveloper.HasController.CreateComponentFromStub(compDetected, namespace, "", "", appTest.ApplicationName)
   173  								Expect(err).NotTo(HaveOccurred())
   174  							}
   175  						}
   176  					})
   177  
   178  				} else {
   179  					defer GinkgoRecover()
   180  					Fail("Please Provide a valid test sample")
   181  				}
   182  
   183  				// Start to watch the pipeline until is finished
   184  				It(fmt.Sprintf("waits %s component %s pipeline to be finished", componentTest.Type, componentTest.Name), func() {
   185  					if componentTest.ContainerSource != "" {
   186  						Skip(fmt.Sprintf("component %s was imported from quay.io/docker.io source. Skipping pipelinerun check.", componentTest.Name))
   187  					}
   188  					component, err = fw.AsKubeAdmin.HasController.GetHasComponent(component.Name, namespace)
   189  					Expect(err).ShouldNot(HaveOccurred(), "failed to get component: %v", err)
   190  
   191  					Expect(fw.AsKubeAdmin.HasController.WaitForComponentPipelineToBeFinished(component, "", 2)).To(Succeed())
   192  				})
   193  
   194  				It("finds the snapshot and checks if it is marked as successful", func() {
   195  					timeout = time.Second * 600
   196  					interval = time.Second * 10
   197  
   198  					Eventually(func() bool {
   199  						snapshot, err = fw.AsKubeAdmin.IntegrationController.GetSnapshot("", "", component.Name, namespace)
   200  						if err != nil {
   201  							GinkgoWriter.Println("snapshot has not been found yet")
   202  							return false
   203  						}
   204  						return fw.AsKubeAdmin.IntegrationController.HaveTestsSucceeded(snapshot)
   205  
   206  					}, timeout, interval).Should(BeTrue(), fmt.Sprintf("time out when trying to check if the snapshot %s is marked as successful", snapshot.Name))
   207  				})
   208  
   209  				It("checks if a snapshot environment binding is created successfully", func() {
   210  					Eventually(func() bool {
   211  						if fw.AsKubeAdmin.IntegrationController.HaveTestsSucceeded(snapshot) {
   212  							envbinding, err := fw.AsKubeAdmin.IntegrationController.GetSnapshotEnvironmentBinding(application.Name, namespace, env)
   213  							if err != nil {
   214  								GinkgoWriter.Println("SnapshotEnvironmentBinding has not been found yet")
   215  								return false
   216  							}
   217  							GinkgoWriter.Printf("The SnapshotEnvironmentBinding %s is created\n", envbinding.Name)
   218  							return true
   219  						}
   220  						return false
   221  					}, timeout, interval).Should(BeTrue(), fmt.Sprintf("time out when trying to check if SnapshotEnvironmentBinding is created (snapshot: %s, env: %s)", snapshot.Name, env.Name))
   222  				})
   223  
   224  				// Deploy the component using gitops
   225  				It(fmt.Sprintf("deploys component %s using gitops", component.Name), func() {
   226  					if componentTest.SkipDeploymentCheck {
   227  						Skip("component deployment skipped.")
   228  					}
   229  					var deployment *appsv1.Deployment
   230  					Eventually(func() bool {
   231  						deployment, err = fw.AsKubeDeveloper.CommonController.GetDeployment(component.Name, namespace)
   232  						return err == nil
   233  					}, 25*time.Minute, 10*time.Second).Should(BeTrue(), fmt.Sprintf("Component deployment did not exist: %+v", deployment))
   234  					Expect(err).NotTo(HaveOccurred())
   235  				})
   236  
   237  				// Check for the health of the deployed component
   238  				It(fmt.Sprintf("deployed component %s becomes ready", component.Name), func() {
   239  					if componentTest.SkipDeploymentCheck {
   240  						Skip("component deployment skipped.")
   241  					}
   242  					var deployment *appsv1.Deployment
   243  					Eventually(func() bool {
   244  						deployment, err = fw.AsKubeDeveloper.CommonController.GetDeployment(component.Name, namespace)
   245  						if err != nil && !errors.IsNotFound(err) {
   246  							return false
   247  						}
   248  						if deployment.Status.AvailableReplicas == 1 {
   249  							GinkgoWriter.Printf("Deployment %s is ready\n", deployment.Name)
   250  							return true
   251  						}
   252  
   253  						return false
   254  					}, 25*time.Minute, 10*time.Second).Should(BeTrue(), fmt.Sprintf("Component deployment didn't become ready: %+v", deployment))
   255  					Expect(err).NotTo(HaveOccurred())
   256  				})
   257  
   258  				It(fmt.Sprintf("checks if component %s health", component.Name), func() {
   259  					if componentTest.SkipDeploymentCheck {
   260  						Skip("component deployment skipped.")
   261  					}
   262  					Eventually(func() bool {
   263  						gitOpsRoute, err := fw.AsKubeDeveloper.CommonController.GetOpenshiftRouteByComponentName(component.Name, namespace)
   264  						Expect(err).NotTo(HaveOccurred())
   265  						err = fw.AsKubeDeveloper.GitOpsController.CheckGitOpsEndpoint(gitOpsRoute, componentTest.HealthEndpoint)
   266  						if err != nil {
   267  							GinkgoWriter.Printf("Failed to request component endpoint: %+v\n retrying...\n", err)
   268  						}
   269  						return true
   270  					}, 5*time.Minute, 10*time.Second).Should(BeTrue())
   271  				})
   272  
   273  				if componentTest.K8sSpec != (e2eConfig.K8sSpec{}) && componentTest.K8sSpec.Replicas > 1 {
   274  					It(fmt.Sprintf("scales component %s replicas", component.Name), Pending, func() {
   275  						component, err := fw.AsKubeDeveloper.HasController.GetHasComponent(component.Name, namespace)
   276  						Expect(err).NotTo(HaveOccurred())
   277  						_, err = fw.AsKubeDeveloper.HasController.ScaleComponentReplicas(component, pointer.Int(componentTest.K8sSpec.Replicas))
   278  						Expect(err).NotTo(HaveOccurred())
   279  
   280  						Eventually(func() bool {
   281  							deployment, _ := fw.AsKubeDeveloper.CommonController.GetDeployment(component.Name, namespace)
   282  							if err != nil && !errors.IsNotFound(err) {
   283  								return false
   284  							}
   285  							if int(deployment.Status.AvailableReplicas) == componentTest.K8sSpec.Replicas {
   286  								GinkgoWriter.Printf("Replicas scaled to %s\n", componentTest.K8sSpec.Replicas)
   287  								return true
   288  							}
   289  
   290  							return false
   291  						}, 5*time.Minute, 10*time.Second).Should(BeTrue(), "Component deployment didn't get scaled to desired replicas")
   292  						Expect(err).NotTo(HaveOccurred())
   293  					})
   294  				}
   295  			}
   296  		})
   297  	}
   298  })