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

add tests for PublicViewer support #931

Closed
wants to merge 2 commits into from
Closed
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
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,7 @@ require (
)

go 1.20

replace github.com/codeready-toolchain/toolchain-common => github.com/filariow/toolchain-common v0.0.0-20240322165115-87027670d9b3

replace github.com/codeready-toolchain/api => github.com/filariow/toolchain-api v0.0.0-20240322163859-f974f2dbbc8e
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,6 @@ 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-20240322110702-5ab3840476e9 h1:Lm7bFLrzfJzrUiRGVqtsSaZMpj+akLiR/fvAFjjE9gM=
github.com/codeready-toolchain/api v0.0.0-20240322110702-5ab3840476e9/go.mod h1:cfNN6YPX4TORvhhZXMSjSPesqAHlB3nD/WAfGe4WLKQ=
github.com/codeready-toolchain/toolchain-common v0.0.0-20240322131000-8d44f7428e83 h1:j+3snE8RGTyB5MdwPUqIfmAm9C2aScCni+ma1EveC4c=
github.com/codeready-toolchain/toolchain-common v0.0.0-20240322131000-8d44f7428e83/go.mod h1:OJ3L9aaTRMGjxr2WeH/9l6m5OjExwEK3Bp/+P+efoGg=
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 Expand Up @@ -184,6 +180,10 @@ github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
github.com/filariow/toolchain-api v0.0.0-20240322163859-f974f2dbbc8e h1:h+uO6jYovPD3j9VIo9JajpmTZIyl7x6wSap/4RjS6aw=
github.com/filariow/toolchain-api v0.0.0-20240322163859-f974f2dbbc8e/go.mod h1:cfNN6YPX4TORvhhZXMSjSPesqAHlB3nD/WAfGe4WLKQ=
github.com/filariow/toolchain-common v0.0.0-20240322165115-87027670d9b3 h1:k1kjVkS1CUazxpA8Hu0X6M4ChubNhGmHSQUEUhfGo4I=
github.com/filariow/toolchain-common v0.0.0-20240322165115-87027670d9b3/go.mod h1:2vTPf4wRr6Q9Pq3zkJ5I3wBNagXEMvyjmdk8w0/UJRE=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
Expand Down
26 changes: 26 additions & 0 deletions make/test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,14 @@ E2E_PARALLELISM=1

TESTS_RUN_FILTER_REGEXP ?= ""

.PHONY: test-e2e-community
test-e2e-community: prepare-e2e deploy-e2e e2e-run-community
@:

.PHONY: test-e2e-community-local
test-e2e-community-local: prepare-e2e deploy-e2e-local e2e-run-community
@:

.PHONY: test-e2e
## Run the e2e tests
test-e2e: INSTALL_OPERATOR=true
Expand Down Expand Up @@ -116,15 +124,33 @@ test-e2e-registration-local:
.PHONY: e2e-run-parallel
e2e-run-parallel:
@echo "Running e2e tests in parallel..."
oc patch -n ${HOST_NS} toolchainconfigs.toolchain.dev.openshift.com config --patch='{"spec":{"global":{"publicViewer":{"enabled":false}}}}' --type=merge
oc delete -n ${HOST_NS} pods -l control-plane=controller-manager
oc delete -n ${HOST_NS} pod -l name=registration-service
Comment on lines +128 to +129
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: What's the difference between oc delete pods (plural) and oc delete pod (singular)? I'd prefer a convention that we stick to.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a typo 😄 good catch!

oc rollout -n ${HOST_NS} status deployment
$(MAKE) execute-tests MEMBER_NS=${MEMBER_NS} MEMBER_NS_2=${MEMBER_NS_2} HOST_NS=${HOST_NS} REGISTRATION_SERVICE_NS=${REGISTRATION_SERVICE_NS} TESTS_TO_EXECUTE="./test/e2e/parallel" E2E_PARALLELISM=100
@echo "The parallel e2e tests successfully finished"

.PHONY: e2e-run
e2e-run:
@echo "Running e2e tests..."
oc patch -n ${HOST_NS} toolchainconfigs.toolchain.dev.openshift.com config --patch='{"spec":{"global":{"publicViewer":{"enabled":false}}}}' --type=merge
oc delete -n ${HOST_NS} pods -l control-plane=controller-manager
oc delete -n ${HOST_NS} pod -l name=registration-service
oc rollout -n ${HOST_NS} status deployment
$(MAKE) execute-tests MEMBER_NS=${MEMBER_NS} MEMBER_NS_2=${MEMBER_NS_2} HOST_NS=${HOST_NS} REGISTRATION_SERVICE_NS=${REGISTRATION_SERVICE_NS} TESTS_TO_EXECUTE="./test/e2e ./test/metrics"
@echo "The e2e tests successfully finished"

.PHONY: e2e-run-community
e2e-run-community:
@echo "Running e2e community tests..."
oc patch -n ${HOST_NS} toolchainconfigs.toolchain.dev.openshift.com config --patch='{"spec":{"global":{"publicViewer":{"enabled":true,"username":"public-viewer"}}}}' --type=merge
oc delete -n ${HOST_NS} pods -l control-plane=controller-manager
oc delete -n ${HOST_NS} pod -l name=registration-service
oc rollout -n ${HOST_NS} status deployment
$(MAKE) execute-tests MEMBER_NS=${MEMBER_NS} MEMBER_NS_2=${MEMBER_NS_2} HOST_NS=${HOST_NS} REGISTRATION_SERVICE_NS=${REGISTRATION_SERVICE_NS} TESTS_TO_EXECUTE="./test/e2e/community"
@echo "The e2e community tests successfully finished"

.PHONY: execute-tests
execute-tests:
@echo "Present Spaces"
Expand Down
191 changes: 191 additions & 0 deletions test/e2e/community/proxy_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
package community_test

import (
"context"
"testing"

"github.com/gofrs/uuid"
"github.com/stretchr/testify/require"

corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/selection"
waitpoll "k8s.io/apimachinery/pkg/util/wait"
"sigs.k8s.io/controller-runtime/pkg/client"

toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"
commonauth "github.com/codeready-toolchain/toolchain-common/pkg/test/auth"
. "github.com/codeready-toolchain/toolchain-e2e/testsupport"
authsupport "github.com/codeready-toolchain/toolchain-e2e/testsupport/auth"
"github.com/codeready-toolchain/toolchain-e2e/testsupport/spacebinding"
"github.com/codeready-toolchain/toolchain-e2e/testsupport/tiers"
"github.com/codeready-toolchain/toolchain-e2e/testsupport/wait"
)

type proxyUser struct {
expectedMemberCluster *wait.MemberAwaitility
username string
token string
identityID uuid.UUID
signup *toolchainv1alpha1.UserSignup
compliantUsername string
}

// tests access to community-shared spaces
func TestPublicViewerProxy(t *testing.T) {
// given

// make sure everything is ready before running the actual tests
awaitilities := WaitForDeployments(t)
hostAwait := awaitilities.Host()
memberAwait := awaitilities.Member1()
// we create a space to share , a new MUR and a SpaceBindingRequest
space, _, _ := NewSpaceBindingRequest(t, awaitilities, memberAwait, hostAwait, "admin")

communityUser := &proxyUser{
expectedMemberCluster: memberAwait,
username: "community-user",
identityID: uuid.Must(uuid.NewV4()),
}
createAppStudioUser(t, awaitilities, communityUser)

communityUserProxyClient, err := hostAwait.CreateAPIProxyClient(t, communityUser.token, hostAwait.APIProxyURL)
require.NoError(t, err)

t.Run("space is flagged as community", func(t *testing.T) {
// when
sb := CreateCommunitySpaceBinding(t, hostAwait, space.Name, space.Namespace)
require.NoError(t, err)
t.Logf("created space binding for public-viewer:\n%+v", sb)

// Wait until space is flagged as community
require.NoError(t,
waitpoll.Poll(hostAwait.RetryInterval, hostAwait.Timeout, func() (bool, error) {
mr, err := labels.NewRequirement(toolchainv1alpha1.SpaceBindingMasterUserRecordLabelKey, selection.In, []string{"public-viewer"})
if err != nil {
return false, err
}

sr, err := labels.NewRequirement(toolchainv1alpha1.SpaceBindingSpaceLabelKey, selection.Equals, []string{space.Name})
if err != nil {
return false, err
}

opts := &client.ListOptions{
Namespace: space.Namespace,
LabelSelector: labels.NewSelector().Add(*sr, *mr),
}
sbs := &toolchainv1alpha1.SpaceBindingList{}
if err := hostAwait.Client.List(context.TODO(), sbs, opts); err != nil {
return false, err
}

return len(sbs.Items) == 1, nil
}))

sp := toolchainv1alpha1.Space{}
err = hostAwait.Client.Get(context.TODO(), client.ObjectKeyFromObject(space), &sp)
require.NoError(t, err)

/*
Given Space exists for user A
Given User community-user exists
When A flags their space visibility to "community"
Then community-user can view A's Space
And community-user cannot create resources in A's Space
*/
t.Run("community user access to community space", func(t *testing.T) {
require.NotEmpty(t, sp.Status.ProvisionedNamespaces)

t.Run("community user can list config maps from community space", func(t *testing.T) {
// then
cms := corev1.ConfigMapList{}

communityUserProxyClient, err := hostAwait.CreateAPIProxyClient(t, communityUser.token, hostAwait.ProxyURLWithWorkspaceContext(sp.Name))
require.NoError(t, err)

err = communityUserProxyClient.List(context.TODO(), &cms, client.InNamespace(sp.Status.ProvisionedNamespaces[0].Name))
require.NoError(t, err)
})

t.Run("community user cannot create config maps into space", func(t *testing.T) {
cm := corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cm",
Namespace: sp.Status.ProvisionedNamespaces[0].Name,
},
}
err := communityUserProxyClient.Create(context.TODO(), &cm)
require.Error(t, err)
})
})

/*
Given Space exists for user A
Given SSO user joe exists
When A flags their space visibility to "community"
Then joe can view A's Space
And joe cannot create resources in A's Space
*/
t.Run("as sso user", func(t *testing.T) {
// Given
userIdentity := &commonauth.Identity{
ID: uuid.Must(uuid.NewV4()),
Username: "joe",
}
claims := []commonauth.ExtraClaim{commonauth.WithEmailClaim("[email protected]")}
token, err := authsupport.NewTokenFromIdentity(userIdentity, claims...)
require.NoError(t, err)

joeCli, err := hostAwait.CreateAPIProxyClient(t, token, hostAwait.ProxyURLWithWorkspaceContext(sp.Name))
require.NoError(t, err)

t.Run("sso user can list config maps from space", func(t *testing.T) {
// then
cms := corev1.ConfigMapList{}
err := joeCli.List(context.TODO(), &cms, client.InNamespace(sp.Status.ProvisionedNamespaces[0].Name))
require.NoError(t, err)
})

t.Run("sso user cannot create config maps into space", func(t *testing.T) {
// then
cm := corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Name: "test-cm",
Namespace: sp.Status.ProvisionedNamespaces[0].Name,
},
}
err := joeCli.Create(context.TODO(), &cm)
require.Error(t, err)
})
})
})
}

func createAppStudioUser(t *testing.T, awaitilities wait.Awaitilities, user *proxyUser) {
// Create and approve signup
req := NewSignupRequest(awaitilities).
Username(user.username).
IdentityID(user.identityID).
ManuallyApprove().
TargetCluster(user.expectedMemberCluster).
EnsureMUR().
RequireConditions(wait.ConditionSet(wait.Default(), wait.ApprovedByAdmin())...).
Execute(t)
user.signup, _ = req.Resources()
user.token = req.GetToken()
tiers.MoveSpaceToTier(t, awaitilities.Host(), user.signup.Status.CompliantUsername, "appstudio")
VerifyResourcesProvisionedForSignup(t, awaitilities, user.signup, "deactivate30", "appstudio")
user.compliantUsername = user.signup.Status.CompliantUsername
_, err := awaitilities.Host().WaitForMasterUserRecord(t, user.compliantUsername, wait.UntilMasterUserRecordHasCondition(wait.Provisioned()))
require.NoError(t, err)
}

func CreateCommunitySpaceBinding(
t *testing.T,
hostAwait *wait.HostAwaitility,
spaceName, spaceNamespace string,
) *toolchainv1alpha1.SpaceBinding {
return spacebinding.CreateSpaceBindingStr(t, hostAwait, "public-viewer", spaceName, spaceNamespace, "contributor")
}
88 changes: 88 additions & 0 deletions test/e2e/community/spacebindingrequest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package community_test

import (
"sort"
"testing"

"github.com/gofrs/uuid"
"github.com/stretchr/testify/require"

"k8s.io/apimachinery/pkg/types"

toolchainv1alpha1 "github.com/codeready-toolchain/api/api/v1alpha1"

testspace "github.com/codeready-toolchain/toolchain-common/pkg/test/space"
spacebindingrequesttestcommon "github.com/codeready-toolchain/toolchain-common/pkg/test/spacebindingrequest"
. "github.com/codeready-toolchain/toolchain-e2e/testsupport"
testsupportspace "github.com/codeready-toolchain/toolchain-e2e/testsupport/space"
"github.com/codeready-toolchain/toolchain-e2e/testsupport/spacebinding"
"github.com/codeready-toolchain/toolchain-e2e/testsupport/wait"
)

func NewSpaceBindingRequest(
t *testing.T,
awaitilities wait.Awaitilities,
memberAwait *wait.MemberAwaitility,
hostAwait *wait.HostAwaitility,
spaceRole string,
) (
*toolchainv1alpha1.Space,
*toolchainv1alpha1.SpaceBindingRequest,
*toolchainv1alpha1.SpaceBinding,
) {
space, firstUserSignup, _ := testsupportspace.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, wait.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(wait.ConditionSet(wait.Default(), wait.ApprovedByAdmin())...).
NoSpace().
WaitForMUR().Execute(t).Resources()
// create the spacebinding request
spaceBindingRequest := spacebinding.CreateSpaceBindingRequest(t, awaitilities, memberAwait.ClusterName,
spacebinding.WithSpecSpaceRole(spaceRole),

spacebinding.WithSpecMasterUserRecord(secondUserMUR.GetName()),
spacebinding.WithNamespace(testsupportspace.GetDefaultNamespace(space.Status.ProvisionedNamespaces)),
)

// then
// check for the spaceBinding creation
spaceBinding, err := hostAwait.WaitForSpaceBinding(t, spaceBindingRequest.Spec.MasterUserRecord, space.Name,
wait.UntilSpaceBindingHasMurName(spaceBindingRequest.Spec.MasterUserRecord),
wait.UntilSpaceBindingHasSpaceName(space.Name),
wait.UntilSpaceBindingHasSpaceRole(spaceBindingRequest.Spec.SpaceRole),
wait.UntilSpaceBindingHasLabel(toolchainv1alpha1.SpaceBindingRequestLabelKey, spaceBindingRequest.GetName()),
wait.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()},
wait.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,
wait.UntilNSTemplateSetHasSpaceRoles(
wait.SpaceRole(tier.Spec.SpaceRoles[spaceRole].TemplateRef, usernamesSorted[0], usernamesSorted[1])))
require.NoError(t, err)
} else {
_, err = memberAwait.WaitForNSTmplSet(t, space.Name,
wait.UntilNSTemplateSetHasSpaceRoles(
wait.SpaceRole(tier.Spec.SpaceRoles["admin"].TemplateRef, firstUserSignup.Status.CompliantUsername),
wait.SpaceRole(tier.Spec.SpaceRoles[spaceRole].TemplateRef, secondUserMUR.Name)))
require.NoError(t, err)
}
testsupportspace.VerifyResourcesProvisionedForSpace(t, awaitilities, space.Name)
return space, spaceBindingRequest, spaceBinding
}
Loading
Loading