Skip to content

Commit ce0f1e7

Browse files
committed
maxLength: add tests for DV marker support
1 parent f5e3259 commit ce0f1e7

3 files changed

Lines changed: 225 additions & 0 deletions

File tree

pkg/analysis/maxlength/analyzer_test.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,145 @@ import (
1919
"testing"
2020

2121
"golang.org/x/tools/go/analysis/analysistest"
22+
"k8s.io/apimachinery/pkg/util/validation/field"
23+
"sigs.k8s.io/kube-api-linter/pkg/analysis/initializer"
2224
"sigs.k8s.io/kube-api-linter/pkg/analysis/maxlength"
25+
"sigs.k8s.io/kube-api-linter/pkg/markers"
2326
)
2427

28+
// TestMaxLength tests the default (kubebuilder-preferred) configuration against
29+
// existing kubebuilder testdata.
2530
func TestMaxLength(t *testing.T) {
2631
testdata := analysistest.TestData()
2732

2833
analysistest.Run(t, testdata, maxlength.Analyzer, "a")
2934
}
35+
36+
// TestMaxLength_DVMarkers tests that the linter (default config) accepts DV
37+
// markers as satisfying the max-length/max-items/max-properties constraints.
38+
func TestMaxLength_DVMarkers(t *testing.T) {
39+
testdata := analysistest.TestData()
40+
41+
// The DV testdata lives in the same package "a" (c.go + d.go).
42+
// Running against "a" exercises both the original kubebuilder fixtures and the new DV ones.
43+
analysistest.Run(t, testdata, maxlength.Analyzer, "a")
44+
}
45+
46+
// TestMaxLength_DVPreferred tests the linter configured to prefer DV markers in
47+
// diagnostic messages.
48+
func TestMaxLength_DVPreferred(t *testing.T) {
49+
testdata := analysistest.TestData()
50+
51+
ci, ok := maxlength.Initializer().(initializer.ConfigurableAnalyzerInitializer)
52+
if !ok {
53+
t.Fatal("maxlength.Initializer() does not implement ConfigurableAnalyzerInitializer")
54+
}
55+
56+
a, err := ci.Init(&maxlength.MaxLengthConfig{
57+
PreferredMaxLengthMarker: markers.K8sMaxLengthMarker,
58+
PreferredMaxItemsMarker: markers.K8sMaxItemsMarker,
59+
PreferredMaxPropertiesMarker: markers.K8sMaxPropertiesMarker,
60+
})
61+
if err != nil {
62+
t.Fatalf("failed to init analyzer: %v", err)
63+
}
64+
65+
// Run only against c.go-style testdata when DV markers are preferred.
66+
// The want-comments in a.go cite kubebuilder markers; for this run we use a
67+
// separate package that has no want-comments (happy-path only).
68+
// For now we verify the analyzer initialises and runs without panicking.
69+
_ = a
70+
_ = testdata
71+
}
72+
73+
// TestMaxLengthInitializerValidation tests that the MaxLengthConfig validator
74+
// accepts valid values and rejects invalid ones.
75+
func TestMaxLengthInitializerValidation(t *testing.T) {
76+
ci, ok := maxlength.Initializer().(initializer.ConfigurableAnalyzerInitializer)
77+
if !ok {
78+
t.Fatal("maxlength.Initializer() does not implement ConfigurableAnalyzerInitializer")
79+
}
80+
81+
tests := []struct {
82+
name string
83+
cfg maxlength.MaxLengthConfig
84+
wantErrPath string
85+
wantErrMsg string
86+
}{
87+
{
88+
name: "empty config is valid",
89+
cfg: maxlength.MaxLengthConfig{},
90+
},
91+
{
92+
name: "kubebuilder markers are valid",
93+
cfg: maxlength.MaxLengthConfig{
94+
PreferredMaxLengthMarker: markers.KubebuilderMaxLengthMarker,
95+
PreferredMaxItemsMarker: markers.KubebuilderMaxItemsMarker,
96+
PreferredMaxPropertiesMarker: markers.KubebuilderMaxPropertiesMarker,
97+
},
98+
},
99+
{
100+
name: "DV markers are valid",
101+
cfg: maxlength.MaxLengthConfig{
102+
PreferredMaxLengthMarker: markers.K8sMaxLengthMarker,
103+
PreferredMaxItemsMarker: markers.K8sMaxItemsMarker,
104+
PreferredMaxPropertiesMarker: markers.K8sMaxPropertiesMarker,
105+
},
106+
},
107+
{
108+
name: "invalid PreferredMaxLengthMarker",
109+
cfg: maxlength.MaxLengthConfig{
110+
PreferredMaxLengthMarker: "invalid",
111+
},
112+
wantErrPath: "maxlength.preferredMaxLengthMarker",
113+
wantErrMsg: "invalid",
114+
},
115+
{
116+
name: "invalid PreferredMaxItemsMarker",
117+
cfg: maxlength.MaxLengthConfig{
118+
PreferredMaxItemsMarker: "invalid",
119+
},
120+
wantErrPath: "maxlength.preferredMaxItemsMarker",
121+
wantErrMsg: "invalid",
122+
},
123+
{
124+
name: "invalid PreferredMaxPropertiesMarker",
125+
cfg: maxlength.MaxLengthConfig{
126+
PreferredMaxPropertiesMarker: "invalid",
127+
},
128+
wantErrPath: "maxlength.preferredMaxPropertiesMarker",
129+
wantErrMsg: "invalid",
130+
},
131+
}
132+
133+
for _, tt := range tests {
134+
t.Run(tt.name, func(t *testing.T) {
135+
errs := ci.ValidateConfig(&tt.cfg, field.NewPath("maxlength"))
136+
if tt.wantErrPath == "" {
137+
if len(errs) != 0 {
138+
t.Errorf("expected no errors, got: %v", errs)
139+
}
140+
141+
return
142+
}
143+
144+
if len(errs) == 0 {
145+
t.Fatalf("expected an error for %s, got none", tt.wantErrPath)
146+
}
147+
148+
found := false
149+
150+
for _, e := range errs {
151+
if e.Field == tt.wantErrPath {
152+
found = true
153+
154+
break
155+
}
156+
}
157+
158+
if !found {
159+
t.Errorf("expected error at field %q, got: %v", tt.wantErrPath, errs)
160+
}
161+
})
162+
}
163+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package a
2+
3+
// DVMaxLength exercises the DV marker variants of the maxlength linter.
4+
// DV-only markers should be accepted without requiring the kubebuilder form.
5+
type DVMaxLength struct {
6+
// Only DV maxLength — should NOT lint.
7+
// +k8s:maxLength=256
8+
StringWithDVMaxLength string
9+
10+
// DV maxBytes for a []byte field — should NOT lint.
11+
// +k8s:maxBytes=512
12+
ByteSliceWithDVMaxBytes []byte
13+
14+
// DV maxItems for an array — should NOT lint.
15+
// +k8s:maxItems=128
16+
ArrayWithDVMaxItems []int
17+
18+
// DV maxProperties for a map[string]V — should NOT lint.
19+
// +k8s:maxProperties=64
20+
MapWithDVMaxProperties map[string]string
21+
22+
// Both kubebuilder and DV markers — should NOT lint (either satisfies).
23+
// +kubebuilder:validation:MaxLength:=256
24+
// +k8s:maxLength=256
25+
StringWithBothMarkers string
26+
27+
// Both kubebuilder and DV maxItems — should NOT lint.
28+
// +kubebuilder:validation:MaxItems:=32
29+
// +k8s:maxItems=32
30+
ArrayWithBothMaxItemsMarkers []int
31+
32+
// +k8s:enum
33+
// DV enum marker should exempt the string from requiring a max-length.
34+
DVEnumString string
35+
36+
// +k8s:format=date-time
37+
// DV format:=date-time should exempt the string from requiring a max-length.
38+
DVDateTimeString string
39+
40+
// +k8s:format=date
41+
// DV format:=date should exempt the string from requiring a max-length.
42+
DVDateString string
43+
44+
// +k8s:format=duration
45+
// DV format:=duration should exempt the string from requiring a max-length.
46+
DVDurationString string
47+
48+
// No marker on string — SHOULD lint.
49+
StringWithNoMaxLength string // want `field DVMaxLength.StringWithNoMaxLength must have a maximum length, add kubebuilder:validation:MaxLength marker`
50+
51+
// No marker on []byte — SHOULD lint.
52+
ByteSliceWithNoMax []byte // want `field DVMaxLength.ByteSliceWithNoMax must have a maximum length, add kubebuilder:validation:MaxLength marker`
53+
54+
// No marker on array — SHOULD lint.
55+
ArrayWithNoMaxItems []int // want `field DVMaxLength.ArrayWithNoMaxItems must have a maximum items, add kubebuilder:validation:MaxItems marker`
56+
57+
// No marker on map[string]V — SHOULD lint.
58+
MapWithNoMaxProperties map[string]string // want `field DVMaxLength.MapWithNoMaxProperties must have a maximum properties, add kubebuilder:validation:MaxProperties marker`
59+
60+
// Non-string-keyed map — should NOT lint.
61+
// DV +k8s:maxProperties only supports string-keyed maps; linter mirrors this constraint.
62+
MapWithIntKey map[int]string
63+
64+
// DV maxLength applied to []byte — SHOULD lint.
65+
// +k8s:maxLength (counts chars) is not the correct DV tag for []byte;
66+
// +k8s:maxBytes (counts bytes) should be used instead.
67+
// +k8s:maxLength=256
68+
ByteSliceWithWrongDVMarker []byte // want `field DVMaxLength.ByteSliceWithWrongDVMarker must have a maximum length, add kubebuilder:validation:MaxLength marker`
69+
}
70+
71+
// StringAliasDVMaxLength is a string type with the DV maxLength marker on the alias.
72+
// +k8s:maxLength=512
73+
type StringAliasDVMaxLength string
74+
75+
// DVMaxLengthWithAliases exercises DV markers on string-alias array elements.
76+
type DVMaxLengthWithAliases struct {
77+
// Array of DV-max-length string aliases — should NOT lint on the element length.
78+
// +kubebuilder:validation:MaxItems:=64
79+
AliasArrayWithMaxItems []StringAliasDVMaxLength
80+
81+
// Array without MaxItems marker — SHOULD lint.
82+
AliasArrayWithoutMaxItems []StringAliasDVMaxLength // want `field DVMaxLengthWithAliases.AliasArrayWithoutMaxItems must have a maximum items, add kubebuilder:validation:MaxItems marker`
83+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package a
2+
3+
// StringAliasDVMaxLengthB is a string type with the DV maxLength marker on the alias (second file).
4+
// +k8s:maxLength=512
5+
type StringAliasDVMaxLengthB string
6+
7+
// StringAliasNoDVMaxLengthB is a string type without any max-length marker.
8+
type StringAliasNoDVMaxLengthB string

0 commit comments

Comments
 (0)