Skip to content

Commit

Permalink
Refactoring Pact tests and adding parametrized states (#391)
Browse files Browse the repository at this point in the history
* Move Pact contract tests related files to a separate package

* Remove sleeps
  • Loading branch information
Katka92 authored Sep 25, 2023
1 parent dc3a43b commit c2f7c29
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package controllers
package contracts

import (
"context"
Expand All @@ -29,6 +29,7 @@ import (
models "github.com/pact-foundation/pact-go/v2/models"
provider "github.com/pact-foundation/pact-go/v2/provider"
appstudiov1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1"
"github.com/redhat-appstudio/application-service/controllers"
"sigs.k8s.io/controller-runtime/pkg/client"
)

Expand Down Expand Up @@ -84,7 +85,7 @@ func TestContracts(t *testing.T) {

// Register fail handler and setup test environment (same as during unit tests)
RegisterFailHandler(Fail)
setupTestEnv()
k8sClient, testEnv, ctx, cancel = controllers.SetupTestEnv()

verifyRequest.ProviderBaseURL = testEnv.Config.Host

Expand All @@ -105,7 +106,10 @@ func TestContracts(t *testing.T) {
// setup state handlers
verifyRequest.StateHandlers = models.StateHandlers{
"No app with the name app-to-create in the default namespace exists.": func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) { return nil, nil },
"App myapp exists and has component gh-component and quay-component": createAppAndComponents(HASAppNamespace),
// deprecated
"App myapp exists and has component gh-component and quay-component": createAppAndComponents(HASAppNamespace),
"Application exists": createApp(),
"Application has components": createComponents(),
}
verifyRequest.AfterEach = func() error {
// Remove all applications and components after each tests
Expand Down
191 changes: 191 additions & 0 deletions contracts/application_pact_test_state_handlers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
//
// Copyright 2023 Red Hat, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package contracts

import (
"context"
"strings"
"time"

gomega "github.com/onsi/gomega"
models "github.com/pact-foundation/pact-go/v2/models"
appstudiov1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1"

"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
)

var (
k8sClient client.Client
testEnv *envtest.Environment
ctx context.Context
cancel context.CancelFunc
)

type Comp struct {
app AppParams
repo string
name string
}

type CompParams struct {
components []Comp
}

type AppParams struct {
appName string
namespace string
}

const timeout = 10 * time.Second
const interval = 250 * time.Millisecond

// Deprecated
func createAppAndComponents(HASAppNamespace string) models.StateHandler {
var stateHandler = func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) {
if !setup {
println("skipping state handler")
return nil, nil
}

appName := "myapp"
ghCompName := "gh-component"
quayCompName := "quay-component"
ghCompRepoLink := "https://github.com/devfile-samples/devfile-sample-java-springboot-basic"
quayRepoLink := "quay.io/test/test-image:latest"

hasApp := getApplicationSpec(appName, HASAppNamespace)
ghComp := getGhComponentSpec(ghCompName, HASAppNamespace, appName, ghCompRepoLink)
quayComp := getQuayComponentSpec(quayCompName, HASAppNamespace, appName, quayRepoLink)

//create app
gomega.Expect(k8sClient.Create(ctx, hasApp)).Should(gomega.Succeed())
hasAppLookupKey := types.NamespacedName{Name: appName, Namespace: HASAppNamespace}
createdHasApp := &appstudiov1alpha1.Application{}
gomega.Eventually(func() bool {
k8sClient.Get(context.Background(), hasAppLookupKey, createdHasApp)
if len(createdHasApp.Status.Conditions) > 0 {
return createdHasApp.Status.Conditions[0].Type == "Created"
}
return false
}, timeout, interval).Should(gomega.BeTrue())

//create gh component
gomega.Expect(k8sClient.Create(ctx, ghComp)).Should(gomega.Succeed())
hasCompLookupKey := types.NamespacedName{Name: ghCompName, Namespace: HASAppNamespace}
createdHasComp := &appstudiov1alpha1.Component{}
gomega.Eventually(func() bool {
gomega.Expect(k8sClient.Get(context.Background(), hasCompLookupKey, createdHasComp)).Should(gomega.Succeed())
return len(createdHasComp.Status.Conditions) > 1
}, timeout, interval).Should(gomega.BeTrue())

//create quay component
gomega.Expect(k8sClient.Create(ctx, quayComp)).Should(gomega.Succeed())
hasCompLookupKey2 := types.NamespacedName{Name: quayCompName, Namespace: HASAppNamespace}
createdHasComp2 := &appstudiov1alpha1.Component{}
gomega.Eventually(func() bool {
gomega.Expect(k8sClient.Get(context.Background(), hasCompLookupKey2, createdHasComp2)).Should(gomega.Succeed())
return len(createdHasComp2.Status.Conditions) > 1
}, timeout, interval).Should(gomega.BeTrue())

gomega.Eventually(func() bool {
gomega.Expect(k8sClient.Get(context.Background(), hasAppLookupKey, createdHasApp)).Should(gomega.Succeed())
return len(createdHasApp.Status.Conditions) > 0 && strings.Contains(createdHasApp.Status.Devfile, ghCompName)
}, timeout, interval).Should(gomega.BeTrue())
return nil, nil
}
return stateHandler
}

func createApp() models.StateHandler {
var stateHandler = func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) {
if !setup {
println("skipping state handler during turndownn phase")
return nil, nil
}

app := parseApp(s.Parameters)
hasApp := getApplicationSpec(app.appName, app.namespace)

//create app
gomega.Expect(k8sClient.Create(ctx, hasApp)).Should(gomega.Succeed())
hasAppLookupKey := types.NamespacedName{Name: app.appName, Namespace: app.namespace}
createdHasApp := &appstudiov1alpha1.Application{}

gomega.Eventually(func() bool {
k8sClient.Get(context.Background(), hasAppLookupKey, createdHasApp)
return len(createdHasApp.Status.Conditions) > 0
}, timeout, interval).Should(gomega.BeTrue())

return nil, nil
}
return stateHandler
}

func createComponents() models.StateHandler {
var stateHandler = func(setup bool, s models.ProviderState) (models.ProviderStateResponse, error) {
if !setup {
println("skipping state handler")
return nil, nil
}

components := parseComp(s.Parameters)

for _, comp := range components.components {
ghComp := getGhComponentSpec(comp.name, comp.app.namespace, comp.app.appName, comp.repo)

hasAppLookupKey := types.NamespacedName{Name: comp.app.appName, Namespace: comp.app.namespace}
createdHasApp := &appstudiov1alpha1.Application{}

//create gh component
gomega.Expect(k8sClient.Create(ctx, ghComp)).Should(gomega.Succeed())
hasCompLookupKey := types.NamespacedName{Name: comp.name, Namespace: comp.app.namespace}
createdHasComp := &appstudiov1alpha1.Component{}
gomega.Eventually(func() bool {
k8sClient.Get(context.Background(), hasCompLookupKey, createdHasComp)
return len(createdHasComp.Status.Conditions) > 1
}, timeout, interval).Should(gomega.BeTrue())

gomega.Eventually(func() bool {
k8sClient.Get(context.Background(), hasAppLookupKey, createdHasApp)
return len(createdHasApp.Status.Conditions) > 0 && strings.Contains(createdHasApp.Status.Devfile, comp.name)
}, timeout, interval).Should(gomega.BeTrue())
}
return nil, nil
}
return stateHandler
}

func parseApp(params map[string]interface{}) AppParams {
return AppParams{
params["params"].(map[string]interface{})["appName"].(string),
params["params"].(map[string]interface{})["namespace"].(string),
}
}

func parseComp(params map[string]interface{}) CompParams {
tmp := params["params"].(map[string]interface{})["components"].([]interface{})
var components CompParams
for _, compToParse := range tmp {
component := compToParse.(map[string]interface{})
appParsed := AppParams{component["app"].(map[string]interface{})["appName"].(string),
component["app"].(map[string]interface{})["namespace"].(string)}
compParsed := Comp{appParsed, component["repo"].(string), component["compName"].(string)}
components.components = append(components.components, compParsed)
}
return components
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package controllers
package contracts

import (
appstudiov1alpha1 "github.com/redhat-appstudio/application-api/api/v1alpha1"
Expand Down
93 changes: 0 additions & 93 deletions controllers/application_pact_test_state_handlers.go

This file was deleted.

3 changes: 2 additions & 1 deletion controllers/start_test_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ var (
cancel context.CancelFunc
)

func setupTestEnv() {
func SetupTestEnv() (client.Client, *envtest.Environment, context.Context, context.CancelFunc) {
logf.SetLogger(zap.New(zap.WriteTo(ginkgo.GinkgoWriter), zap.UseDevMode(true)))

ctx, cancel = context.WithCancel(context.TODO())
Expand Down Expand Up @@ -140,4 +140,5 @@ func setupTestEnv() {
err = k8sManager.Start(ctx)
gomega.Expect(err).ToNot(gomega.HaveOccurred(), "failed to run manager")
}()
return k8sClient, testEnv, ctx, cancel
}
4 changes: 3 additions & 1 deletion controllers/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ func TestAPIs(t *testing.T) {
"Controller Suite")
}

var _ = BeforeSuite(setupTestEnv, 60)
var _ = BeforeSuite(func() {
SetupTestEnv()
}, 60)

var _ = AfterSuite(func() {
cancel()
Expand Down

0 comments on commit c2f7c29

Please sign in to comment.