Skip to content

Commit e660c89

Browse files
committed
metrics: add integration test
1 parent f645a68 commit e660c89

8 files changed

+504
-0
lines changed
+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
Copyright 2023 The Kubernetes Authors All rights reserved.
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+
package metrics
17+
18+
import (
19+
"bytes"
20+
"io"
21+
"os"
22+
"path"
23+
"testing"
24+
25+
"github.com/google/go-cmp/cmp"
26+
"sigs.k8s.io/controller-tools/pkg/genall"
27+
"sigs.k8s.io/controller-tools/pkg/loader"
28+
"sigs.k8s.io/controller-tools/pkg/markers"
29+
)
30+
31+
func Test_Generate(t *testing.T) {
32+
cwd, err := os.Getwd()
33+
if err != nil {
34+
t.Error(err)
35+
}
36+
37+
optionsRegistry := &markers.Registry{}
38+
39+
metricGenerator := Generator{}
40+
if err := metricGenerator.RegisterMarkers(optionsRegistry); err != nil {
41+
t.Error(err)
42+
}
43+
44+
out := &outputRule{
45+
buf: &bytes.Buffer{},
46+
}
47+
48+
// Load the passed packages as roots.
49+
roots, err := loader.LoadRoots(path.Join(cwd, "testdata", "..."))
50+
if err != nil {
51+
t.Errorf("loading packages %v", err)
52+
}
53+
54+
gen := Generator{}
55+
56+
generationContext := &genall.GenerationContext{
57+
Collector: &markers.Collector{Registry: optionsRegistry},
58+
Roots: roots,
59+
Checker: &loader.TypeChecker{},
60+
OutputRule: out,
61+
}
62+
63+
t.Log("Trying to generate a custom resource configuration from the loaded packages")
64+
65+
if err := gen.Generate(generationContext); err != nil {
66+
t.Error(err)
67+
}
68+
output := out.buf.String()
69+
70+
t.Log("Comparing output to testdata to check for regressions")
71+
72+
expectedFile, err := os.ReadFile(path.Clean(path.Join(cwd, "testdata", "foo-config.yaml")))
73+
if err != nil {
74+
t.Error(err)
75+
}
76+
77+
diff := cmp.Diff(string(expectedFile), output)
78+
if diff != "" {
79+
t.Log("output:")
80+
t.Log(output)
81+
t.Log("diff:")
82+
t.Log(diff)
83+
t.Log("Expected output to match file `testdata/foo-config.yaml` but it does not.")
84+
t.Log("If the change is intended, use `go generate ./pkg/customresourcestate/generate/generator/testdata` to regenerate the `testdata/foo-config.yaml` file.")
85+
t.Error("Detected a diff between the output of the integration test and the file `testdata/foo-config.yaml`.")
86+
}
87+
}
88+
89+
type outputRule struct {
90+
buf *bytes.Buffer
91+
}
92+
93+
func (o *outputRule) Open(_ *loader.Package, _ string) (io.WriteCloser, error) {
94+
return nopCloser{o.buf}, nil
95+
}
96+
97+
type nopCloser struct {
98+
io.Writer
99+
}
100+
101+
func (n nopCloser) Close() error {
102+
return nil
103+
}

pkg/metrics/testdata/README.md

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Testdata for generator tests
2+
3+
The files in this directory are used for testing the `kube-state-metrics generate` command and to provide an example.
4+
5+
## foo-config.yaml
6+
7+
This file is used in the test at [generate_integration_test.go](../generate_integration_test.go) to verify that the resulting configuration does not change during changes in the codebase.
8+
9+
If there are intended changes this file needs to get regenerated to make the test succeed again.
10+
This could be done via:
11+
12+
```sh
13+
go run generate \
14+
./pkg/customresourcestate/generate/generator/testdata/ \
15+
> ./pkg/customresourcestate/generate/generator/testdata/foo-config.yaml
16+
```
17+
18+
Or by using the go:generate marker inside [foo_types.go](foo_types.go):
19+
20+
```sh
21+
go generate ./pkg/customresourcestate/generate/generator/testdata/
22+
```
23+
24+
## Example files: foo-cr-example.yaml and foo-cr-example-metrics.txt
25+
26+
There is also an example CR ([foo-cr-example.yaml](foo-cr-example.yaml)) and resulting example metrics ([foo-cr-example-metrics.txt](foo-cr-example-metrics.txt)).
27+
28+
The example metrics file got created by:
29+
30+
1. Generating a CustomResourceDefinition yaml by using [controller-gen](https://github.com/kubernetes-sigs/kubebuilder/blob/master/docs/book/src/reference/controller-gen.md):
31+
32+
```sh
33+
controller-gen crd paths=./pkg/customresourcestate/generate/generator/testdata/ output:dir=./pkg/customresourcestate/generate/generator/testdata/
34+
```
35+
36+
2. Creating a cluster using [kind](https://kind.sigs.k8s.io/)
37+
3. Applying the CRD and example CR to the cluster:
38+
39+
```sh
40+
kubectl apply -f /pkg/customresourcestate/generate/generator/testdata/bar.example.com_foos.yaml
41+
kubectl apply -f /pkg/customresourcestate/generate/generator/testdata/foo-cr-example.yaml
42+
```
43+
44+
4. Running kube-state-metrics with the provided configuration file:
45+
46+
```sh
47+
go run ./ --kubeconfig $HOME/.kube/config --custom-resource-state-only \
48+
--custom-resource-state-config-file pkg/customresourcestate/generate/generator/testdata/foo-config.yaml
49+
```
50+
51+
5. Querying the metrics endpoint in a second terminal:
52+
53+
```sh
54+
curl localhost:8080/metrics > ./pkg/customresourcestate/generate/generator/testdata/foo-cr-example-metrics.txt
55+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
---
2+
apiVersion: apiextensions.k8s.io/v1
3+
kind: CustomResourceDefinition
4+
metadata:
5+
annotations:
6+
controller-gen.kubebuilder.io/version: v0.8.0
7+
creationTimestamp: null
8+
name: foos.bar.example.com
9+
spec:
10+
group: bar.example.com
11+
names:
12+
kind: Foo
13+
listKind: FooList
14+
plural: foos
15+
singular: foo
16+
scope: Namespaced
17+
versions:
18+
- name: foo
19+
schema:
20+
openAPIV3Schema:
21+
description: Foo is a test object.
22+
properties:
23+
apiVersion:
24+
description: 'APIVersion defines the versioned schema of this representation
25+
of an object. Servers should convert recognized schemas to the latest
26+
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
27+
type: string
28+
kind:
29+
description: 'Kind is a string value representing the REST resource this
30+
object represents. Servers may infer this from the endpoint the client
31+
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
32+
type: string
33+
metadata:
34+
type: object
35+
spec:
36+
description: Spec comments SHOULD appear in the CRD spec
37+
properties:
38+
someString:
39+
description: SomeString is a string.
40+
type: string
41+
required:
42+
- someString
43+
type: object
44+
status:
45+
description: Status comments SHOULD appear in the CRD spec
46+
properties:
47+
conditions:
48+
items:
49+
description: Condition is a test condition.
50+
properties:
51+
lastTransitionTime:
52+
description: LastTransitionTime of condition.
53+
format: date-time
54+
type: string
55+
status:
56+
description: Status of condition.
57+
type: string
58+
type:
59+
description: Type of condition.
60+
type: string
61+
required:
62+
- lastTransitionTime
63+
- status
64+
- type
65+
type: object
66+
type: array
67+
type: object
68+
type: object
69+
served: true
70+
storage: true
71+
status:
72+
acceptedNames:
73+
kind: ""
74+
plural: ""
75+
conditions: []
76+
storedVersions: []

pkg/metrics/testdata/foo-config.yaml

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
---
2+
kind: CustomResourceStateMetrics
3+
spec:
4+
resources:
5+
- errorLogV: 0
6+
groupVersionKind:
7+
group: bar.example.com
8+
kind: Foo
9+
version: foo
10+
labelsFromPath:
11+
cluster_name:
12+
- metadata
13+
- labels
14+
- cluster.x-k8s.io/cluster-name
15+
name:
16+
- metadata
17+
- name
18+
metricNamePrefix: foo
19+
metrics:
20+
- each:
21+
gauge:
22+
labelFromKey: ""
23+
nilIsZero: false
24+
path:
25+
- metadata
26+
- creationTimestamp
27+
valueFrom: null
28+
type: Gauge
29+
help: Unix creation timestamp.
30+
name: created
31+
- each:
32+
info:
33+
labelFromKey: ""
34+
labelsFromPath:
35+
owner_is_controller:
36+
- controller
37+
owner_kind:
38+
- kind
39+
owner_name:
40+
- name
41+
owner_uid:
42+
- uid
43+
path:
44+
- metadata
45+
- ownerReferences
46+
type: Info
47+
help: Owner references.
48+
name: owner
49+
- each:
50+
stateSet:
51+
labelName: status
52+
labelsFromPath:
53+
type:
54+
- type
55+
list:
56+
- "True"
57+
- "False"
58+
- Unknown
59+
path:
60+
- status
61+
- conditions
62+
valueFrom:
63+
- status
64+
type: StateSet
65+
help: The condition of a foo.
66+
name: status_condition
67+
- each:
68+
gauge:
69+
labelFromKey: ""
70+
labelsFromPath:
71+
status:
72+
- status
73+
type:
74+
- type
75+
nilIsZero: false
76+
path:
77+
- status
78+
- conditions
79+
valueFrom:
80+
- lastTransitionTime
81+
type: Gauge
82+
help: The condition last transition time of a foo.
83+
name: status_condition_last_transition_time
84+
resourcePlural: ""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# HELP foo_created Unix creation timestamp.
2+
# TYPE foo_created gauge
3+
foo_created{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar"} 1.697543739e+09
4+
# HELP foo_owner Owner references.
5+
# TYPE foo_owner info
6+
foo_owner{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar",owner_is_controller="true",owner_kind="foo",owner_name="foo",owner_uid="someuid"} 1
7+
# HELP foo_status_condition The condition of a foo.
8+
# TYPE foo_status_condition stateset
9+
foo_status_condition{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar",status="False",type="AnotherType"} 1
10+
foo_status_condition{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar",status="False",type="SomeType"} 0
11+
foo_status_condition{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar",status="True",type="AnotherType"} 0
12+
foo_status_condition{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar",status="True",type="SomeType"} 1
13+
foo_status_condition{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar",status="Unknown",type="AnotherType"} 0
14+
foo_status_condition{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar",status="Unknown",type="SomeType"} 0
15+
# HELP foo_status_condition_last_transition_time The condition last transition time of a foo.
16+
# TYPE foo_status_condition_last_transition_time gauge
17+
foo_status_condition_last_transition_time{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar",status="False",type="AnotherType"} 1.697119142e+09
18+
foo_status_condition_last_transition_time{customresource_group="bar.example.com",customresource_kind="Foo",customresource_version="foo",name="bar",status="True",type="SomeType"} 1.697119142e+09
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
apiVersion: bar.example.com/foo
3+
kind: Foo
4+
metadata:
5+
name: bar
6+
ownerReferences:
7+
- apiVersion: v1
8+
kind: foo
9+
controller: true
10+
name: foo
11+
uid: someuid
12+
spec:
13+
someString: test
14+
status:
15+
conditions:
16+
- lastTransitionTime: "2023-10-12T13:59:02Z"
17+
status: "True"
18+
type: SomeType
19+
- lastTransitionTime: "2023-10-12T13:59:02Z"
20+
status: "False"
21+
type: AnotherType

0 commit comments

Comments
 (0)