Skip to content

Commit

Permalink
feat(RELEASE-983): add e2e tests for push-binaries-to-dev-portal
Browse files Browse the repository at this point in the history
Signed-off-by: Jing Qi <[email protected]>
  • Loading branch information
jinqi7 committed Jul 15, 2024
1 parent 3fdbf3e commit 5841896
Show file tree
Hide file tree
Showing 3 changed files with 329 additions and 0 deletions.
7 changes: 7 additions & 0 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,13 @@ const (
// Cert auth for accessing Pyxis stage external registry
PYXIS_STAGE_CERT_ENV string = "PYXIS_STAGE_CERT"


// Key auth for accessing exodus non_prod
EXODUS_NON_PROD_KEY_ENV string = "EXODUS_NON_PROD_KEY"

// Cert auth for accessing exodus non_prod
EXODUS_NON_PROD_CERT_ENV string = "EXODUS_NON_PROD_CERT"

// Offline/refresh token used for getting Keycloak token in order to authenticate against stage/prod cluster
// More details: https://access.redhat.com/articles/3626371
OFFLINE_TOKEN_ENV = "OFFLINE_TOKEN"
Expand Down
1 change: 1 addition & 0 deletions tests/release/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const (
HacbsReleaseTestsTokenSecret string = "redhat-appstudio-registry-pull-secret"
PublicSecretNameAuth string = "cosign-public-key"
ReleasePipelineServiceAccountDefault string = "release-service-account"
CgwSecret string = "publish-to-cgw-secret"

Check failure

Code scanning / gosec

Potential hardcoded credentials Error test

Potential hardcoded credentials

SourceReleasePlanName string = "source-releaseplan"
SecondReleasePlanName string = "the-second-releaseplan"
Expand Down
321 changes: 321 additions & 0 deletions tests/release/pipelines/push_binaries_to_dev_portal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,321 @@
package pipelines

import (
"encoding/base64"
"encoding/json"
"fmt"
"os"
"strings"
"time"

"github.com/devfile/library/v2/pkg/util"
ecp "github.com/enterprise-contract/enterprise-contract-controller/api/v1alpha1"
appservice "github.com/konflux-ci/application-api/api/v1alpha1"
"github.com/konflux-ci/e2e-tests/pkg/clients/github"
"github.com/konflux-ci/e2e-tests/pkg/constants"
"github.com/konflux-ci/e2e-tests/pkg/framework"
"github.com/konflux-ci/e2e-tests/pkg/utils"
"github.com/konflux-ci/e2e-tests/pkg/utils/tekton"
releasecommon "github.com/konflux-ci/e2e-tests/tests/release"
releaseapi "github.com/konflux-ci/release-service/api/v1alpha1"
tektonutils "github.com/konflux-ci/release-service/tekton/utils"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"knative.dev/pkg/apis"
)

const (
devportalServiceAccountName = "release-service-account"
devportalSourceGitURL = "https://github.com/redhat-appstudio-qe/devfile-sample-go-basic"
devportalRepoOwner = "redhat-appstudio-qe"
devportalRepo = "devfile-sample-go-basic"
devportalCatalogPathInRepo = "pipelines/push-binaries-to-dev-portal/push-binaries-to-dev-portal.yaml"
)

var devportalComponent *appservice.Component
var _ = framework.ReleasePipelinesSuiteDescribe("e2e tests for push-binaries-to-dev-portal pipeline", Label("release-pipelines", "push-binaries-to-dev-portal"), func() {
defer GinkgoRecover()

var devWorkspace = utils.GetEnv(constants.RELEASE_DEV_WORKSPACE_ENV, constants.DevReleaseTeam)
var managedWorkspace = utils.GetEnv(constants.RELEASE_MANAGED_WORKSPACE_ENV, constants.ManagedReleaseTeam)

var devNamespace = devWorkspace + "-tenant"
var managedNamespace = managedWorkspace + "-tenant"

var err error
var devFw *framework.Framework
var managedFw *framework.Framework
var devportalApplicationName = "devportal-app-" + util.GenerateRandomString(4)
var devportalComponentName = "devportal-comp-" + util.GenerateRandomString(4)
var devportalReleasePlanName = "devportal-rp-" + util.GenerateRandomString(4)
var devportalReleasePlanAdmissionName = "devportal-rpa-" + util.GenerateRandomString(4)
var devportalEnterpriseContractPolicyName = "devportal-policy-" + util.GenerateRandomString(4)

var snapshot *appservice.Snapshot
var releaseCR *releaseapi.Release
var releasePR, buildPR *tektonv1.PipelineRun
var gh *github.Github
var devportalReleaseURL string

AfterEach(framework.ReportFailure(&devFw))

Describe("Push-to-dev-portal happy path", Label("pushToDevPortal"), func() {
BeforeAll(func() {
devFw = releasecommon.NewFramework(devWorkspace)
managedFw = releasecommon.NewFramework(managedWorkspace)

managedNamespace = managedFw.UserNamespace

// Linking the build secret to the pipeline service account in dev namespace.
err = devFw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(devNamespace, releasecommon.HacbsReleaseTestsTokenSecret, constants.DefaultPipelineServiceAccount, true)
Expect(err).ToNot(HaveOccurred())

keyExodusNonProd := os.Getenv(constants.EXODUS_NON_PROD_KEY_ENV)
Expect(keyExodusNonProd).ToNot(BeEmpty())

certExodusNonProd := os.Getenv(constants.EXODUS_NON_PROD_CERT_ENV)
Expect(certExodusNonProd).ToNot(BeEmpty())

// Creating k8s secret to access Exodus Non product based on base64 decoded of key and cert
exodusKeyDecoded, err := base64.StdEncoding.DecodeString(string(keyExodusNonProd))
Expect(err).ToNot(HaveOccurred())

exodusCertDecoded, err := base64.StdEncoding.DecodeString(string(certExodusNonProd))
Expect(err).ToNot(HaveOccurred())

_, err = managedFw.AsKubeAdmin.CommonController.GetSecret(managedNamespace, releasecommon.RedhatAppstudioQESecret)
if errors.IsNotFound(err) {
secret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: "exodus-stage-secret",
Namespace: managedNamespace,
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"cert": exodusCertDecoded,
"key": exodusKeyDecoded,
},
}

_, err = managedFw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, secret)
Expect(err).ToNot(HaveOccurred())
}

//err = managedFw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(managedNamespace, releasecommon.RedhatAppstudioUserSecret, constants.DefaultPipelineServiceAccount, true)
githubUser := utils.GetEnv("GITHUB_USER", "redhat-appstudio-qe-bot")
githubToken := utils.GetEnv(constants.GITHUB_TOKEN_ENV, "")
gh, err = github.NewGithubClient(githubToken, githubUser)
Expect(githubToken).ToNot(BeEmpty())
Expect(err).ToNot(HaveOccurred())

_, err = managedFw.AsKubeAdmin.CommonController.GetSecret(managedNamespace, releasecommon.RedhatAppstudioQESecret)
if errors.IsNotFound(err) {
githubSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: releasecommon.RedhatAppstudioQESecret,
Namespace: managedNamespace,
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"token": []byte(githubToken),
},
}
_, err = managedFw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, githubSecret)
Expect(err).ToNot(HaveOccurred())
}
Expect(err).ToNot(HaveOccurred())

cgwUser := utils.GetEnv("CGW_USERNAME", "")
cgwToken := utils.GetEnv(constants.GITHUB_TOKEN_ENV, "")
_, err = managedFw.AsKubeAdmin.CommonController.GetSecret(managedNamespace, releasecommon.CgwSecret)
if errors.IsNotFound(err) {
githubSecret := &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: releasecommon.CgwSecret,
Namespace: managedNamespace,
},
Type: corev1.SecretTypeOpaque,
Data: map[string][]byte{
"username": []byte(cgwUser),
"user-token": []byte(cgwToken),
},
}
_, err = managedFw.AsKubeAdmin.CommonController.CreateSecret(managedNamespace, githubSecret)
Expect(err).ToNot(HaveOccurred())
}
Expect(err).ToNot(HaveOccurred())

err = managedFw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(managedNamespace, releasecommon.RedhatAppstudioQESecret, constants.DefaultPipelineServiceAccount, true)
Expect(err).ToNot(HaveOccurred())

err = managedFw.AsKubeAdmin.CommonController.LinkSecretToServiceAccount(managedNamespace, releasecommon.CgwSecret, constants.DefaultPipelineServiceAccount, true)
Expect(err).ToNot(HaveOccurred())

_, err = devFw.AsKubeDeveloper.HasController.CreateApplication(devportalApplicationName, devNamespace)
Expect(err).NotTo(HaveOccurred())

_, err = devFw.AsKubeDeveloper.ReleaseController.CreateReleasePlan(devportalReleasePlanName, devNamespace, devportalApplicationName, managedNamespace, "true", nil, nil)
Expect(err).NotTo(HaveOccurred())

devportalComponent = releasecommon.CreateComponent(*devFw, devNamespace, devportalApplicationName, devportalComponentName, devportalSourceGitURL, "", ".", "Dockerfile", constants.DefaultDockerBuildPipelineBundle)

createDevPortalReleasePlanAdmission(devportalReleasePlanAdmissionName, *managedFw, devNamespace, managedNamespace, devportalApplicationName, devportalEnterpriseContractPolicyName, devportalCatalogPathInRepo, "false", "", "", "", "")
Expect(err).NotTo(HaveOccurred())

createDevPortalEnterpriseContractPolicy(devportalEnterpriseContractPolicyName, *managedFw, devNamespace, managedNamespace)
})

AfterAll(func() {
devFw = releasecommon.NewFramework(devWorkspace)
managedFw = releasecommon.NewFramework(managedWorkspace)
Expect(devFw.AsKubeDeveloper.HasController.DeleteApplication(devportalApplicationName, devNamespace, false)).NotTo(HaveOccurred())
Expect(managedFw.AsKubeDeveloper.TektonController.DeleteEnterpriseContractPolicy(devportalEnterpriseContractPolicyName, managedNamespace, false)).NotTo(HaveOccurred())
Expect(managedFw.AsKubeDeveloper.ReleaseController.DeleteReleasePlanAdmission(devportalReleasePlanAdmissionName, managedNamespace, false)).NotTo(HaveOccurred())

if gh.CheckIfReleaseExist(devportalRepoOwner, devportalRepo, devportalReleaseURL) {
gh.DeleteRelease(devportalRepoOwner, devportalRepo, devportalReleaseURL)
}
})

var _ = Describe("Post-release verification", func() {
It("verifies that a build PipelineRun is created in dev namespace and succeeds", func() {
devFw = releasecommon.NewFramework(devWorkspace)
managedFw = releasecommon.NewFramework(managedWorkspace)
// Create a ticker that ticks every 3 minutes
ticker := time.NewTicker(3 * time.Minute)
// Schedule the stop of the ticker after 15 minutes
time.AfterFunc(15*time.Minute, func() {
ticker.Stop()
fmt.Println("Stopped executing every 3 minutes.")
})
// Run a goroutine to handle the ticker ticks
go func() {
for range ticker.C {
devFw = releasecommon.NewFramework(devWorkspace)
managedFw = releasecommon.NewFramework(managedWorkspace)
}
}()
Eventually(func() error {
buildPR, err = devFw.AsKubeDeveloper.HasController.GetComponentPipelineRun(devportalComponent.Name, devportalApplicationName, devNamespace, "")
if err != nil {
GinkgoWriter.Printf("Build PipelineRun has not been created yet for the component %s/%s\n", devNamespace, devportalComponent.Name)
return err
}
GinkgoWriter.Printf("PipelineRun %s reason: %s\n", buildPR.Name, buildPR.GetStatusCondition().GetCondition(apis.ConditionSucceeded).GetReason())
if !buildPR.IsDone() {
return fmt.Errorf("build pipelinerun %s in namespace %s did not finish yet", buildPR.Name, buildPR.Namespace)
}
if buildPR.GetStatusCondition().GetCondition(apis.ConditionSucceeded).IsTrue() {
snapshot, err = devFw.AsKubeDeveloper.IntegrationController.GetSnapshot("", buildPR.Name, "", devNamespace)
if err != nil {
return err
}
return nil
} else {
return fmt.Errorf(tekton.GetFailedPipelineRunLogs(devFw.AsKubeDeveloper.HasController.KubeRest(), devFw.AsKubeDeveloper.HasController.KubeInterface(), buildPR))
}
}, releasecommon.BuildPipelineRunCompletionTimeout, releasecommon.DefaultInterval).Should(Succeed(), fmt.Sprintf("timed out when waiting for the build PipelineRun to be finished for the component %s/%s", devNamespace, devportalComponent.Name))
})
It("verifies release pipelinerun is running and succeeds", func() {
devFw = releasecommon.NewFramework(devWorkspace)
managedFw = releasecommon.NewFramework(managedWorkspace)
releaseCR, err = devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace)
Expect(err).ShouldNot(HaveOccurred())

Expect(managedFw.AsKubeAdmin.ReleaseController.WaitForReleasePipelineToBeFinished(releaseCR, managedNamespace)).To(Succeed(), fmt.Sprintf("Error when waiting for a release pipelinerun for release %s/%s to finish", releaseCR.GetNamespace(), releaseCR.GetName()))

releasePR, err = managedFw.AsKubeAdmin.ReleaseController.GetPipelineRunInNamespace(managedFw.UserNamespace, releaseCR.GetName(), releaseCR.GetNamespace())
Expect(err).NotTo(HaveOccurred())
})

It("verifies release CR completed and set succeeded.", func() {
devFw = releasecommon.NewFramework(devWorkspace)
Eventually(func() error {
releaseCR, err := devFw.AsKubeDeveloper.ReleaseController.GetRelease("", snapshot.Name, devNamespace)
if err != nil {
return err
}
GinkgoWriter.Println("Release CR: ", releaseCR.Name)
if !releaseCR.IsReleased() {
return fmt.Errorf("release %s/%s is not marked as finished yet", releaseCR.GetNamespace(), releaseCR.GetName())
}
return nil
}, 10*time.Minute, releasecommon.DefaultInterval).Should(Succeed())
})

It("verifies if the Release exists in github repo", func() {
managedFw = releasecommon.NewFramework(managedWorkspace)
trReleasePr, err := managedFw.AsKubeAdmin.TektonController.GetTaskRunStatus(managedFw.AsKubeAdmin.CommonController.KubeRest(), releasePR, "create-github-release")
Expect(err).NotTo(HaveOccurred())
trReleaseURL := trReleasePr.Status.TaskRunStatusFields.Results[0].Value.StringVal
releaseURL := strings.Replace(trReleaseURL, "\n", "", -1)
Expect(gh.CheckIfReleaseExist(devportalRepoOwner, devportalRepo, releaseURL)).To(BeTrue(), fmt.Sprintf("release %s doesn't exist", releaseURL))
devportalReleaseURL = releaseURL
})
})
})
})

func createDevPortalEnterpriseContractPolicy(devportalECPName string, managedFw framework.Framework, devNamespace, managedNamespace string) {
defaultEcPolicySpec := ecp.EnterpriseContractPolicySpec{
Description: "Red Hat's enterprise requirements",
PublicKey: "k8s://openshift-pipelines/public-key",
Sources: []ecp.Source{{
Name: "Default",
Policy: []string{releasecommon.EcPolicyLibPath, releasecommon.EcPolicyReleasePath},
Data: []string{releasecommon.EcPolicyDataBundle, releasecommon.EcPolicyDataPath},
}},
Configuration: &ecp.EnterpriseContractPolicyConfiguration{
Exclude: []string{"step_image_registries", "tasks.required_tasks_found:prefetch-dependencies"},
Include: []string{"@slsa3"},
},
}

_, err := managedFw.AsKubeDeveloper.TektonController.CreateEnterpriseContractPolicy(devportalECPName, managedNamespace, defaultEcPolicySpec)
Expect(err).NotTo(HaveOccurred())

}

func createDevPortalReleasePlanAdmission(devportalRPAName string, managedFw framework.Framework, devNamespace, managedNamespace, devportalAppName, devportalECPName, pathInRepoValue, hotfix, issueId, preGA, productName, productVersion string) {
var err error

data, err := json.Marshal(map[string]interface{}{
"github": map[string]interface{}{
"githubSecret": releasecommon.RedhatAppstudioQESecret,
},
"exodus": map[string]interface{}{
"env": "cdn-qa",
},
"contentGateway": map[string]interface{}{
"productName": "Konflux test product",
"productCode": "KTestProduct",
"productVersionName": "KTestProduct 1",
"components":[]map[string]interface{}{{
"name": devportalComponent.GetName(),
"description": "Red Hat OpenShift Local Sandbox Test",
"label": "Checksum File Sandbox Test",
}},
},
"sign": map[string]interface{}{
"configMapName": "hacbs-signing-pipeline-config-redhatbeta2",
},
})
Expect(err).NotTo(HaveOccurred())

_, err = managedFw.AsKubeAdmin.ReleaseController.CreateReleasePlanAdmission(devportalRPAName, managedNamespace, "", devNamespace, devportalECPName, devportalServiceAccountName, []string{devportalAppName}, true, &tektonutils.PipelineRef{
Resolver: "git",
Params: []tektonutils.Param{
{Name: "url", Value: releasecommon.RelSvcCatalogURL},
{Name: "revision", Value: releasecommon.RelSvcCatalogRevision},
{Name: "pathInRepo", Value: pathInRepoValue},
},
}, &runtime.RawExtension{
Raw: data,
})
Expect(err).NotTo(HaveOccurred())
}

0 comments on commit 5841896

Please sign in to comment.