Skip to content

Commit fe1a030

Browse files
authored
Merge pull request #38 from SimonTheLeg/front-proxy-e2e-tests
✨ Add e2e tests for frontproxy objects
2 parents 7e3bf97 + 684b625 commit fe1a030

File tree

7 files changed

+148
-6
lines changed

7 files changed

+148
-6
lines changed

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,12 @@ graph TB
7272
classDef ca color:#F77
7373
classDef cert color:orange
7474
```
75+
76+
### Running E2E tests locally
77+
78+
In order to run the E2E tests locally, you will need to setup cert-manager with the sample clusterissuer:
79+
80+
```sh
81+
helm upgrade --install --namespace cert-manager --create-namespace --version v1.16.2 --set crds.enabled=true cert-manager jetstack/cert-manager
82+
kubectl apply -n cert-manager --filename hack/ci/testdata/clusterissuer.yaml
83+
```

internal/controller/suite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ var _ = BeforeSuite(func() {
7070
// default path defined in controller-runtime which is /usr/local/kubebuilder/.
7171
// Note that you must have the required binaries setup under the bin directory to perform
7272
// the tests directly. When we run make test it will be setup and used automatically.
73-
BinaryAssetsDirectory: filepath.Join("..", "..", "bin", "k8s",
73+
BinaryAssetsDirectory: filepath.Join("..", "..", "_tools", "k8s",
7474
fmt.Sprintf("1.31.0-%s-%s", runtime.GOOS, runtime.GOARCH)),
7575
}
7676

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
//go:build e2e
2+
3+
/*
4+
Copyright 2025 The KCP Authors.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
package frontproxies
20+
21+
import (
22+
"context"
23+
"fmt"
24+
"testing"
25+
"time"
26+
27+
"github.com/go-logr/logr"
28+
29+
corev1 "k8s.io/api/core/v1"
30+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31+
"k8s.io/apimachinery/pkg/types"
32+
ctrlruntime "sigs.k8s.io/controller-runtime"
33+
34+
operatorv1alpha1 "github.com/kcp-dev/kcp-operator/sdk/apis/operator/v1alpha1"
35+
"github.com/kcp-dev/kcp-operator/test/utils"
36+
)
37+
38+
func TestCreateFrontProxy(t *testing.T) {
39+
fmt.Println()
40+
41+
ctrlruntime.SetLogger(logr.Discard())
42+
43+
client := utils.GetKubeClient(t)
44+
ctx := context.Background()
45+
namespace := "create-frontproxy"
46+
47+
utils.CreateSelfDestructingNamespace(t, ctx, client, namespace)
48+
49+
externalHostname := "front-proxy-front-proxy.svc.cluster.local"
50+
51+
// deploy rootshard
52+
rootShard := utils.DeployRootShard(ctx, t, client, namespace, externalHostname)
53+
54+
// deploy front-proxy
55+
frontProxy := utils.DeployFrontProxy(ctx, t, client, namespace, rootShard.Name, externalHostname)
56+
57+
// create front-proxy kubeconfig
58+
configSecretName := "kubeconfig-front-proxy-e2e"
59+
60+
fpConfig := operatorv1alpha1.Kubeconfig{}
61+
fpConfig.Name = "front-proxy"
62+
fpConfig.Namespace = namespace
63+
fpConfig.Spec = operatorv1alpha1.KubeconfigSpec{
64+
Target: operatorv1alpha1.KubeconfigTarget{
65+
FrontProxyRef: &corev1.LocalObjectReference{
66+
Name: frontProxy.Name,
67+
},
68+
},
69+
Username: "e2e",
70+
Validity: metav1.Duration{Duration: 2 * time.Hour},
71+
SecretRef: corev1.LocalObjectReference{
72+
Name: configSecretName,
73+
},
74+
Groups: []string{"system:masters"},
75+
}
76+
77+
t.Log("Creating kubeconfig for FrontProxy…")
78+
if err := client.Create(ctx, &fpConfig); err != nil {
79+
t.Fatal(err)
80+
}
81+
utils.WaitForObject(t, ctx, client, &corev1.Secret{}, types.NamespacedName{Namespace: fpConfig.Namespace, Name: fpConfig.Spec.SecretRef.Name})
82+
83+
// verify that we can use frontproxy kubeconfig to access rootshard workspaces
84+
t.Log("Connecting to FrontProxy…")
85+
kcpClient := utils.ConnectWithKubeconfig(t, ctx, client, namespace, fpConfig.Name)
86+
// proof of life: list something every logicalcluster in kcp has
87+
t.Log("Should be able to list Secrets.")
88+
secrets := &corev1.SecretList{}
89+
if err := kcpClient.List(ctx, secrets); err != nil {
90+
t.Fatalf("Failed to list secrets in kcp: %v", err)
91+
}
92+
}

test/e2e/rootshards/rootshards_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestCreateRootShard(t *testing.T) {
4242
namespace := "create-rootshard"
4343

4444
utils.CreateSelfDestructingNamespace(t, ctx, client, namespace)
45-
rootShard := utils.DeployRootShard(ctx, t, client, namespace)
45+
rootShard := utils.DeployRootShard(ctx, t, client, namespace, "example.localhost")
4646

4747
configSecretName := "kubeconfig"
4848

test/e2e/shards/shards_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func TestCreateShard(t *testing.T) {
4747
utils.CreateSelfDestructingNamespace(t, ctx, client, namespace)
4848

4949
// deploy a root shard incl. etcd
50-
rootShard := utils.DeployRootShard(ctx, t, client, namespace)
50+
rootShard := utils.DeployRootShard(ctx, t, client, namespace, "example.localhost")
5151

5252
// deploy a 2nd shard incl. etcd
5353
shardName := "aadvark"

test/utils/deploy.go

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func DeployShard(ctx context.Context, t *testing.T, client ctrlruntimeclient.Cli
106106
return shard
107107
}
108108

109-
func DeployRootShard(ctx context.Context, t *testing.T, client ctrlruntimeclient.Client, namespace string, patches ...func(*operatorv1alpha1.RootShard)) operatorv1alpha1.RootShard {
109+
func DeployRootShard(ctx context.Context, t *testing.T, client ctrlruntimeclient.Client, namespace string, externalHostname string, patches ...func(*operatorv1alpha1.RootShard)) operatorv1alpha1.RootShard {
110110
t.Helper()
111111

112112
etcd := DeployEtcd(t, "etcd-r00t", namespace)
@@ -117,7 +117,7 @@ func DeployRootShard(ctx context.Context, t *testing.T, client ctrlruntimeclient
117117

118118
rootShard.Spec = operatorv1alpha1.RootShardSpec{
119119
External: operatorv1alpha1.ExternalConfig{
120-
Hostname: "example.localhost",
120+
Hostname: externalHostname,
121121
Port: 6443,
122122
},
123123
Cache: operatorv1alpha1.CacheConfig{
@@ -155,3 +155,44 @@ func DeployRootShard(ctx context.Context, t *testing.T, client ctrlruntimeclient
155155

156156
return rootShard
157157
}
158+
159+
func DeployFrontProxy(ctx context.Context, t *testing.T, client ctrlruntimeclient.Client, namespace string, rootShardName string, externalHostname string, patches ...func(*operatorv1alpha1.FrontProxy)) operatorv1alpha1.FrontProxy {
160+
t.Helper()
161+
162+
frontProxy := operatorv1alpha1.FrontProxy{}
163+
frontProxy.Name = "front-proxy"
164+
frontProxy.Namespace = namespace
165+
166+
frontProxy.Spec = operatorv1alpha1.FrontProxySpec{
167+
RootShard: operatorv1alpha1.RootShardConfig{
168+
Reference: &corev1.LocalObjectReference{
169+
Name: rootShardName,
170+
},
171+
},
172+
ExternalHostname: externalHostname,
173+
Auth: &operatorv1alpha1.AuthSpec{
174+
// we need to remove the default system:masters group in order to do our testing
175+
DropGroups: []string{""},
176+
},
177+
}
178+
179+
for _, patch := range patches {
180+
patch(&frontProxy)
181+
}
182+
183+
t.Logf("Creating FrontProxy %s…", frontProxy.Name)
184+
if err := client.Create(ctx, &frontProxy); err != nil {
185+
t.Fatal(err)
186+
}
187+
188+
opts := []ctrlruntimeclient.ListOption{
189+
ctrlruntimeclient.InNamespace(frontProxy.Namespace),
190+
ctrlruntimeclient.MatchingLabels{
191+
"app.kubernetes.io/component": "front-proxy",
192+
"app.kubernetes.io/instance": frontProxy.Name,
193+
},
194+
}
195+
WaitForPods(t, ctx, client, opts...)
196+
197+
return frontProxy
198+
}

test/utils/wait.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func WaitForPods(t *testing.T, ctx context.Context, client ctrlruntimeclient.Cli
3232

3333
t.Log("Waiting for pods to be available…")
3434

35-
err := wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, 3*time.Minute, false, func(ctx context.Context) (done bool, err error) {
35+
err := wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, 5*time.Minute, false, func(ctx context.Context) (done bool, err error) {
3636
pods := corev1.PodList{}
3737
if err := client.List(ctx, &pods, listOpts...); err != nil {
3838
return false, err

0 commit comments

Comments
 (0)