Skip to content

Commit 5d22cc4

Browse files
zmotsoSergK
authored andcommitted
fix: Resolve subgroup creation and assignment issues (#95)
- Fix subgroup creation for the main group - Fix subgroup assignment to users - Add integration tests for KeycloakRealmGroup - Add integration tests for KeycloakRealmUser with subgroup assignments
1 parent 4bc7be0 commit 5d22cc4

17 files changed

+833
-361
lines changed

controllers/keycloakclient/chain/put_client_scope_test.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ package chain
22

33
import (
44
"context"
5-
keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
6-
"github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mocks"
5+
"testing"
6+
77
"github.com/go-logr/logr"
88
"github.com/stretchr/testify/mock"
99
"github.com/stretchr/testify/require"
@@ -13,7 +13,9 @@ import (
1313
ctrl "sigs.k8s.io/controller-runtime"
1414
"sigs.k8s.io/controller-runtime/pkg/client"
1515
"sigs.k8s.io/controller-runtime/pkg/client/fake"
16-
"testing"
16+
17+
keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
18+
"github.com/epam/edp-keycloak-operator/pkg/client/keycloak/mocks"
1719
)
1820

1921
func TestPutClientScope_Serve(t *testing.T) {

controllers/keycloakrealmgroup/keycloakrealmgroup_controller.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ func (r *ReconcileKeycloakRealmGroup) tryReconcile(ctx context.Context, keycloak
130130
return fmt.Errorf("unable to get keycloak realm from ref: %w", err)
131131
}
132132

133-
id, err := kClient.SyncRealmGroup(gocloak.PString(realm.Realm), &keycloakRealmGroup.Spec)
133+
id, err := kClient.SyncRealmGroup(ctx, gocloak.PString(realm.Realm), &keycloakRealmGroup.Spec)
134134
if err != nil {
135135
return fmt.Errorf("unable to sync realm group: %w", err)
136136
}
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
package keycloakrealmgroup
2+
3+
import (
4+
"time"
5+
6+
. "github.com/onsi/ginkgo/v2"
7+
. "github.com/onsi/gomega"
8+
9+
"github.com/Nerzal/gocloak/v12"
10+
k8sErrors "k8s.io/apimachinery/pkg/api/errors"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/types"
13+
14+
"github.com/epam/edp-keycloak-operator/api/common"
15+
keycloakApi "github.com/epam/edp-keycloak-operator/api/v1"
16+
"github.com/epam/edp-keycloak-operator/controllers/helper"
17+
"github.com/epam/edp-keycloak-operator/pkg/client/keycloak/adapter"
18+
"github.com/epam/edp-keycloak-operator/pkg/objectmeta"
19+
)
20+
21+
var _ = Describe("KeycloakRealmGroup controller", Ordered, func() {
22+
const (
23+
groupCR = "test-keycloak-realm-group"
24+
)
25+
It("Should create KeycloakRealmGroup", func() {
26+
By("Creating role for the group")
27+
_, err := keycloakApiClient.CreateRealmRole(ctx, getKeyCloakToken(), KeycloakRealmCR, gocloak.Role{
28+
Name: gocloak.StringP("test-group-role"),
29+
})
30+
Expect(adapter.SkipAlreadyExistsErr(err)).ShouldNot(HaveOccurred())
31+
32+
By("Creating a KeycloakRealmGroup subgroup")
33+
group := &keycloakApi.KeycloakRealmGroup{
34+
ObjectMeta: metav1.ObjectMeta{
35+
Name: "test-subgroup",
36+
Namespace: ns,
37+
},
38+
Spec: keycloakApi.KeycloakRealmGroupSpec{
39+
Name: "test-subgroup",
40+
RealmRef: common.RealmRef{
41+
Kind: keycloakApi.KeycloakRealmKind,
42+
Name: KeycloakRealmCR,
43+
},
44+
Path: "/test-subgroup",
45+
},
46+
}
47+
Expect(k8sClient.Create(ctx, group)).Should(Succeed())
48+
Eventually(func(g Gomega) {
49+
createdGroup := &keycloakApi.KeycloakRealmGroup{}
50+
err = k8sClient.Get(ctx, types.NamespacedName{Name: "test-subgroup", Namespace: ns}, createdGroup)
51+
g.Expect(err).ShouldNot(HaveOccurred())
52+
g.Expect(createdGroup.Status.Value).Should(Equal(helper.StatusOK))
53+
}).WithTimeout(time.Second * 20).WithPolling(time.Second).Should(Succeed())
54+
55+
By("Creating a KeycloakRealmGroup")
56+
group = &keycloakApi.KeycloakRealmGroup{
57+
ObjectMeta: metav1.ObjectMeta{
58+
Name: groupCR,
59+
Namespace: ns,
60+
},
61+
Spec: keycloakApi.KeycloakRealmGroupSpec{
62+
Name: "test-group",
63+
RealmRef: common.RealmRef{
64+
Kind: keycloakApi.KeycloakRealmKind,
65+
Name: KeycloakRealmCR,
66+
},
67+
Path: "/test-group",
68+
RealmRoles: []string{"test-group-role"},
69+
SubGroups: []string{"test-subgroup"},
70+
},
71+
}
72+
Expect(k8sClient.Create(ctx, group)).Should(Succeed())
73+
Eventually(func(g Gomega) {
74+
createdGroup := &keycloakApi.KeycloakRealmGroup{}
75+
err = k8sClient.Get(ctx, types.NamespacedName{Name: groupCR, Namespace: ns}, createdGroup)
76+
g.Expect(err).ShouldNot(HaveOccurred())
77+
g.Expect(createdGroup.Status.Value).Should(Equal(helper.StatusOK))
78+
}).WithTimeout(time.Second * 20).WithPolling(time.Second).Should(Succeed())
79+
})
80+
It("Should update KeycloakRealmGroup", func() {
81+
By("Getting KeycloakRealmGroup")
82+
group := &keycloakApi.KeycloakRealmGroup{}
83+
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: groupCR}, group)).Should(Succeed())
84+
85+
By("Updating a parent KeycloakRealmGroup")
86+
group.Spec.SubGroups = []string{}
87+
88+
Expect(k8sClient.Update(ctx, group)).Should(Succeed())
89+
Eventually(func(g Gomega) {
90+
updatedGroup := &keycloakApi.KeycloakRealmGroup{}
91+
err := k8sClient.Get(ctx, types.NamespacedName{Name: group.Name, Namespace: ns}, updatedGroup)
92+
g.Expect(err).ShouldNot(HaveOccurred())
93+
g.Expect(updatedGroup.Status.Value).Should(Equal(helper.StatusOK))
94+
}, time.Minute, time.Second*5).Should(Succeed())
95+
})
96+
It("Should delete KeycloakRealmGroup", func() {
97+
By("Getting KeycloakRealmGroup")
98+
group := &keycloakApi.KeycloakRealmGroup{}
99+
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: ns, Name: groupCR}, group)).Should(Succeed())
100+
By("Deleting KeycloakRealmGroup")
101+
Expect(k8sClient.Delete(ctx, group)).Should(Succeed())
102+
Eventually(func(g Gomega) {
103+
deletedGroup := &keycloakApi.KeycloakRealmGroup{}
104+
err := k8sClient.Get(ctx, types.NamespacedName{Name: group.Name, Namespace: ns}, deletedGroup)
105+
106+
g.Expect(k8sErrors.IsNotFound(err)).Should(BeTrue())
107+
}, timeout, interval).Should(Succeed())
108+
})
109+
It("Should preserve group with annotation", func() {
110+
By("Creating a KeycloakRealmGroup")
111+
group := &keycloakApi.KeycloakRealmGroup{
112+
ObjectMeta: metav1.ObjectMeta{
113+
Name: "test-keycloak-realm-group-preserve",
114+
Namespace: ns,
115+
Annotations: map[string]string{
116+
objectmeta.PreserveResourcesOnDeletionAnnotation: "true",
117+
},
118+
},
119+
Spec: keycloakApi.KeycloakRealmGroupSpec{
120+
RealmRef: common.RealmRef{
121+
Kind: keycloakApi.KeycloakRealmKind,
122+
Name: KeycloakRealmCR,
123+
},
124+
Name: "test-group-preserve",
125+
},
126+
}
127+
Expect(k8sClient.Create(ctx, group)).Should(Succeed())
128+
Eventually(func(g Gomega) {
129+
createdGroup := &keycloakApi.KeycloakRealmGroup{}
130+
err := k8sClient.Get(ctx, types.NamespacedName{Name: group.Name, Namespace: ns}, createdGroup)
131+
g.Expect(err).ShouldNot(HaveOccurred())
132+
g.Expect(createdGroup.Status.Value).Should(Equal(helper.StatusOK))
133+
}).WithTimeout(time.Second * 20).WithPolling(time.Second).Should(Succeed())
134+
135+
By("Deleting KeycloakRealmGroup")
136+
Expect(k8sClient.Delete(ctx, group)).Should(Succeed())
137+
Eventually(func(g Gomega) {
138+
groups, err := keycloakApiClient.GetGroups(ctx, getKeyCloakToken(), KeycloakRealmCR, gocloak.GetGroupsParams{
139+
Search: gocloak.StringP("test-group-preserve"),
140+
})
141+
g.Expect(err).ShouldNot(HaveOccurred())
142+
g.Expect(groups).Should(HaveLen(1))
143+
}, time.Minute, time.Second*5).Should(Succeed())
144+
})
145+
It("Should fail to create KeycloakRealmGroup with not existing subgroup", func() {
146+
By("Creating a KeycloakRealmGroup")
147+
group := &keycloakApi.KeycloakRealmGroup{
148+
ObjectMeta: metav1.ObjectMeta{
149+
Name: "test-keycloak-realm-group-with-invalid-subgroup",
150+
Namespace: ns,
151+
},
152+
Spec: keycloakApi.KeycloakRealmGroupSpec{
153+
RealmRef: common.RealmRef{
154+
Kind: keycloakApi.KeycloakRealmKind,
155+
Name: KeycloakRealmCR,
156+
},
157+
Name: "test-group-with-invalid-subgroup",
158+
SubGroups: []string{"not-existing-subgroup"},
159+
},
160+
}
161+
Expect(k8sClient.Create(ctx, group)).Should(Succeed())
162+
163+
By("Waiting for KeycloakRealmGroup to be processed")
164+
time.Sleep(time.Second * 3)
165+
166+
By("Checking KeycloakRealmGroup status")
167+
Consistently(func(g Gomega) {
168+
createdGroup := &keycloakApi.KeycloakRealmGroup{}
169+
err := k8sClient.Get(ctx, types.NamespacedName{Name: group.Name, Namespace: ns}, createdGroup)
170+
g.Expect(err).ShouldNot(HaveOccurred())
171+
g.Expect(createdGroup.Status.Value).Should(ContainSubstring("unable to sync realm group"))
172+
}, time.Second*3, time.Second).Should(Succeed())
173+
})
174+
})

controllers/keycloakrealmgroup/keycloakrealmgroup_controller_test.go

Lines changed: 0 additions & 92 deletions
This file was deleted.

0 commit comments

Comments
 (0)