Skip to content

Commit ffa9c0d

Browse files
committed
add basic tester utils
On-behalf-of: @SAP [email protected]
1 parent 0e24491 commit ffa9c0d

File tree

3 files changed

+236
-0
lines changed

3 files changed

+236
-0
lines changed

Diff for: test/utils/deploy.go

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/*
2+
Copyright 2025 The KCP Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package utils
18+
19+
import (
20+
"context"
21+
"os"
22+
"os/exec"
23+
"testing"
24+
25+
"github.com/kcp-dev/logicalcluster/v3"
26+
27+
corev1 "k8s.io/api/core/v1"
28+
"k8s.io/apimachinery/pkg/runtime"
29+
"k8s.io/client-go/rest"
30+
"k8s.io/client-go/scale/scheme"
31+
ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client"
32+
"sigs.k8s.io/controller-runtime/pkg/envtest"
33+
)
34+
35+
func RunAgent(
36+
ctx context.Context,
37+
t *testing.T,
38+
name string,
39+
kcpKubeconfig string,
40+
localKubeconfig string,
41+
apiExportCluster logicalcluster.Path,
42+
apiExport string,
43+
) context.CancelFunc {
44+
t.Helper()
45+
46+
t.Logf("Running agent %q…", name)
47+
48+
args := []string{
49+
"--agent-name", name,
50+
"--apiexport-ref", apiExport,
51+
"--enable-leader-election=false",
52+
"--kubeconfig", localKubeconfig,
53+
"--kcp-kubeconfig", kcpKubeconfig,
54+
"--namespace", "kube-system",
55+
}
56+
57+
localCtx, cancel := context.WithCancel(ctx)
58+
59+
cmd := exec.CommandContext(localCtx, "_build/api-syncagent", args...)
60+
if err := cmd.Start(); err != nil {
61+
t.Fatalf("Failed to start api-syncagent: %v", err)
62+
}
63+
64+
cancelAndWait := func() {
65+
cancel()
66+
_ = cmd.Wait()
67+
}
68+
69+
t.Cleanup(cancelAndWait)
70+
71+
return cancelAndWait
72+
}
73+
74+
func RunEnvtest(t *testing.T) (string, ctrlruntimeclient.Client, context.CancelFunc) {
75+
t.Helper()
76+
77+
testEnv := &envtest.Environment{
78+
CRDDirectoryPaths: []string{"../../../deploy/crd/kcp.io"},
79+
ErrorIfCRDPathMissing: true,
80+
}
81+
82+
_, err := testEnv.Start()
83+
if err != nil {
84+
t.Fatalf("Failed to start envtest: %v", err)
85+
}
86+
87+
adminKubeconfig, adminRestConfig := createEnvtestKubeconfig(t, testEnv)
88+
if err != nil {
89+
t.Fatal(err)
90+
}
91+
92+
sc := runtime.NewScheme()
93+
if err := scheme.AddToScheme(sc); err != nil {
94+
t.Fatal(err)
95+
}
96+
if err := corev1.AddToScheme(sc); err != nil {
97+
t.Fatal(err)
98+
}
99+
100+
client, err := ctrlruntimeclient.New(adminRestConfig, ctrlruntimeclient.Options{
101+
Scheme: sc,
102+
})
103+
if err != nil {
104+
t.Fatalf("Failed to create client: %v", err)
105+
}
106+
107+
cancelAndWait := func() {
108+
_ = testEnv.Stop()
109+
}
110+
111+
t.Cleanup(cancelAndWait)
112+
113+
return adminKubeconfig, client, cancelAndWait
114+
}
115+
116+
func createEnvtestKubeconfig(t *testing.T, env *envtest.Environment) (string, *rest.Config) {
117+
adminInfo := envtest.User{Name: "admin", Groups: []string{"system:masters"}}
118+
119+
adminUser, err := env.ControlPlane.AddUser(adminInfo, nil)
120+
if err != nil {
121+
t.Fatal(err)
122+
}
123+
124+
adminKubeconfig, err := adminUser.KubeConfig()
125+
if err != nil {
126+
t.Fatal(err)
127+
}
128+
129+
kubeconfigFile, err := os.CreateTemp(os.TempDir(), "kubeconfig*")
130+
if err != nil {
131+
t.Fatalf("Failed to create envtest kubeconfig file: %v", err)
132+
}
133+
defer kubeconfigFile.Close()
134+
135+
if _, err := kubeconfigFile.Write(adminKubeconfig); err != nil {
136+
t.Fatalf("Failed to write envtest kubeconfig file: %v", err)
137+
}
138+
139+
return kubeconfigFile.Name(), adminUser.Config()
140+
}

Diff for: test/utils/utils.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
Copyright 2025 The KCP Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package utils
18+
19+
import (
20+
"os"
21+
"testing"
22+
23+
corev1 "k8s.io/api/core/v1"
24+
"k8s.io/apimachinery/pkg/runtime"
25+
"k8s.io/client-go/scale/scheme"
26+
"k8s.io/client-go/tools/clientcmd"
27+
ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client"
28+
)
29+
30+
func GetKcpClient(t *testing.T) ctrlruntimeclient.Client {
31+
t.Helper()
32+
33+
sc := runtime.NewScheme()
34+
if err := scheme.AddToScheme(sc); err != nil {
35+
t.Fatal(err)
36+
}
37+
if err := corev1.AddToScheme(sc); err != nil {
38+
t.Fatal(err)
39+
}
40+
41+
config, err := clientcmd.BuildConfigFromFlags("", os.Getenv("KCP_KUBECONFIG"))
42+
if err != nil {
43+
t.Fatalf("Failed to get kcp kubeconfig: %v", err)
44+
}
45+
46+
client, err := ctrlruntimeclient.New(config, ctrlruntimeclient.Options{
47+
Scheme: sc,
48+
})
49+
if err != nil {
50+
t.Fatalf("Failed to create client: %v", err)
51+
}
52+
53+
return client
54+
}

Diff for: test/utils/wait.go

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Copyright 2025 The KCP Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package utils
18+
19+
import (
20+
"context"
21+
"testing"
22+
"time"
23+
24+
"k8s.io/apimachinery/pkg/types"
25+
"k8s.io/apimachinery/pkg/util/wait"
26+
ctrlruntimeclient "sigs.k8s.io/controller-runtime/pkg/client"
27+
)
28+
29+
func WaitForObject(t *testing.T, ctx context.Context, client ctrlruntimeclient.Client, obj ctrlruntimeclient.Object, key types.NamespacedName) {
30+
t.Helper()
31+
t.Logf("Waiting for %T to exist…", obj)
32+
33+
err := wait.PollUntilContextTimeout(ctx, 500*time.Millisecond, 3*time.Minute, false, func(ctx context.Context) (done bool, err error) {
34+
err = client.Get(ctx, key, obj)
35+
return err == nil, nil
36+
})
37+
if err != nil {
38+
t.Fatalf("Failed to wait for %T to exist: %v", obj, err)
39+
}
40+
41+
t.Logf("%T is ready.", obj)
42+
}

0 commit comments

Comments
 (0)