mirror of
https://github.com/stakater/Reloader.git
synced 2026-08-22 13:36:54 +00:00
280 lines
5.9 KiB
Go
280 lines
5.9 KiB
Go
package reload
|
|
|
|
import (
|
|
"testing"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
csiv1 "sigs.k8s.io/secrets-store-csi-driver/apis/v1"
|
|
)
|
|
|
|
func TestHasher_HashConfigMap(t *testing.T) {
|
|
hasher := NewHasher()
|
|
|
|
tests := []struct {
|
|
name string
|
|
cm *corev1.ConfigMap
|
|
wantHash string
|
|
}{
|
|
{
|
|
name: "empty configmap",
|
|
cm: &corev1.ConfigMap{
|
|
Data: nil,
|
|
BinaryData: nil,
|
|
},
|
|
wantHash: hasher.HashConfigMap(&corev1.ConfigMap{}),
|
|
},
|
|
{
|
|
name: "configmap with data",
|
|
cm: &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
"key1": "value1",
|
|
"key2": "value2",
|
|
},
|
|
},
|
|
wantHash: hasher.HashConfigMap(
|
|
&corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
"key1": "value1",
|
|
"key2": "value2",
|
|
},
|
|
},
|
|
),
|
|
},
|
|
{
|
|
name: "configmap with binary data",
|
|
cm: &corev1.ConfigMap{
|
|
BinaryData: map[string][]byte{
|
|
"binary1": []byte("binaryvalue1"),
|
|
},
|
|
},
|
|
wantHash: hasher.HashConfigMap(
|
|
&corev1.ConfigMap{
|
|
BinaryData: map[string][]byte{
|
|
"binary1": []byte("binaryvalue1"),
|
|
},
|
|
},
|
|
),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(
|
|
tt.name, func(t *testing.T) {
|
|
got := hasher.HashConfigMap(tt.cm)
|
|
if got != tt.wantHash {
|
|
t.Errorf("HashConfigMap() = %v, want %v", got, tt.wantHash)
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestHasher_HashConfigMap_Deterministic(t *testing.T) {
|
|
hasher := NewHasher()
|
|
|
|
cm := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
"z-key": "value-z",
|
|
"a-key": "value-a",
|
|
"m-key": "value-m",
|
|
},
|
|
}
|
|
|
|
hash1 := hasher.HashConfigMap(cm)
|
|
hash2 := hasher.HashConfigMap(cm)
|
|
hash3 := hasher.HashConfigMap(cm)
|
|
|
|
if hash1 != hash2 || hash2 != hash3 {
|
|
t.Errorf("Hash is not deterministic: %s, %s, %s", hash1, hash2, hash3)
|
|
}
|
|
}
|
|
|
|
func TestHasher_HashConfigMap_DifferentValues(t *testing.T) {
|
|
hasher := NewHasher()
|
|
|
|
cm1 := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
"key": "value1",
|
|
},
|
|
}
|
|
|
|
cm2 := &corev1.ConfigMap{
|
|
Data: map[string]string{
|
|
"key": "value2",
|
|
},
|
|
}
|
|
|
|
hash1 := hasher.HashConfigMap(cm1)
|
|
hash2 := hasher.HashConfigMap(cm2)
|
|
|
|
if hash1 == hash2 {
|
|
t.Errorf("Different values should produce different hashes")
|
|
}
|
|
}
|
|
|
|
func TestHasher_HashSecret(t *testing.T) {
|
|
hasher := NewHasher()
|
|
|
|
tests := []struct {
|
|
name string
|
|
secret *corev1.Secret
|
|
wantHash string
|
|
}{
|
|
{
|
|
name: "empty secret",
|
|
secret: &corev1.Secret{
|
|
Data: nil,
|
|
},
|
|
wantHash: hasher.HashSecret(&corev1.Secret{}),
|
|
},
|
|
{
|
|
name: "secret with data",
|
|
secret: &corev1.Secret{
|
|
Data: map[string][]byte{
|
|
"key1": []byte("value1"),
|
|
"key2": []byte("value2"),
|
|
},
|
|
},
|
|
wantHash: hasher.HashSecret(
|
|
&corev1.Secret{
|
|
Data: map[string][]byte{
|
|
"key1": []byte("value1"),
|
|
"key2": []byte("value2"),
|
|
},
|
|
},
|
|
),
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(
|
|
tt.name, func(t *testing.T) {
|
|
got := hasher.HashSecret(tt.secret)
|
|
if got != tt.wantHash {
|
|
t.Errorf("HashSecret() = %v, want %v", got, tt.wantHash)
|
|
}
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func TestHasher_HashSecret_Deterministic(t *testing.T) {
|
|
hasher := NewHasher()
|
|
|
|
secret := &corev1.Secret{
|
|
Data: map[string][]byte{
|
|
"z-key": []byte("value-z"),
|
|
"a-key": []byte("value-a"),
|
|
"m-key": []byte("value-m"),
|
|
},
|
|
}
|
|
|
|
hash1 := hasher.HashSecret(secret)
|
|
hash2 := hasher.HashSecret(secret)
|
|
hash3 := hasher.HashSecret(secret)
|
|
|
|
if hash1 != hash2 || hash2 != hash3 {
|
|
t.Errorf("Hash is not deterministic: %s, %s, %s", hash1, hash2, hash3)
|
|
}
|
|
}
|
|
|
|
func TestHasher_HashSecret_DifferentValues(t *testing.T) {
|
|
hasher := NewHasher()
|
|
|
|
secret1 := &corev1.Secret{
|
|
Data: map[string][]byte{
|
|
"key": []byte("value1"),
|
|
},
|
|
}
|
|
|
|
secret2 := &corev1.Secret{
|
|
Data: map[string][]byte{
|
|
"key": []byte("value2"),
|
|
},
|
|
}
|
|
|
|
hash1 := hasher.HashSecret(secret1)
|
|
hash2 := hasher.HashSecret(secret2)
|
|
|
|
if hash1 == hash2 {
|
|
t.Errorf("Different values should produce different hashes")
|
|
}
|
|
}
|
|
|
|
func TestHasher_EmptyHash(t *testing.T) {
|
|
hasher := NewHasher()
|
|
|
|
emptyHash := hasher.EmptyHash()
|
|
if emptyHash != "" {
|
|
t.Errorf("EmptyHash should be empty string, got %s", emptyHash)
|
|
}
|
|
|
|
cm := &corev1.ConfigMap{}
|
|
cmHash := hasher.HashConfigMap(cm)
|
|
if cmHash == "" {
|
|
t.Error("Empty ConfigMap should have a non-empty hash")
|
|
}
|
|
|
|
secret := &corev1.Secret{}
|
|
secretHash := hasher.HashSecret(secret)
|
|
if secretHash == "" {
|
|
t.Error("Empty Secret should have a non-empty hash")
|
|
}
|
|
}
|
|
|
|
func TestHasher_NilInput(t *testing.T) {
|
|
hasher := NewHasher()
|
|
|
|
cmHash := hasher.HashConfigMap(nil)
|
|
if cmHash == "" {
|
|
t.Error("nil ConfigMap should return a valid hash")
|
|
}
|
|
|
|
secretHash := hasher.HashSecret(nil)
|
|
if secretHash == "" {
|
|
t.Error("nil Secret should return a valid hash")
|
|
}
|
|
}
|
|
|
|
func TestHashSecretProviderClass(t *testing.T) {
|
|
h := NewHasher()
|
|
status := csiv1.SecretProviderClassPodStatusStatus{
|
|
SecretProviderClassName: "my-spc",
|
|
Objects: []csiv1.SecretProviderClassObject{
|
|
{ID: "secret/data/b", Version: "2"},
|
|
{ID: "secret/data/a", Version: "1"},
|
|
},
|
|
}
|
|
|
|
// Expected = SHA1 hex of the sorted, ';'-joined string, matching master.
|
|
expectedInput := "SecretProviderClassName=my-spc;secret/data/a=1;secret/data/b=2"
|
|
expected := h.computeSHA(expectedInput)
|
|
|
|
got := h.HashSecretProviderClass(status)
|
|
if got != expected {
|
|
t.Fatalf("HashSecretProviderClass = %q, want %q", got, expected)
|
|
}
|
|
|
|
// Order independence: shuffling objects must not change the hash.
|
|
statusReordered := csiv1.SecretProviderClassPodStatusStatus{
|
|
SecretProviderClassName: "my-spc",
|
|
Objects: []csiv1.SecretProviderClassObject{
|
|
{ID: "secret/data/a", Version: "1"},
|
|
{ID: "secret/data/b", Version: "2"},
|
|
},
|
|
}
|
|
if h.HashSecretProviderClass(statusReordered) != got {
|
|
t.Fatalf("hash not order-independent")
|
|
}
|
|
}
|
|
|
|
func TestHashSecretProviderClassEmpty(t *testing.T) {
|
|
h := NewHasher()
|
|
status := csiv1.SecretProviderClassPodStatusStatus{SecretProviderClassName: "empty"}
|
|
got := h.HashSecretProviderClass(status)
|
|
want := h.computeSHA("SecretProviderClassName=empty")
|
|
if got != want {
|
|
t.Fatalf("HashSecretProviderClass(empty) = %q, want %q", got, want)
|
|
}
|
|
}
|