github.com/redhat-appstudio/e2e-tests@v0.0.0-20240520140907-9709f6f59323/pkg/clients/integration/snapshots.go (about) 1 package integration 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "github.com/devfile/library/v2/pkg/util" 9 . "github.com/onsi/ginkgo/v2" 10 appstudioApi "github.com/redhat-appstudio/application-api/api/v1alpha1" 11 "github.com/redhat-appstudio/e2e-tests/pkg/constants" 12 "github.com/redhat-appstudio/e2e-tests/pkg/logs" 13 "github.com/redhat-appstudio/e2e-tests/pkg/utils" 14 intgteststat "github.com/konflux-ci/integration-service/pkg/integrationteststatus" 15 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 16 "k8s.io/apimachinery/pkg/types" 17 "k8s.io/apimachinery/pkg/util/wait" 18 "sigs.k8s.io/controller-runtime/pkg/client" 19 ) 20 21 // SnapshotTestsStatusAnnotation is annotation in snapshot where integration test results are stored 22 const SnapshotTestsStatusAnnotation = "test.appstudio.openshift.io/status" 23 24 // CreateSnapshotWithComponents creates a Snapshot using the given parameters. 25 func (i *IntegrationController) CreateSnapshotWithComponents(snapshotName, componentName, applicationName, namespace string, snapshotComponents []appstudioApi.SnapshotComponent) (*appstudioApi.Snapshot, error) { 26 snapshot := &appstudioApi.Snapshot{ 27 ObjectMeta: metav1.ObjectMeta{ 28 Name: snapshotName, 29 Namespace: namespace, 30 Labels: map[string]string{ 31 "test.appstudio.openshift.io/type": "component", 32 "appstudio.openshift.io/component": componentName, 33 "pac.test.appstudio.openshift.io/event-type": "push", 34 }, 35 }, 36 Spec: appstudioApi.SnapshotSpec{ 37 Application: applicationName, 38 Components: snapshotComponents, 39 }, 40 } 41 return snapshot, i.KubeRest().Create(context.Background(), snapshot) 42 } 43 44 // CreateSnapshotWithImage creates a snapshot using an image. 45 func (i *IntegrationController) CreateSnapshotWithImage(componentName, applicationName, namespace, containerImage string) (*appstudioApi.Snapshot, error) { 46 snapshotComponents := []appstudioApi.SnapshotComponent{ 47 { 48 Name: componentName, 49 ContainerImage: containerImage, 50 }, 51 } 52 53 snapshotName := "snapshot-sample-" + util.GenerateRandomString(4) 54 55 return i.CreateSnapshotWithComponents(snapshotName, componentName, applicationName, namespace, snapshotComponents) 56 } 57 58 // GetSnapshotByComponent returns the first snapshot in namespace if exist, else will return nil 59 func (i *IntegrationController) GetSnapshotByComponent(namespace string) (*appstudioApi.Snapshot, error) { 60 snapshot := &appstudioApi.SnapshotList{} 61 opts := []client.ListOption{ 62 client.MatchingLabels{ 63 "test.appstudio.openshift.io/type": "component", 64 }, 65 client.InNamespace(namespace), 66 } 67 err := i.KubeRest().List(context.Background(), snapshot, opts...) 68 69 if err == nil && len(snapshot.Items) > 0 { 70 return &snapshot.Items[0], nil 71 } 72 return nil, err 73 } 74 75 // GetSnapshot returns the Snapshot in the namespace and nil if it's not found 76 // It will search for the Snapshot based on the Snapshot name, associated PipelineRun name or Component name 77 // In the case the List operation fails, an error will be returned. 78 func (i *IntegrationController) GetSnapshot(snapshotName, pipelineRunName, componentName, namespace string) (*appstudioApi.Snapshot, error) { 79 ctx := context.Background() 80 // If Snapshot name is provided, try to get the resource directly 81 if len(snapshotName) > 0 { 82 snapshot := &appstudioApi.Snapshot{} 83 if err := i.KubeRest().Get(ctx, types.NamespacedName{Name: snapshotName, Namespace: namespace}, snapshot); err != nil { 84 return nil, fmt.Errorf("couldn't find Snapshot with name '%s' in '%s' namespace", snapshotName, namespace) 85 } 86 return snapshot, nil 87 } 88 // Search for the Snapshot in the namespace based on the associated Component or PipelineRun 89 snapshots := &appstudioApi.SnapshotList{} 90 opts := []client.ListOption{ 91 client.InNamespace(namespace), 92 } 93 err := i.KubeRest().List(ctx, snapshots, opts...) 94 if err != nil { 95 return nil, fmt.Errorf("error when listing Snapshots in '%s' namespace", namespace) 96 } 97 for _, snapshot := range snapshots.Items { 98 if snapshot.Name == snapshotName { 99 return &snapshot, nil 100 } 101 // find snapshot by pipelinerun name 102 if len(pipelineRunName) > 0 && snapshot.Labels["appstudio.openshift.io/build-pipelinerun"] == pipelineRunName { 103 return &snapshot, nil 104 105 } 106 // find snapshot by component name 107 if len(componentName) > 0 && snapshot.Labels["appstudio.openshift.io/component"] == componentName { 108 return &snapshot, nil 109 110 } 111 } 112 return nil, fmt.Errorf("no snapshot found for component '%s', pipelineRun '%s' in '%s' namespace", componentName, pipelineRunName, namespace) 113 } 114 115 // DeleteSnapshot removes given snapshot from specified namespace. 116 func (i *IntegrationController) DeleteSnapshot(hasSnapshot *appstudioApi.Snapshot, namespace string) error { 117 err := i.KubeRest().Delete(context.Background(), hasSnapshot) 118 return err 119 } 120 121 // PatchSnapshot patches the given snapshot with the provided patch. 122 func (i *IntegrationController) PatchSnapshot(oldSnapshot *appstudioApi.Snapshot, newSnapshot *appstudioApi.Snapshot) error { 123 patch := client.MergeFrom(oldSnapshot) 124 err := i.KubeRest().Patch(context.Background(), newSnapshot, patch) 125 return err 126 } 127 128 // DeleteAllSnapshotsInASpecificNamespace removes all snapshots from a specific namespace. Useful when creating a lot of resources and want to remove all of them 129 func (i *IntegrationController) DeleteAllSnapshotsInASpecificNamespace(namespace string, timeout time.Duration) error { 130 if err := i.KubeRest().DeleteAllOf(context.Background(), &appstudioApi.Snapshot{}, client.InNamespace(namespace)); err != nil { 131 return fmt.Errorf("error deleting snapshots from the namespace %s: %+v", namespace, err) 132 } 133 134 return utils.WaitUntil(func() (done bool, err error) { 135 snapshotList, err := i.ListAllSnapshots(namespace) 136 if err != nil { 137 return false, nil 138 } 139 return len(snapshotList.Items) == 0, nil 140 }, timeout) 141 } 142 143 // WaitForSnapshotToGetCreated wait for the Snapshot to get created successfully. 144 func (i *IntegrationController) WaitForSnapshotToGetCreated(snapshotName, pipelinerunName, componentName, testNamespace string) (*appstudioApi.Snapshot, error) { 145 var snapshot *appstudioApi.Snapshot 146 147 err := wait.PollUntilContextTimeout(context.Background(), constants.PipelineRunPollingInterval, 10*time.Minute, true, func(ctx context.Context) (done bool, err error) { 148 snapshot, err = i.GetSnapshot(snapshotName, pipelinerunName, componentName, testNamespace) 149 if err != nil { 150 GinkgoWriter.Printf("unable to get the Snapshot within the namespace %s. Error: %v", testNamespace, err) 151 return false, nil 152 } 153 154 return true, nil 155 }) 156 157 return snapshot, err 158 } 159 160 // ListAllSnapshots returns a list of all Snapshots in a given namespace. 161 func (i *IntegrationController) ListAllSnapshots(namespace string) (*appstudioApi.SnapshotList, error) { 162 snapshotList := &appstudioApi.SnapshotList{} 163 err := i.KubeRest().List(context.Background(), snapshotList, &client.ListOptions{Namespace: namespace}) 164 165 return snapshotList, err 166 } 167 168 // StoreSnapshot stores a given Snapshot as an artifact. 169 func (i *IntegrationController) StoreSnapshot(snapshot *appstudioApi.Snapshot) error { 170 return logs.StoreResourceYaml(snapshot, "snapshot-"+snapshot.Name) 171 } 172 173 // StoreAllSnapshots stores all Snapshots in a given namespace. 174 func (i *IntegrationController) StoreAllSnapshots(namespace string) error { 175 snapshotList, err := i.ListAllSnapshots(namespace) 176 if err != nil { 177 return err 178 } 179 180 for _, snapshot := range snapshotList.Items { 181 if err := i.StoreSnapshot(&snapshot); err != nil { 182 return err 183 } 184 } 185 return nil 186 } 187 188 // GetIntegrationTestStatusDetailFromSnapshot parses snapshot annotation and returns integration test status detail 189 func (i *IntegrationController) GetIntegrationTestStatusDetailFromSnapshot(snapshot *appstudioApi.Snapshot, scenarioName string) (*intgteststat.IntegrationTestStatusDetail, error) { 190 var ( 191 resultsJson string 192 ok bool 193 ) 194 annotations := snapshot.GetAnnotations() 195 resultsJson, ok = annotations[SnapshotTestsStatusAnnotation] 196 if !ok { 197 resultsJson = "" 198 } 199 statuses, err := intgteststat.NewSnapshotIntegrationTestStatuses(resultsJson) 200 if err != nil { 201 return nil, fmt.Errorf("failed to create new SnapshotIntegrationTestStatuses object: %w", err) 202 } 203 statusDetail, ok := statuses.GetScenarioStatus(scenarioName) 204 if !ok { 205 return nil, fmt.Errorf("status detail for scenario %s not found", scenarioName) 206 } 207 return statusDetail, nil 208 }