Skip to content

Commit 5c992e0

Browse files
committed
(e2e) add e2e test for user defined service account
1 parent f152699 commit 5c992e0

File tree

3 files changed

+473
-1
lines changed

3 files changed

+473
-1
lines changed

test/e2e/installplan_e2e_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,15 @@ func buildInstallPlanCleanupFunc(crc versioned.Interface, namespace string, inst
6565
}
6666

6767
func fetchInstallPlan(t *testing.T, c versioned.Interface, name string, checkPhase checkInstallPlanFunc) (*v1alpha1.InstallPlan, error) {
68+
return fetchInstallPlanWithNamespace(t, c, name, testNamespace, checkPhase)
69+
}
70+
71+
func fetchInstallPlanWithNamespace(t *testing.T, c versioned.Interface, name string, namespace string, checkPhase checkInstallPlanFunc) (*v1alpha1.InstallPlan, error) {
6872
var fetchedInstallPlan *v1alpha1.InstallPlan
6973
var err error
7074

7175
err = wait.Poll(pollInterval, pollDuration, func() (bool, error) {
72-
fetchedInstallPlan, err = c.OperatorsV1alpha1().InstallPlans(testNamespace).Get(name, metav1.GetOptions{})
76+
fetchedInstallPlan, err = c.OperatorsV1alpha1().InstallPlans(namespace).Get(name, metav1.GetOptions{})
7377
if err != nil || fetchedInstallPlan == nil {
7478
return false, err
7579
}

test/e2e/scoped_client_test.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
package e2e
2+
3+
import (
4+
"testing"
5+
"time"
6+
7+
"github.com/sirupsen/logrus"
8+
"github.com/stretchr/testify/require"
9+
corev1 "k8s.io/api/core/v1"
10+
k8serrors "k8s.io/apimachinery/pkg/api/errors"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/util/wait"
13+
"k8s.io/client-go/tools/clientcmd"
14+
15+
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/operatorclient"
16+
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped"
17+
)
18+
19+
// TestScopedClient ensures that we we can create a scoped client bound to a
20+
// service account and then we can use the scoped client to make API calls.
21+
func TestScopedClient(t *testing.T) {
22+
defer cleaner.NotifyTestComplete(t, false)
23+
24+
require.NotEmpty(t, kubeConfigPath)
25+
26+
config, err := clientcmd.BuildConfigFromFlags("", *kubeConfigPath)
27+
require.NoError(t, err)
28+
29+
kubeclient := newKubeClient(t)
30+
crclient := newCRClient(t)
31+
32+
logger := logrus.New()
33+
34+
tests := []struct {
35+
name string
36+
grant func(namespace, name string) (cleanup cleanupFunc)
37+
assertFunc func(errGot error)
38+
}{
39+
// The parent test invokes 'Get' API on non existent objects. If the
40+
// scoped client has enough permission, we expect a NotFound error code.
41+
// Otherwise, we expect a 'Forbidden' error code due to lack of permission.
42+
{
43+
// The service account does not have any permission granted to it.
44+
// We expect the get api call to return 'Forbidden' error due to
45+
// lack of permission.
46+
name: "ServiceAccountDoesNotHaveAnyPermission",
47+
assertFunc: func(errGot error) {
48+
require.True(t, k8serrors.IsForbidden(errGot))
49+
},
50+
},
51+
{
52+
// The service account does have permission granted to it.
53+
// We expect the get api call to return 'NotFound' error.
54+
name: "ServiceAccountHasPermission",
55+
grant: func(namespace, name string) (cleanup cleanupFunc) {
56+
cleanup = grantPermission(t, kubeclient, namespace, name)
57+
return
58+
},
59+
assertFunc: func(errGot error) {
60+
require.True(t, k8serrors.IsNotFound(errGot))
61+
},
62+
},
63+
}
64+
65+
for _, tt := range tests {
66+
t.Run(tt.name, func(t *testing.T) {
67+
// Steps:
68+
// 1. Create a new namespace
69+
// 2. Create a service account.
70+
// 3. Grant permission(s) to the service account if specified.
71+
// 4. Get scoped client instance(s)
72+
// 5. Invoke Get API call on non existent object(s) to check if
73+
// the call can be made successfully.
74+
namespace := genName("a")
75+
_, cleanupNS := newNamespace(t, kubeclient, namespace)
76+
defer cleanupNS()
77+
78+
saName := genName("user-defined-")
79+
sa, cleanupSA := newServiceAccount(t, kubeclient, namespace, saName)
80+
defer cleanupSA()
81+
82+
waitForServiceAccountSecretAvailable(t, kubeclient, sa.GetNamespace(), sa.GetName())
83+
84+
strategy := scoped.NewClientAttenuator(logger, config, kubeclient, crclient)
85+
getter := func() (reference *corev1.ObjectReference, err error) {
86+
reference = &corev1.ObjectReference{
87+
Namespace: namespace,
88+
Name: saName,
89+
}
90+
91+
return
92+
}
93+
94+
if tt.grant != nil {
95+
cleanupPerm := tt.grant(sa.GetNamespace(), sa.GetName())
96+
defer cleanupPerm()
97+
}
98+
99+
// We expect to get scoped client instance(s).
100+
kubeclientGot, crclientGot, errGot := strategy.AttenuateClient(getter)
101+
require.NoError(t, errGot)
102+
require.NotNil(t, kubeclientGot)
103+
require.NotNil(t, crclientGot)
104+
105+
_, errGot = kubeclientGot.KubernetesInterface().CoreV1().ConfigMaps(namespace).Get(genName("does-not-exist-"), metav1.GetOptions{})
106+
require.Error(t, errGot)
107+
tt.assertFunc(errGot)
108+
109+
_, errGot = crclientGot.OperatorsV1alpha1().CatalogSources(namespace).Get(genName("does-not-exist-"), metav1.GetOptions{})
110+
require.Error(t, errGot)
111+
tt.assertFunc(errGot)
112+
})
113+
}
114+
}
115+
116+
func waitForServiceAccountSecretAvailable(t *testing.T, client operatorclient.ClientInterface, namespace, name string) *corev1.ServiceAccount {
117+
var sa *corev1.ServiceAccount
118+
err := wait.Poll(5*time.Second, time.Minute, func() (bool, error) {
119+
sa, err := client.KubernetesInterface().CoreV1().ServiceAccounts(namespace).Get(name, metav1.GetOptions{})
120+
if err != nil {
121+
return false, err
122+
}
123+
124+
if len(sa.Secrets) > 0 {
125+
return true, nil
126+
}
127+
128+
return false, nil
129+
130+
})
131+
132+
require.NoError(t, err)
133+
return sa
134+
}

0 commit comments

Comments
 (0)