Skip to content

Commit 004da15

Browse files
committed
bump tests
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
1 parent 670619b commit 004da15

34 files changed

Lines changed: 1619 additions & 2069 deletions

common-hooks/copy-custom-certificate/hook_test.go

Lines changed: 61 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -17,82 +17,78 @@ limitations under the License.
1717
package copycustomcertificate_test
1818

1919
import (
20-
"bytes"
2120
"context"
22-
"encoding/json"
2321
"testing"
2422

2523
"github.com/stretchr/testify/assert"
24+
"github.com/stretchr/testify/require"
2625

2726
copycustomcertificate "github.com/deckhouse/module-sdk/common-hooks/copy-custom-certificate"
2827
tlscertificate "github.com/deckhouse/module-sdk/common-hooks/tls-certificate"
2928
"github.com/deckhouse/module-sdk/pkg/certificate"
30-
"github.com/deckhouse/module-sdk/pkg/jq"
29+
"github.com/deckhouse/module-sdk/testing/helpers"
3130
)
3231

33-
func Test_JQFilterApplyCertificateSecret(t *testing.T) {
34-
t.Run("apply tls", func(t *testing.T) {
35-
const rawSecret = `
36-
{
37-
"apiVersion": "v1",
38-
"data": {
39-
"ca.crt": "c29tZS1jYQ==",
40-
"tls.crt": "c29tZS1jcnQ=",
41-
"tls.key": "c29tZS1rZXk="
42-
},
43-
"kind": "Secret",
44-
"metadata": {
45-
"name": "some-cert",
46-
"namespace": "some-ns"
47-
},
48-
"type": "kubernetes.io/tls"
49-
}`
50-
51-
q, err := jq.NewQuery(copycustomcertificate.JQFilterCustomCertificate)
52-
assert.NoError(t, err)
53-
54-
res, err := q.FilterStringObject(context.Background(), rawSecret)
55-
assert.NoError(t, err)
56-
57-
cert := new(certificate.Certificate)
58-
err = json.NewDecoder(bytes.NewBufferString(res.String())).Decode(cert)
59-
assert.NoError(t, err)
60-
61-
assert.Equal(t, "some-key", string(cert.Key))
62-
assert.Equal(t, "some-crt", string(cert.Cert))
63-
assert.Equal(t, "some-ca", string(cert.CA))
64-
assert.Equal(t, "some-cert", cert.Name)
65-
})
66-
67-
t.Run("apply tls from client", func(t *testing.T) {
68-
const rawSecret = `
69-
{
70-
"apiVersion": "v1",
71-
"data": {
72-
"ca.crt": "c29tZS1jYQ==",
73-
"client.crt": "c29tZS1jcnQ=",
74-
"client.key": "c29tZS1rZXk="
75-
},
76-
"kind": "Secret",
77-
"metadata": {
78-
"name": "some-cert",
79-
"namespace": "some-ns"
80-
},
81-
"type": "kubernetes.io/tls"
82-
}`
83-
84-
q, err := jq.NewQuery(tlscertificate.JQFilterApplyCertificateSecret)
85-
assert.NoError(t, err)
32+
// tlsSecret is the canonical TLS-typed kubernetes Secret payload used by
33+
// the JQ filters. The values are base64-encoded so the filter can decode
34+
// them back into "some-key", "some-crt", etc.
35+
const tlsSecret = `{
36+
"apiVersion": "v1",
37+
"data": {
38+
"ca.crt": "c29tZS1jYQ==",
39+
"tls.crt": "c29tZS1jcnQ=",
40+
"tls.key": "c29tZS1rZXk="
41+
},
42+
"kind": "Secret",
43+
"metadata": {
44+
"name": "some-cert",
45+
"namespace": "some-ns"
46+
},
47+
"type": "kubernetes.io/tls"
48+
}`
49+
50+
const clientSecret = `{
51+
"apiVersion": "v1",
52+
"data": {
53+
"ca.crt": "c29tZS1jYQ==",
54+
"client.crt": "c29tZS1jcnQ=",
55+
"client.key": "c29tZS1rZXk="
56+
},
57+
"kind": "Secret",
58+
"metadata": {
59+
"name": "some-cert",
60+
"namespace": "some-ns"
61+
},
62+
"type": "kubernetes.io/tls"
63+
}`
64+
65+
func TestJQFilterCustomCertificate_ParsesTLSSecret(t *testing.T) {
66+
cert := new(certificate.Certificate)
67+
68+
require.NoError(t, helpers.JQRunOnString(
69+
context.Background(),
70+
copycustomcertificate.JQFilterCustomCertificate,
71+
tlsSecret,
72+
cert,
73+
))
74+
75+
assert.Equal(t, "some-cert", cert.Name)
76+
assert.Equal(t, "some-key", string(cert.Key))
77+
assert.Equal(t, "some-crt", string(cert.Cert))
78+
assert.Equal(t, "some-ca", string(cert.CA))
79+
}
8680

87-
res, err := q.FilterStringObject(context.Background(), rawSecret)
88-
assert.NoError(t, err)
81+
func TestJQFilterApplyCertificateSecret_ParsesClientCertificate(t *testing.T) {
82+
auth := new(certificate.Certificate)
8983

90-
auth := new(certificate.Certificate)
91-
err = json.NewDecoder(bytes.NewBufferString(res.String())).Decode(auth)
92-
assert.NoError(t, err)
84+
require.NoError(t, helpers.JQRunOnString(
85+
context.Background(),
86+
tlscertificate.JQFilterApplyCertificateSecret,
87+
clientSecret,
88+
auth,
89+
))
9390

94-
assert.Equal(t, "some-key", string(auth.Key))
95-
assert.Equal(t, "some-crt", string(auth.Cert))
96-
assert.Equal(t, "some-cert", auth.Name)
97-
})
91+
assert.Equal(t, "some-cert", auth.Name)
92+
assert.Equal(t, "some-key", string(auth.Key))
93+
assert.Equal(t, "some-crt", string(auth.Cert))
9894
}
Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
/*
2+
Copyright 2025 Flant JSC
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 storageclasschange
18+
19+
import (
20+
"context"
21+
"testing"
22+
23+
"github.com/stretchr/testify/assert"
24+
"github.com/stretchr/testify/require"
25+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
26+
27+
"github.com/deckhouse/module-sdk/pkg"
28+
"github.com/deckhouse/module-sdk/testing/framework"
29+
)
30+
31+
// hookConfigFor mirrors what RegisterHook builds, but without registering
32+
// anything in the global registry. Functional tests use this to feed the
33+
// framework a complete *pkg.HookConfig.
34+
func hookConfigFor(args Args) *pkg.HookConfig {
35+
return &pkg.HookConfig{
36+
OnBeforeHelm: &pkg.OrderedConfig{Order: 1},
37+
Kubernetes: []pkg.KubernetesConfig{
38+
{
39+
Name: "pvcs",
40+
APIVersion: "v1",
41+
Kind: "PersistentVolumeClaim",
42+
NamespaceSelector: &pkg.NamespaceSelector{
43+
NameSelector: &pkg.NameSelector{MatchNames: []string{args.Namespace}},
44+
},
45+
LabelSelector: &metav1.LabelSelector{
46+
MatchLabels: map[string]string{args.LabelSelectorKey: args.LabelSelectorValue},
47+
},
48+
JqFilter: pvcFilter,
49+
},
50+
{
51+
Name: "pods",
52+
APIVersion: "v1",
53+
Kind: "Pod",
54+
NamespaceSelector: &pkg.NamespaceSelector{
55+
NameSelector: &pkg.NameSelector{MatchNames: []string{args.Namespace}},
56+
},
57+
LabelSelector: &metav1.LabelSelector{
58+
MatchLabels: map[string]string{args.LabelSelectorKey: args.LabelSelectorValue},
59+
},
60+
JqFilter: podFilter,
61+
},
62+
{
63+
Name: "storageClasses",
64+
APIVersion: "storage.k8s.io/v1",
65+
Kind: "StorageClass",
66+
JqFilter: storageClassFilter,
67+
},
68+
},
69+
}
70+
}
71+
72+
func newArgs() Args {
73+
return Args{
74+
ModuleName: "myModule",
75+
Namespace: "test-ns",
76+
LabelSelectorKey: "app",
77+
LabelSelectorValue: "data",
78+
ObjectKind: "StatefulSet",
79+
ObjectName: "data-set",
80+
}
81+
}
82+
83+
// TestStorageClassChange_DefaultStorageClassWritesEffectiveValue exercises
84+
// the snapshot pipeline end-to-end: storage classes from the cluster,
85+
// PVCs filtered by the label selector, and the resulting internal value.
86+
func TestStorageClassChange_DefaultStorageClassWritesEffectiveValue(t *testing.T) {
87+
args := newArgs()
88+
89+
const state = `
90+
---
91+
apiVersion: storage.k8s.io/v1
92+
kind: StorageClass
93+
metadata:
94+
name: standard
95+
annotations:
96+
storageclass.kubernetes.io/is-default-class: "true"
97+
---
98+
apiVersion: storage.k8s.io/v1
99+
kind: StorageClass
100+
metadata:
101+
name: fast
102+
`
103+
104+
f := framework.HookExecutionConfigInit(t, hookConfigFor(args), func(ctx context.Context, in *pkg.HookInput) error {
105+
return storageClassChange(ctx, in, args)
106+
}, `{}`, `{}`)
107+
f.KubeStateSet(state)
108+
f.RunHook()
109+
110+
require.NoError(t, f.HookError())
111+
112+
// The hook discovers the default SC and writes it to the internal path.
113+
val := f.ValuesGet("myModule.internal.effectiveStorageClass").String()
114+
assert.Equal(t, "standard", val)
115+
}
116+
117+
// TestStorageClassChange_ConfigOverridesDefault asserts that an explicit
118+
// global.modules.storageClass override beats the cluster default.
119+
func TestStorageClassChange_ConfigOverridesDefault(t *testing.T) {
120+
args := newArgs()
121+
122+
const state = `
123+
---
124+
apiVersion: storage.k8s.io/v1
125+
kind: StorageClass
126+
metadata:
127+
name: standard
128+
annotations:
129+
storageclass.kubernetes.io/is-default-class: "true"
130+
`
131+
132+
const config = `{"global":{"modules":{"storageClass":"premium"}}}`
133+
134+
f := framework.HookExecutionConfigInit(t, hookConfigFor(args), func(ctx context.Context, in *pkg.HookInput) error {
135+
return storageClassChange(ctx, in, args)
136+
}, `{}`, config)
137+
f.KubeStateSet(state)
138+
f.RunHook()
139+
140+
require.NoError(t, f.HookError())
141+
assert.Equal(t, "premium", f.ValuesGet("myModule.internal.effectiveStorageClass").String())
142+
}
143+
144+
// TestStorageClassChange_LabelSelectorScopesPVCs ensures the hook only
145+
// considers PVCs whose labels match the configured selector.
146+
func TestStorageClassChange_LabelSelectorScopesPVCs(t *testing.T) {
147+
args := newArgs()
148+
149+
const state = `
150+
---
151+
apiVersion: storage.k8s.io/v1
152+
kind: StorageClass
153+
metadata:
154+
name: standard
155+
annotations:
156+
storageclass.kubernetes.io/is-default-class: "true"
157+
---
158+
apiVersion: v1
159+
kind: PersistentVolumeClaim
160+
metadata:
161+
name: matching
162+
namespace: test-ns
163+
labels:
164+
app: data
165+
spec:
166+
storageClassName: legacy
167+
---
168+
apiVersion: v1
169+
kind: PersistentVolumeClaim
170+
metadata:
171+
name: irrelevant
172+
namespace: test-ns
173+
labels:
174+
app: other
175+
spec:
176+
storageClassName: ignored
177+
`
178+
179+
f := framework.HookExecutionConfigInit(t, hookConfigFor(args), func(ctx context.Context, in *pkg.HookInput) error {
180+
return storageClassChange(ctx, in, args)
181+
}, `{}`, `{}`)
182+
f.KubeStateSet(state)
183+
f.RunHook()
184+
185+
require.NoError(t, f.HookError())
186+
// The current PVC's storageClassName ("legacy") wins over the default.
187+
assert.Equal(t, "legacy", f.ValuesGet("myModule.internal.effectiveStorageClass").String())
188+
}
189+
190+
// TestStorageClassChange_BeforeHookCheckGate validates that returning false
191+
// from BeforeHookCheck short-circuits the hook (no values, no errors).
192+
func TestStorageClassChange_BeforeHookCheckGate(t *testing.T) {
193+
args := newArgs()
194+
args.BeforeHookCheck = func(_ *pkg.HookInput) bool { return false }
195+
196+
f := framework.HookExecutionConfigInit(t, hookConfigFor(args), func(ctx context.Context, in *pkg.HookInput) error {
197+
return storageClassChange(ctx, in, args)
198+
}, `{}`, `{}`)
199+
f.KubeStateSet(`
200+
---
201+
apiVersion: storage.k8s.io/v1
202+
kind: StorageClass
203+
metadata:
204+
name: standard
205+
annotations:
206+
storageclass.kubernetes.io/is-default-class: "true"
207+
`)
208+
f.RunHook()
209+
210+
require.NoError(t, f.HookError())
211+
assert.False(t, f.ValuesGet("myModule.internal.effectiveStorageClass").Exists())
212+
}

0 commit comments

Comments
 (0)