Skip to content

Commit fe915e8

Browse files
committed
Adds unit test to test CRDs
Tests the current CRDs against example valid and invalid CRDs. There are two ways to use this: Test cases ---------- Each test case takes its name from the name of the resource being instantiated. - pkg/crdtest/testdata/{valid, invalid} Running ------- Run as a standard Go-test: $ go test ./pkg/crdtest Run in -watch mode for development: $ go test -c -o crdtest ./pkg/crdtest # or "make crdtest" $ ./crdtest -crdDir config/crd/standard -watch pkg/crdtest/testdata/valid will apply all yamls in pkg/crdtest/valid folder and continue watching the changes to the *.yaml files in the folder. When a file is changed, it will load it into an API server and print the result.
1 parent 62b446c commit fe915e8

File tree

9 files changed

+486
-7
lines changed

9 files changed

+486
-7
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ bin/
44
vendor/
55
site/
66
.DS_Store
7+
/crdtest

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ fmt: ## Run go fmt against code.
3838
vet: ## Run go vet against code.
3939
go vet ./...
4040

41+
.PHONY: test
42+
test: ## Run go test
43+
go test ./apis/...
44+
go test ./pkg/...
45+
4146
.PHONY: generate
4247
generate: ## Generate the code from the API definitions.
4348
./hack/update-codegen.sh
@@ -92,3 +97,7 @@ local-docs:
9297
.PHONY: build-install-yaml ## Build the install YAML.
9398
build-install-yaml:
9499
./hack/build-install-yaml.sh
100+
101+
.PHONY: crdtest # use go to check build freshness
102+
crdtest: ## Build the crdtest executable
103+
go test -c ./pkg/crdtest -o crdtest

go.mod

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,25 @@ go 1.24.0
55
require (
66
github.com/ahmetb/gen-crd-api-reference-docs v0.3.0
77
github.com/stretchr/testify v1.10.0
8-
k8s.io/api v0.34.0
9-
k8s.io/apiextensions-apiserver v0.34.0
10-
k8s.io/apimachinery v0.34.0
11-
k8s.io/client-go v0.34.0
12-
k8s.io/code-generator v0.34.0
8+
k8s.io/api v0.34.1
9+
k8s.io/apiextensions-apiserver v0.34.1
10+
k8s.io/apimachinery v0.34.1
11+
k8s.io/client-go v0.34.1
12+
k8s.io/code-generator v0.34.1
1313
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
14-
sigs.k8s.io/controller-runtime v0.18.4
14+
sigs.k8s.io/controller-runtime v0.22.2
1515
sigs.k8s.io/controller-tools v0.16.4
1616
sigs.k8s.io/structured-merge-diff/v4 v4.6.0
1717
sigs.k8s.io/yaml v1.6.0
1818
)
1919

2020
require (
21+
github.com/beorn7/perks v1.0.1 // indirect
22+
github.com/cespare/xxhash/v2 v2.3.0 // indirect
2123
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
2224
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
2325
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
24-
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
26+
github.com/evanphx/json-patch/v5 v5.9.11 // indirect
2527
github.com/fatih/color v1.17.0 // indirect
2628
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
2729
github.com/go-logr/logr v1.4.2 // indirect
@@ -47,6 +49,10 @@ require (
4749
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
4850
github.com/pkg/errors v0.9.1 // indirect
4951
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
52+
github.com/prometheus/client_golang v1.22.0 // indirect
53+
github.com/prometheus/client_model v0.6.1 // indirect
54+
github.com/prometheus/common v0.62.0 // indirect
55+
github.com/prometheus/procfs v0.15.1 // indirect
5056
github.com/russross/blackfriday/v2 v2.1.0 // indirect
5157
github.com/spf13/cobra v1.9.1 // indirect
5258
github.com/spf13/pflag v1.0.6 // indirect

go.sum

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ github.com/ahmetb/gen-crd-api-reference-docs v0.3.0 h1:+XfOU14S4bGuwyvCijJwhhBIj
22
github.com/ahmetb/gen-crd-api-reference-docs v0.3.0/go.mod h1:TdjdkYhlOifCQWPs1UdTma97kQQMozf5h26hTuG70u8=
33
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
44
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
5+
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
6+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
7+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
8+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
59
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
610
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
711
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -14,6 +18,8 @@ github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCv
1418
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
1519
github.com/evanphx/json-patch/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
1620
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
21+
github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU=
22+
github.com/evanphx/json-patch/v5 v5.9.11/go.mod h1:3j+LviiESTElxA4p3EMKAB9HXj3/XEtnUf6OZxqIQTM=
1723
github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4=
1824
github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI=
1925
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
@@ -95,14 +101,24 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
95101
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
96102
github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
97103
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
104+
github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
98105
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
99106
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
107+
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
100108
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
101109
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
102110
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
103111
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
104112
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
105113
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
114+
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
115+
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
116+
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
117+
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
118+
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
119+
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
120+
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
121+
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
106122
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
107123
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
108124
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
@@ -207,14 +223,24 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
207223
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
208224
k8s.io/api v0.34.0 h1:L+JtP2wDbEYPUeNGbeSa/5GwFtIA662EmT2YSLOkAVE=
209225
k8s.io/api v0.34.0/go.mod h1:YzgkIzOOlhl9uwWCZNqpw6RJy9L2FK4dlJeayUoydug=
226+
k8s.io/api v0.34.1 h1:jC+153630BMdlFukegoEL8E/yT7aLyQkIVuwhmwDgJM=
227+
k8s.io/api v0.34.1/go.mod h1:SB80FxFtXn5/gwzCoN6QCtPD7Vbu5w2n1S0J5gFfTYk=
210228
k8s.io/apiextensions-apiserver v0.34.0 h1:B3hiB32jV7BcyKcMU5fDaDxk882YrJ1KU+ZSkA9Qxoc=
211229
k8s.io/apiextensions-apiserver v0.34.0/go.mod h1:hLI4GxE1BDBy9adJKxUxCEHBGZtGfIg98Q+JmTD7+g0=
230+
k8s.io/apiextensions-apiserver v0.34.1 h1:NNPBva8FNAPt1iSVwIE0FsdrVriRXMsaWFMqJbII2CI=
231+
k8s.io/apiextensions-apiserver v0.34.1/go.mod h1:hP9Rld3zF5Ay2Of3BeEpLAToP+l4s5UlxiHfqRaRcMc=
212232
k8s.io/apimachinery v0.34.0 h1:eR1WO5fo0HyoQZt1wdISpFDffnWOvFLOOeJ7MgIv4z0=
213233
k8s.io/apimachinery v0.34.0/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
234+
k8s.io/apimachinery v0.34.1 h1:dTlxFls/eikpJxmAC7MVE8oOeP1zryV7iRyIjB0gky4=
235+
k8s.io/apimachinery v0.34.1/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
214236
k8s.io/client-go v0.34.0 h1:YoWv5r7bsBfb0Hs2jh8SOvFbKzzxyNo0nSb0zC19KZo=
215237
k8s.io/client-go v0.34.0/go.mod h1:ozgMnEKXkRjeMvBZdV1AijMHLTh3pbACPvK7zFR+QQY=
238+
k8s.io/client-go v0.34.1 h1:ZUPJKgXsnKwVwmKKdPfw4tB58+7/Ik3CrjOEhsiZ7mY=
239+
k8s.io/client-go v0.34.1/go.mod h1:kA8v0FP+tk6sZA0yKLRG67LWjqufAoSHA2xVGKw9Of8=
216240
k8s.io/code-generator v0.34.0 h1:Ze2i1QsvUprIlX3oHiGv09BFQRLCz+StA8qKwwFzees=
217241
k8s.io/code-generator v0.34.0/go.mod h1:Py2+4w2HXItL8CGhks8uI/wS3Y93wPKO/9mBQUYNua0=
242+
k8s.io/code-generator v0.34.1 h1:WpphT26E+j7tEgIUfFr5WfbJrktCGzB3JoJH9149xYc=
243+
k8s.io/code-generator v0.34.1/go.mod h1:DeWjekbDnJWRwpw3s0Jat87c+e0TgkxoR4ar608yqvg=
218244
k8s.io/gengo v0.0.0-20201203183100-97869a43a9d9/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
219245
k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01 h1:pWEwq4Asjm4vjW7vcsmijwBhOr1/shsbSYiWXmNGlks=
220246
k8s.io/gengo v0.0.0-20230829151522-9cce18d56c01/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
@@ -231,6 +257,8 @@ k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8
231257
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
232258
sigs.k8s.io/controller-runtime v0.18.4 h1:87+guW1zhvuPLh1PHybKdYFLU0YJp4FhJRmiHvm5BZw=
233259
sigs.k8s.io/controller-runtime v0.18.4/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg=
260+
sigs.k8s.io/controller-runtime v0.22.2 h1:cK2l8BGWsSWkXz09tcS4rJh95iOLney5eawcK5A33r4=
261+
sigs.k8s.io/controller-runtime v0.22.2/go.mod h1:+QX1XUpTXN4mLoblf4tqr5CQcyHPAki2HLXqQMY6vh8=
234262
sigs.k8s.io/controller-tools v0.16.4 h1:VXmar78eDXbx1by/H09ikEq1hiq3bqInxuV3lMr3GmQ=
235263
sigs.k8s.io/controller-tools v0.16.4/go.mod h1:kcsZyYMXiOFuBhofSPtkB90zTSxVRxVVyvtKQcx3q1A=
236264
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=

pkg/crdtest/crd_test.go

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
Copyright 2025 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
14+
package crdtest
15+
16+
import (
17+
"embed"
18+
"path"
19+
20+
"context"
21+
"strings"
22+
"testing"
23+
24+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
25+
"k8s.io/apimachinery/pkg/util/yaml"
26+
)
27+
28+
var (
29+
//go:embed testdata/*/*
30+
testData embed.FS
31+
)
32+
33+
const testDataDir = "testdata"
34+
35+
// loadYAML from the given embedded test case.
36+
func loadYAML(fs embed.FS, name string) (*unstructured.Unstructured, string, error) {
37+
b, err := fs.ReadFile(name)
38+
if err != nil {
39+
return nil, "", err
40+
}
41+
obj := &unstructured.Unstructured{}
42+
dec := yaml.NewYAMLOrJSONDecoder(strings.NewReader(string(b)), 4096)
43+
if err := dec.Decode(&obj); err != nil {
44+
return nil, "", err
45+
}
46+
return obj, string(b), nil
47+
}
48+
49+
func TestValid(t *testing.T) {
50+
const dir = "valid"
51+
52+
entries, err := testData.ReadDir(path.Join(testDataDir, dir))
53+
if err != nil {
54+
t.Fatalf("ReadDir() = %v, want nil", err)
55+
}
56+
for _, e := range entries {
57+
filePath := path.Join(testDataDir, dir, e.Name())
58+
obj, text, err := loadYAML(testData, filePath)
59+
if err != nil {
60+
t.Fatalf("loadYAML(%s) = %v, want nil\nYAML was:\n%s", filePath, err, text)
61+
}
62+
t.Run(obj.GetName(), func(t *testing.T) {
63+
if err := globals.k8sClient.Create(context.Background(), obj); err != nil {
64+
t.Fatalf("Create() = %v, want nil\nYAML was:\n%s", err, text)
65+
}
66+
if err := globals.k8sClient.Delete(context.Background(), obj); err != nil {
67+
t.Fatalf("Delete() = %v, want nil\nYAML was:\n%s", err, text)
68+
}
69+
})
70+
}
71+
}
72+
73+
func TestInvalid(t *testing.T) {
74+
const dir = "invalid"
75+
76+
entries, err := testData.ReadDir(path.Join(testDataDir, dir))
77+
if err != nil {
78+
t.Fatalf("ReadDir() = %v, want nil", err)
79+
}
80+
for _, e := range entries {
81+
filePath := path.Join(testDataDir, dir, e.Name())
82+
obj, text, err := loadYAML(testData, filePath)
83+
84+
if err != nil {
85+
t.Fatalf("loadYAML(%s) = %v, want nil\nYAML was:\n%s", filePath, err, text)
86+
}
87+
t.Run(obj.GetName(), func(t *testing.T) {
88+
err := globals.k8sClient.Create(context.Background(), obj)
89+
t.Logf("Create() = %v", err)
90+
if err == nil {
91+
t.Fatalf("Create() = nil, want error\nYAML was:\n%s", text)
92+
}
93+
})
94+
}
95+
}

pkg/crdtest/doc.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package crdtest tests the current CRDs against example valid and invalid CRDs.
2+
package crdtest

0 commit comments

Comments
 (0)