Skip to content

Commit

Permalink
Smoke tests for listing resources
Browse files Browse the repository at this point in the history
The tests verify that
* Authorised users can list resources
* Unauthorised users get empty resources list but no error

issue #3636

Co-authored-by: Georgi Sabev <georgethebeatle@gmail.com>
  • Loading branch information
danail-branekov and georgethebeatle committed Jan 7, 2025
1 parent ebf3242 commit 60aaefd
Show file tree
Hide file tree
Showing 7 changed files with 143 additions and 3 deletions.
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

0 comments on commit 60aaefd

Please sign in to comment.