Skip to content

Commit

Permalink
feat: Implement SpaceBindingRequest controller main logic (#779)
Browse files Browse the repository at this point in the history
* add e2e tests for spacebindingrequests
---------

Co-authored-by: Matous Jobanek <[email protected]>
  • Loading branch information
mfrancisc and MatousJobanek authored Aug 23, 2023
1 parent 82d14a8 commit 56cc5bc
Show file tree
Hide file tree
Showing 6 changed files with 505 additions and 6 deletions.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
module github.com/codeready-toolchain/toolchain-e2e

require (
github.com/codeready-toolchain/api v0.0.0-20230711103642-544bb7e0cf9e
github.com/codeready-toolchain/toolchain-common v0.0.0-20230710095440-719b09376de3
github.com/codeready-toolchain/api v0.0.0-20230823083409-fe9ca973d9a9
github.com/codeready-toolchain/toolchain-common v0.0.0-20230823084119-693476668406
github.com/davecgh/go-spew v1.1.1
github.com/fatih/color v1.12.0
github.com/ghodss/yaml v1.0.0
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,10 @@ github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:z
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
github.com/codeready-toolchain/api v0.0.0-20230711103642-544bb7e0cf9e h1:T6Ay8YwCGPXCufh1toy7QdCwqPJc5SIA0kkOh/be9ZE=
github.com/codeready-toolchain/api v0.0.0-20230711103642-544bb7e0cf9e/go.mod h1:nn3W6eKb9PFIVwSwZW7wDeLACMBOwAV+4kddGuN+ARM=
github.com/codeready-toolchain/toolchain-common v0.0.0-20230710095440-719b09376de3 h1:zPxv/JJRZsXS+OVgsrF1egFlTi45DXJ8MTPi50meujI=
github.com/codeready-toolchain/toolchain-common v0.0.0-20230710095440-719b09376de3/go.mod h1:vtUfWOJBDxQP1DtcIoxfjI5heBGcT8D+C8ux+PLouyg=
github.com/codeready-toolchain/api v0.0.0-20230823083409-fe9ca973d9a9 h1:ytFqNSSEvgevqvwMilmmqlrrDH1O/qUwzg8bO3CxCiY=
github.com/codeready-toolchain/api v0.0.0-20230823083409-fe9ca973d9a9/go.mod h1:nn3W6eKb9PFIVwSwZW7wDeLACMBOwAV+4kddGuN+ARM=
github.com/codeready-toolchain/toolchain-common v0.0.0-20230823084119-693476668406 h1:AkBhFV2tJhQaejTjntIhFC7r1FeLlQEiAL2gcn5/oW0=
github.com/codeready-toolchain/toolchain-common v0.0.0-20230823084119-693476668406/go.mod h1:wvbndymhFMqyc8syiaanid91GsywkDfuVyiTjdyiqNM=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
Expand Down
288 changes: 288 additions & 0 deletions test/e2e/parallel/spacebindingrequest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
package parallel

import (
"context"
"fmt"
"sort"
"testing"

toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
"github.com/gofrs/uuid"
"github.com/stretchr/testify/assert"

spacebindingrequesttestcommon "github.com/codeready-toolchain/toolchain-common/pkg/test/spacebindingrequest"

testspace "github.com/codeready-toolchain/toolchain-common/pkg/test/space"
. "github.com/codeready-toolchain/toolchain-e2e/testsupport"
. "github.com/codeready-toolchain/toolchain-e2e/testsupport/wait"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/types"
)

func TestCreateSpaceBindingRequest(t *testing.T) {
// given
t.Parallel()
// make sure everything is ready before running the actual tests
awaitilities := WaitForDeployments(t)
hostAwait := awaitilities.Host()
memberAwait := awaitilities.Member1()

t.Run("success", func(t *testing.T) {
t.Run("create space binding request", func(t *testing.T) {
// when
// we create a space to share , a new MUR and a SpaceBindingRequest
space, spaceBindingRequest, spaceBinding := NewSpaceBindingRequest(t, awaitilities, memberAwait, hostAwait, "admin")

t.Run("spaceBinding is recreated if deleted ", func(t *testing.T) {
// now, delete the SpaceBinding,
// a new SpaceBinding will be provisioned by the SpaceBindingRequest.
//
// save the old UID that will be used to ensure that a new SpaceBinding was created with the same name but new UID
oldUID := spaceBinding.UID

// when
err := hostAwait.Client.Delete(context.TODO(), spaceBinding)

// then
// a new SpaceBinding is created
// with the same name but different UID.
require.NoError(t, err)
spaceBinding, err = hostAwait.WaitForSpaceBinding(t, spaceBindingRequest.Spec.MasterUserRecord, space.Name,
UntilSpaceBindingHasMurName(spaceBindingRequest.Spec.MasterUserRecord),
UntilSpaceBindingHasSpaceName(space.Name),
UntilSpaceBindingHasSpaceRole(spaceBindingRequest.Spec.SpaceRole),
UntilSpaceBindingHasDifferentUID(oldUID),
UntilSpaceBindingHasLabel(toolchainv1alpha1.SpaceBindingRequestLabelKey, spaceBindingRequest.GetName()),
UntilSpaceBindingHasLabel(toolchainv1alpha1.SpaceBindingRequestNamespaceLabelKey, spaceBindingRequest.GetNamespace()),
)
require.NoError(t, err)

t.Run("SpaceBinding always reflects values from spaceBindingRequest ", func(t *testing.T) {
// given
// something/someone updates the SpaceRole directly on the SpaceBinding object

// when
spaceBinding, err = hostAwait.UpdateSpaceBinding(t, spaceBinding.Name, func(s *toolchainv1alpha1.SpaceBinding) {
s.Spec.SpaceRole = "invalidRole" // let's change the role
})
require.NoError(t, err)

// then
// spaceBindingRequest should reset back the SpaceRole
spaceBinding, err = hostAwait.WaitForSpaceBinding(t, spaceBindingRequest.Spec.MasterUserRecord, space.Name,
UntilSpaceBindingHasMurName(spaceBindingRequest.Spec.MasterUserRecord),
UntilSpaceBindingHasSpaceName(space.Name),
UntilSpaceBindingHasSpaceRole(spaceBindingRequest.Spec.SpaceRole), // should have back the role from the SBR
UntilSpaceBindingHasLabel(toolchainv1alpha1.SpaceBindingRequestLabelKey, spaceBindingRequest.GetName()),
UntilSpaceBindingHasLabel(toolchainv1alpha1.SpaceBindingRequestNamespaceLabelKey, spaceBindingRequest.GetNamespace()),
)
require.NoError(t, err)

t.Run("delete space binding request", func(t *testing.T) {
// now, delete the SpaceBindingRequest and expect that the SpaceBinding will be deleted as well,

// when
err := memberAwait.Client.Delete(context.TODO(), spaceBindingRequest)

// then
// spaceBinding should be deleted as well
require.NoError(t, err)
err = hostAwait.WaitUntilSpaceBindingDeleted(spaceBinding.Name)
require.NoError(t, err)
})
})
})
})
})

t.Run("error", func(t *testing.T) {
t.Run("unable create space binding request with invalid SpaceRole", func(t *testing.T) {
space, _, _ := CreateSpace(t, awaitilities, testspace.WithTierName("appstudio"), testspace.WithSpecTargetCluster(memberAwait.ClusterName))
// wait for the namespace to be provisioned since we will be creating the SpaceBindingRequest into it.
space, err := hostAwait.WaitForSpace(t, space.Name, UntilSpaceHasAnyProvisionedNamespaces())
require.NoError(t, err)
// let's create a new MUR that will have access to the space
username := uuid.Must(uuid.NewV4()).String()
_, mur := NewSignupRequest(awaitilities).
Username(username).
Email(username + "@acme.com").
ManuallyApprove().
TargetCluster(memberAwait).
RequireConditions(ConditionSet(Default(), ApprovedByAdmin())...).
NoSpace().
WaitForMUR().Execute(t).Resources()
// create the spacebinding request
spaceBindingRequest := CreateSpaceBindingRequest(t, awaitilities, memberAwait.ClusterName,
WithSpecSpaceRole("invalid"), // set invalid spacerole
WithSpecMasterUserRecord(mur.GetName()),
WithNamespace(GetDefaultNamespace(space.Status.ProvisionedNamespaces)),
)

// then
require.NoError(t, err)
// wait for spacebinding request status to be set
_, err = memberAwait.WaitForSpaceBindingRequest(t, types.NamespacedName{Namespace: spaceBindingRequest.GetNamespace(), Name: spaceBindingRequest.GetName()},
UntilSpaceBindingRequestHasConditions(spacebindingrequesttestcommon.UnableToCreateSpaceBinding(fmt.Sprintf("invalid role 'invalid' for space '%s'", space.Name))),
)
require.NoError(t, err)
bindings, err := hostAwait.ListSpaceBindings(space.Name)
require.NoError(t, err)
assert.Len(t, bindings, 1)
})

t.Run("unable create space binding request with invalid MasterUserRecord", func(t *testing.T) {
space, _, _ := CreateSpace(t, awaitilities, testspace.WithTierName("appstudio"), testspace.WithSpecTargetCluster(memberAwait.ClusterName))
// wait for the namespace to be provisioned since we will be creating the SpaceBindingRequest into it.
space, err := hostAwait.WaitForSpace(t, space.Name, UntilSpaceHasAnyProvisionedNamespaces())
require.NoError(t, err)
// create the spacebinding request
spaceBindingRequest := CreateSpaceBindingRequest(t, awaitilities, memberAwait.ClusterName,
WithSpecSpaceRole("admin"),
WithSpecMasterUserRecord("invalidMUR"), // we set an invalid MUR
WithNamespace(GetDefaultNamespace(space.Status.ProvisionedNamespaces)),
)

// then
require.NoError(t, err)
// wait for spacebinding request status to be set
_, err = memberAwait.WaitForSpaceBindingRequest(t, types.NamespacedName{Namespace: spaceBindingRequest.GetNamespace(), Name: spaceBindingRequest.GetName()},
UntilSpaceBindingRequestHasConditions(spacebindingrequesttestcommon.UnableToCreateSpaceBinding("unable to get MUR: MasterUserRecord.toolchain.dev.openshift.com \"invalidMUR\" not found")),
)
require.NoError(t, err)
bindings, err := hostAwait.ListSpaceBindings(space.Name)
require.NoError(t, err)
assert.Len(t, bindings, 1)
})
})
}

func TestUpdateSpaceBindingRequest(t *testing.T) {
// given
t.Parallel()
// make sure everything is ready before running the actual tests
awaitilities := WaitForDeployments(t)
hostAwait := awaitilities.Host()
memberAwait := awaitilities.Member1()

t.Run("update space binding request SpaceRole", func(t *testing.T) {
// when
space, spaceBindingRequest, _ := NewSpaceBindingRequest(t, awaitilities, memberAwait, hostAwait, "contributor")
_, err := memberAwait.UpdateSpaceBindingRequest(t, types.NamespacedName{Namespace: spaceBindingRequest.Namespace, Name: spaceBindingRequest.Name},
func(s *toolchainv1alpha1.SpaceBindingRequest) {
s.Spec.SpaceRole = "admin" // set to admin from contributor
},
)
require.NoError(t, err)

//then
// wait for both SpaceBindingRequest and SpaceBinding to have same SpaceRole
spaceBindingRequest, err = memberAwait.WaitForSpaceBindingRequest(t, types.NamespacedName{Namespace: spaceBindingRequest.GetNamespace(), Name: spaceBindingRequest.GetName()},
UntilSpaceBindingRequestHasConditions(spacebindingrequesttestcommon.Ready()),
UntilSpaceBindingRequestHasSpecSpaceRole("admin"), // has admin role
UntilSpaceBindingRequestHasSpecMUR(spaceBindingRequest.Spec.MasterUserRecord),
)
require.NoError(t, err)
_, err = hostAwait.WaitForSpaceBinding(t, spaceBindingRequest.Spec.MasterUserRecord, space.Name,
UntilSpaceBindingHasMurName(spaceBindingRequest.Spec.MasterUserRecord),
UntilSpaceBindingHasSpaceName(space.Name),
UntilSpaceBindingHasSpaceRole("admin"), // has admin role
UntilSpaceBindingHasLabel(toolchainv1alpha1.SpaceBindingRequestLabelKey, spaceBindingRequest.GetName()),
UntilSpaceBindingHasLabel(toolchainv1alpha1.SpaceBindingRequestNamespaceLabelKey, spaceBindingRequest.GetNamespace()),
)
require.NoError(t, err)
})

t.Run("update space binding request MasterUserRecord", func(t *testing.T) {
// when
space, spaceBindingRequest, _ := NewSpaceBindingRequest(t, awaitilities, memberAwait, hostAwait, "admin")
// let's create another MUR that will have access to the space
username := uuid.Must(uuid.NewV4()).String()
_, newmur := NewSignupRequest(awaitilities).
Username(username).
Email(username + "@acme.com").
ManuallyApprove().
TargetCluster(memberAwait).
RequireConditions(ConditionSet(Default(), ApprovedByAdmin())...).
NoSpace().
WaitForMUR().Execute(t).Resources()
// and we update the MUR in the SBR
_, err := memberAwait.UpdateSpaceBindingRequest(t, types.NamespacedName{Namespace: spaceBindingRequest.Namespace, Name: spaceBindingRequest.Name},
func(s *toolchainv1alpha1.SpaceBindingRequest) {
s.Spec.MasterUserRecord = newmur.GetName() // set to the new MUR
},
)
require.NoError(t, err)

//then
// wait for both SpaceBindingRequest and SpaceBinding to have same MUR
spaceBindingRequest, err = memberAwait.WaitForSpaceBindingRequest(t, types.NamespacedName{Namespace: spaceBindingRequest.GetNamespace(), Name: spaceBindingRequest.GetName()},
UntilSpaceBindingRequestHasConditions(spacebindingrequesttestcommon.Ready()),
UntilSpaceBindingRequestHasSpecSpaceRole(spaceBindingRequest.Spec.SpaceRole),
UntilSpaceBindingRequestHasSpecMUR(newmur.GetName()), // new MUR
)
require.NoError(t, err)
_, err = hostAwait.WaitForSpaceBinding(t, spaceBindingRequest.Spec.MasterUserRecord, space.Name,
UntilSpaceBindingHasMurName(newmur.GetName()), // has new MUR
UntilSpaceBindingHasSpaceName(space.Name),
UntilSpaceBindingHasSpaceRole(spaceBindingRequest.Spec.SpaceRole),
)
require.NoError(t, err)
})
}

func NewSpaceBindingRequest(t *testing.T, awaitilities Awaitilities, memberAwait *MemberAwaitility, hostAwait *HostAwaitility, spaceRole string) (*toolchainv1alpha1.Space, *toolchainv1alpha1.SpaceBindingRequest, *toolchainv1alpha1.SpaceBinding) {
space, firstUserSignup, _ := CreateSpace(t, awaitilities, testspace.WithTierName("appstudio"), testspace.WithSpecTargetCluster(memberAwait.ClusterName))
// wait for the namespace to be provisioned since we will be creating the SpaceBindingRequest into it.
space, err := hostAwait.WaitForSpace(t, space.Name, UntilSpaceHasAnyProvisionedNamespaces())
require.NoError(t, err)
// let's create a new MUR that will have access to the space
username := uuid.Must(uuid.NewV4()).String()
_, secondUserMUR := NewSignupRequest(awaitilities).
Username(username).
Email(username + "@acme.com").
ManuallyApprove().
TargetCluster(memberAwait).
RequireConditions(ConditionSet(Default(), ApprovedByAdmin())...).
NoSpace().
WaitForMUR().Execute(t).Resources()
// create the spacebinding request
spaceBindingRequest := CreateSpaceBindingRequest(t, awaitilities, memberAwait.ClusterName,
WithSpecSpaceRole(spaceRole),
WithSpecMasterUserRecord(secondUserMUR.GetName()),
WithNamespace(GetDefaultNamespace(space.Status.ProvisionedNamespaces)),
)

// then
// check for the spaceBinding creation
spaceBinding, err := hostAwait.WaitForSpaceBinding(t, spaceBindingRequest.Spec.MasterUserRecord, space.Name,
UntilSpaceBindingHasMurName(spaceBindingRequest.Spec.MasterUserRecord),
UntilSpaceBindingHasSpaceName(space.Name),
UntilSpaceBindingHasSpaceRole(spaceBindingRequest.Spec.SpaceRole),
UntilSpaceBindingHasLabel(toolchainv1alpha1.SpaceBindingRequestLabelKey, spaceBindingRequest.GetName()),
UntilSpaceBindingHasLabel(toolchainv1alpha1.SpaceBindingRequestNamespaceLabelKey, spaceBindingRequest.GetNamespace()),
)
require.NoError(t, err)
// wait for spacebinding request status
spaceBindingRequest, err = memberAwait.WaitForSpaceBindingRequest(t, types.NamespacedName{Namespace: spaceBindingRequest.GetNamespace(), Name: spaceBindingRequest.GetName()},
UntilSpaceBindingRequestHasConditions(spacebindingrequesttestcommon.Ready()),
)
require.NoError(t, err)
tier, err := awaitilities.Host().WaitForNSTemplateTier(t, space.Spec.TierName)
require.NoError(t, err)
if spaceRole == "admin" {
usernamesSorted := []string{firstUserSignup.Status.CompliantUsername, secondUserMUR.Name}
sort.Strings(usernamesSorted)
_, err = memberAwait.WaitForNSTmplSet(t, space.Name,
UntilNSTemplateSetHasSpaceRoles(
SpaceRole(tier.Spec.SpaceRoles[spaceRole].TemplateRef, usernamesSorted[0], usernamesSorted[1])))
require.NoError(t, err)
} else {
_, err = memberAwait.WaitForNSTmplSet(t, space.Name,
UntilNSTemplateSetHasSpaceRoles(
SpaceRole(tier.Spec.SpaceRoles["admin"].TemplateRef, firstUserSignup.Status.CompliantUsername),
SpaceRole(tier.Spec.SpaceRoles[spaceRole].TemplateRef, secondUserMUR.Name)))
require.NoError(t, err)
}
VerifyResourcesProvisionedForSpace(t, awaitilities, space.Name)
return space, spaceBindingRequest, spaceBinding
}
50 changes: 50 additions & 0 deletions testsupport/spacebindingrequest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package testsupport

import (
"testing"

toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
"github.com/codeready-toolchain/toolchain-e2e/testsupport/wait"

"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

type SpaceBindingRequestOption func(request *toolchainv1alpha1.SpaceBindingRequest)

func WithSpecSpaceRole(spaceRole string) SpaceBindingRequestOption {
return func(s *toolchainv1alpha1.SpaceBindingRequest) {
s.Spec.SpaceRole = spaceRole
}
}

func WithSpecMasterUserRecord(mur string) SpaceBindingRequestOption {
return func(s *toolchainv1alpha1.SpaceBindingRequest) {
s.Spec.MasterUserRecord = mur
}
}

func WithNamespace(ns string) SpaceBindingRequestOption {
return func(s *toolchainv1alpha1.SpaceBindingRequest) {
s.ObjectMeta.Namespace = ns
}
}

func CreateSpaceBindingRequest(t *testing.T, awaitilities wait.Awaitilities, memberName string, opts ...SpaceBindingRequestOption) *toolchainv1alpha1.SpaceBindingRequest {
memberAwait, err := awaitilities.Member(memberName)
require.NoError(t, err)
namePrefix := NewObjectNamePrefix(t)

spaceBindingRequest := &toolchainv1alpha1.SpaceBindingRequest{
ObjectMeta: metav1.ObjectMeta{
GenerateName: namePrefix + "-",
},
}
for _, apply := range opts {
apply(spaceBindingRequest)
}
err = memberAwait.CreateWithCleanup(t, spaceBindingRequest)
require.NoError(t, err)

return spaceBindingRequest
}
Loading

0 comments on commit 56cc5bc

Please sign in to comment.