Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Smoke tests for listing resources #3690

Merged
merged 3 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,8 @@ bin/yq: bin
bin/setup-envtest: bin
go install sigs.k8s.io/controller-runtime/tools/setup-envtest@latest

clean-bin:
rm -f **/bin/*

vendir-update-dependencies: bin/vendir
vendir sync --chdir tests
3 changes: 1 addition & 2 deletions api/repositories/app_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"github.com/BooleanCat/go-functional/v2/it/itx"
"github.com/google/uuid"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
Expand Down Expand Up @@ -670,7 +669,7 @@ func cfAppToAppRecord(cfApp korifiv1alpha1.CFApp) AppRecord {
CreatedAt: cfApp.CreationTimestamp.Time,
UpdatedAt: getLastUpdatedTime(&cfApp),
DeletedAt: golangTime(cfApp.DeletionTimestamp),
IsStaged: meta.IsStatusConditionTrue(cfApp.Status.Conditions, korifiv1alpha1.StatusConditionReady),
IsStaged: cfApp.Spec.CurrentDropletRef.Name != "",
envSecretName: cfApp.Spec.EnvSecretName,
vcapServiceSecretName: cfApp.Status.VCAPServicesSecretName,
vcapAppSecretName: cfApp.Status.VCAPApplicationSecretName,
Expand Down
43 changes: 5 additions & 38 deletions api/repositories/app_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
. "github.com/onsi/gomega/gstruct"
gomega_types "github.com/onsi/gomega/types"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -109,51 +108,19 @@ var _ = Describe("AppRepository", func() {
Stack: cfApp.Spec.Lifecycle.Data.Stack,
},
}))
Expect(app.IsStaged).To(BeFalse())
Expect(app.IsStaged).To(BeTrue())
Expect(app.DeletedAt).To(BeNil())

Expect(app.Relationships()).To(Equal(map[string]string{
"space": app.SpaceGUID,
}))
})

When("the app has staged condition true", func() {
When("the app has no current droplet set", func() {
BeforeEach(func() {
cfApp.Status.Conditions = []metav1.Condition{{
Type: korifiv1alpha1.StatusConditionReady,
Status: metav1.ConditionTrue,
LastTransitionTime: metav1.Now(),
Reason: "staged",
Message: "staged",
}}
Expect(k8sClient.Status().Update(ctx, cfApp)).To(Succeed())
Eventually(func(g Gomega) {
app := korifiv1alpha1.CFApp{}
g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(cfApp), &app)).To(Succeed())
g.Expect(app.Status.Conditions).NotTo(BeEmpty())
}).Should(Succeed())
})

It("sets IsStaged to true", func() {
Expect(getErr).ToNot(HaveOccurred())
Expect(app.IsStaged).To(BeTrue())
})
})

When("the app has staged condition false", func() {
BeforeEach(func() {
meta.SetStatusCondition(&cfApp.Status.Conditions, metav1.Condition{
Type: korifiv1alpha1.StatusConditionReady,
Status: metav1.ConditionFalse,
Reason: "appStaged",
Message: "",
})
Expect(k8sClient.Status().Update(ctx, cfApp)).To(Succeed())
Eventually(func(g Gomega) {
app := korifiv1alpha1.CFApp{}
g.Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(cfApp), &app)).To(Succeed())
g.Expect(meta.IsStatusConditionFalse(app.Status.Conditions, korifiv1alpha1.StatusConditionReady)).To(BeTrue())
}).Should(Succeed())
Expect(k8s.PatchResource(ctx, k8sClient, cfApp, func() {
cfApp.Spec.CurrentDropletRef.Name = ""
})).To(Succeed())
})

It("sets IsStaged to false", func() {
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ require (
github.com/go-logr/logr v1.4.2
github.com/go-logr/stdr v1.2.2
github.com/go-resty/resty/v2 v2.16.2
github.com/gofrs/flock v0.12.1
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/go-containerregistry v0.20.2
github.com/google/uuid v1.6.0
Expand Down Expand Up @@ -83,6 +84,8 @@ require (
go.opentelemetry.io/otel/trace v1.32.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
golang.org/x/exp v0.0.0-20240823005443-9b4947da3948 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
reconciler.io/runtime v0.20.0 // indirect
Expand Down Expand Up @@ -180,8 +183,6 @@ require (
golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.29.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4=
github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs=
github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E=
github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
Expand Down
33 changes: 33 additions & 0 deletions tests/helpers/flock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package helpers

import (
"github.com/gofrs/flock"
. "github.com/onsi/ginkgo/v2" //lint:ignore ST1001 this is a test file
. "github.com/onsi/gomega" //lint:ignore ST1001 this is a test file
)

type FLock struct {
lock *flock.Flock
}

func NewFlock(lockFilePath string) *FLock {
return &FLock{
lock: flock.New(lockFilePath),
}
}

func (f *FLock) Execute(fn func()) {
GinkgoHelper()

Eventually(func(g Gomega) {
ok, err := f.lock.TryLock()
g.Expect(err).NotTo(HaveOccurred())
g.Expect(ok).To(BeTrue())
}).Should(Succeed())

defer func() {
Expect(f.lock.Unlock()).To(Succeed())
}()

fn()
}
2 changes: 2 additions & 0 deletions tests/helpers/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ func AddUserToKubeConfig(userName, userToken string) {
}

func RemoveUserFromKubeConfig(userName string) {
GinkgoHelper()

configAccess := clientcmd.NewDefaultPathOptions()
config, err := configAccess.GetStartingConfig()
Expect(err).NotTo(HaveOccurred())
Expand Down
69 changes: 69 additions & 0 deletions tests/smoke/list_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package smoke_test

import (
"code.cloudfoundry.org/korifi/tests/helpers"
. "code.cloudfoundry.org/korifi/tests/matchers"
"github.com/google/uuid"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
"github.com/onsi/gomega/types"
)

var _ = Describe("list", func() {
listResources := func(resourceType string, resourcesMatch types.GomegaMatcher) {
cfCurlOutput, err := sessionOutput(helpers.Cf("curl", "/v3/"+resourceType))
Expect(err).NotTo(HaveOccurred())
Expect(cfCurlOutput).To(MatchJSONPath("$.resources", resourcesMatch))
}

BeforeEach(func() {
Expect(helpers.Cf("run-task", sharedData.BuildpackAppName, "-c", "sleep 120")).To(Exit(0))

upsiName := uuid.NewString()
Expect(helpers.Cf("create-user-provided-service", upsiName)).To(Exit(0))
Expect(helpers.Cf("bind-service", sharedData.BuildpackAppName, upsiName)).To(Exit(0))
})

DescribeTable("authorised users get the resources",
listResources,
Entry("apps", "apps", Not(BeEmpty())),
Entry("packages", "packages", Not(BeEmpty())),
Entry("processes", "processes", Not(BeEmpty())),
Entry("routes", "routes", Not(BeEmpty())),
Entry("service_instances", "service_instances", Not(BeEmpty())),
Entry("service_credential_bindings", "service_credential_bindings", Not(BeEmpty())),
Entry("tasks", "tasks", Not(BeEmpty())),
)

When("the user is not allowed to list", func() {
BeforeEach(func() {
serviceAccountFactory := helpers.NewServiceAccountFactory(sharedData.RootNamespace)
userName := uuid.NewString()
userToken := serviceAccountFactory.CreateServiceAccount(userName)
helpers.NewFlock(sharedData.FLockPath).Execute(func() {
helpers.AddUserToKubeConfig(userName, userToken)
})

DeferCleanup(func() {
helpers.NewFlock(sharedData.FLockPath).Execute(func() {
helpers.RemoveUserFromKubeConfig(userName)
})
serviceAccountFactory.DeleteServiceAccount(userName)
})

Expect(helpers.Cf("auth", userName)).To(Exit(0))
})

DescribeTable("unauthorised users get empty resources list",
listResources,
Entry("apps", "apps", BeEmpty()),
Entry("packages", "packages", BeEmpty()),
Entry("processes", "processes", BeEmpty()),
Entry("routes", "routes", BeEmpty()),
Entry("service_instances", "service_instances", BeEmpty()),
Entry("service_credential_bindings", "service_credential_bindings", BeEmpty()),
Entry("tasks", "tasks", BeEmpty()),
)
})
})
2 changes: 1 addition & 1 deletion tests/smoke/run_task_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@ import (

var _ = Describe("cf run-task", func() {
It("succeeds", func() {
Eventually(helpers.Cf("run-task", sharedData.BuildpackAppName, "-c", `echo "Hello from the task"`)).Should(Exit(0))
Expect(helpers.Cf("run-task", sharedData.BuildpackAppName, "-c", `echo "Hello from the task"`)).To(Exit(0))
})
})
33 changes: 33 additions & 0 deletions tests/smoke/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"encoding/json"
"fmt"
"net/http"
"os"
"path/filepath"
"strings"
"testing"

Expand Down Expand Up @@ -38,6 +40,7 @@ type SmokeTestSharedData struct {
BuildpackAppName string `json:"buildpack_app_name"`
DockerAppName string `json:"docker_app_name"`
BrokerURL string `json:"broker_url"`
FLockPath string `json:"f_lock_path"`
}

var sharedData SmokeTestSharedData
Expand All @@ -59,6 +62,11 @@ func TestSmoke(t *testing.T) {
}

var _ = SynchronizedBeforeSuite(func() []byte {
setCFHome(GinkgoParallelProcess())

lockDir, err := os.MkdirTemp("", "")
Expect(err).NotTo(HaveOccurred())

sharedData = SmokeTestSharedData{
CfAdmin: uuid.NewString(),
RootNamespace: helpers.GetDefaultedEnvVar("ROOT_NAMESPACE", "cf"),
Expand All @@ -68,6 +76,7 @@ var _ = SynchronizedBeforeSuite(func() []byte {
AppsDomain: helpers.GetRequiredEnvVar("APP_FQDN"),
BuildpackAppName: uuid.NewString(),
DockerAppName: uuid.NewString(),
FLockPath: filepath.Join(lockDir, "lock"),
}
serviceAccountFactory := helpers.NewServiceAccountFactory(sharedData.RootNamespace)

Expand Down Expand Up @@ -105,14 +114,38 @@ var _ = SynchronizedBeforeSuite(func() []byte {

var _ = SynchronizedAfterSuite(func() {
}, func() {
setCFHome(GinkgoParallelProcess())

Expect(helpers.Cf("api", helpers.GetRequiredEnvVar("API_SERVER_ROOT"), "--skip-ssl-validation")).To(Exit(0))
Expect(helpers.Cf("auth", sharedData.CfAdmin)).To(Exit(0))

Expect(helpers.Cf("delete-org", sharedData.OrgName, "-f").Wait()).To(Exit())
Expect(helpers.Cf("delete-org", sharedData.BrokerOrgName, "-f").Wait()).To(Exit())
serviceAccountFactory := helpers.NewServiceAccountFactory(sharedData.RootNamespace)

serviceAccountFactory.DeleteServiceAccount(sharedData.CfAdmin)
helpers.RemoveUserFromKubeConfig(sharedData.CfAdmin)

Expect(os.RemoveAll(filepath.Dir(sharedData.FLockPath))).To(Succeed())
})

var _ = BeforeEach(func() {
setCFHome(GinkgoParallelProcess())

Expect(helpers.Cf("api", helpers.GetRequiredEnvVar("API_SERVER_ROOT"), "--skip-ssl-validation")).To(Exit(0))
Expect(helpers.Cf("auth", sharedData.CfAdmin)).To(Exit(0))
Expect(helpers.Cf("target", "-o", sharedData.OrgName, "-s", sharedData.SpaceName)).To(Exit(0))
})

func setCFHome(ginkgoNode int) {
cfHomeDir, err := os.MkdirTemp("", fmt.Sprintf("ginkgo-%d", ginkgoNode))
Expect(err).NotTo(HaveOccurred())
DeferCleanup(func() {
Expect(os.RemoveAll(cfHomeDir)).To(Succeed())
})
os.Setenv("CF_HOME", cfHomeDir)
}

func sessionOutput(session *Session) (string, error) {
if session.ExitCode() != 0 {
return "", fmt.Errorf("Session %v exited with exit code %d: %s",
Expand Down
Loading