soteria/internal/k8s/state_test.go

192 lines
7.7 KiB
Go
Raw Normal View History

package k8s
import (
"context"
"errors"
"testing"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
k8sfake "k8s.io/client-go/kubernetes/fake"
k8stesting "k8s.io/client-go/testing"
)
func TestLoadSecretDataCoversMissingSecretValueAndCopy(t *testing.T) {
client := &Client{Clientset: k8sfake.NewSimpleClientset(
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "filled", Namespace: "atlas"},
Data: map[string][]byte{"token": []byte("atlas-secret")},
},
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "missing-key", Namespace: "atlas"},
Data: map[string][]byte{"other": []byte("atlas-secret")},
},
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "empty-value", Namespace: "atlas"},
Data: map[string][]byte{"token": {}},
},
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "empty", Namespace: "atlas"},
},
)}
value, err := client.LoadSecretData(context.Background(), "atlas", "missing", "token")
if err != nil || value != nil {
t.Fatalf("expected missing secret to return nil, got %q %v", string(value), err)
}
value, err = client.LoadSecretData(context.Background(), "atlas", "empty", "token")
if err != nil || value != nil {
t.Fatalf("expected empty secret key to return nil, got %q %v", string(value), err)
}
value, err = client.LoadSecretData(context.Background(), "atlas", "missing-key", "token")
if err != nil || value != nil {
t.Fatalf("expected missing data key to return nil, got %q %v", string(value), err)
}
value, err = client.LoadSecretData(context.Background(), "atlas", "empty-value", "token")
if err != nil || value != nil {
t.Fatalf("expected empty data value to return nil, got %q %v", string(value), err)
}
value, err = client.LoadSecretData(context.Background(), "atlas", "filled", "token")
if err != nil || string(value) != "atlas-secret" {
t.Fatalf("expected copied secret value, got %q %v", string(value), err)
}
value[0] = 'X'
secret, err := client.Clientset.CoreV1().Secrets("atlas").Get(context.Background(), "filled", metav1.GetOptions{})
if err != nil {
t.Fatalf("reload filled secret: %v", err)
}
if string(secret.Data["token"]) != "atlas-secret" {
t.Fatalf("expected returned bytes to be copied, got stored=%q", string(secret.Data["token"]))
}
}
func TestLoadSecretDataWrapsUnexpectedErrors(t *testing.T) {
clientset := k8sfake.NewSimpleClientset()
clientset.PrependReactor("get", "secrets", func(action k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, errors.New("get exploded")
})
client := &Client{Clientset: clientset}
if _, err := client.LoadSecretData(context.Background(), "atlas", "filled", "token"); err == nil || err.Error() == "get exploded" {
t.Fatalf("expected wrapped get error, got %v", err)
}
}
func TestSaveSecretDataCreatesAndUpdatesSecrets(t *testing.T) {
client := &Client{Clientset: k8sfake.NewSimpleClientset()}
if err := client.SaveSecretData(context.Background(), "atlas", "restic-usage", "usage.json", []byte("first"), map[string]string{"app": "soteria"}); err != nil {
t.Fatalf("create secret data: %v", err)
}
created, err := client.Clientset.CoreV1().Secrets("atlas").Get(context.Background(), "restic-usage", metav1.GetOptions{})
if err != nil {
t.Fatalf("get created secret: %v", err)
}
if string(created.Data["usage.json"]) != "first" || created.Labels["app"] != "soteria" {
t.Fatalf("unexpected created secret: %#v", created)
}
created.ResourceVersion = "1"
if _, err := client.Clientset.CoreV1().Secrets("atlas").Update(context.Background(), created, metav1.UpdateOptions{}); err != nil {
t.Fatalf("prime created secret resource version: %v", err)
}
if err := client.SaveSecretData(context.Background(), "atlas", "restic-usage", "usage.json", []byte("second"), map[string]string{"component": "usage-store"}); err != nil {
t.Fatalf("update secret data: %v", err)
}
updated, err := client.Clientset.CoreV1().Secrets("atlas").Get(context.Background(), "restic-usage", metav1.GetOptions{})
if err != nil {
t.Fatalf("get updated secret: %v", err)
}
if string(updated.Data["usage.json"]) != "second" {
t.Fatalf("expected updated secret payload, got %#v", updated.Data)
}
if updated.Labels["app"] != "soteria" || updated.Labels["component"] != "usage-store" {
t.Fatalf("expected merged labels, got %#v", updated.Labels)
}
}
func TestSaveSecretDataInitializesNilDataAndLabelsOnExistingSecret(t *testing.T) {
client := &Client{Clientset: k8sfake.NewSimpleClientset()}
if _, err := client.Clientset.CoreV1().Secrets("atlas").Create(context.Background(), &corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "restic-usage", Namespace: "atlas"},
}, metav1.CreateOptions{}); err != nil {
t.Fatalf("seed secret: %v", err)
}
seeded, err := client.Clientset.CoreV1().Secrets("atlas").Get(context.Background(), "restic-usage", metav1.GetOptions{})
if err != nil {
t.Fatalf("get seeded secret: %v", err)
}
seeded.ResourceVersion = "1"
if _, err := client.Clientset.CoreV1().Secrets("atlas").Update(context.Background(), seeded, metav1.UpdateOptions{}); err != nil {
t.Fatalf("prime seeded secret resource version: %v", err)
}
if err := client.SaveSecretData(context.Background(), "atlas", "restic-usage", "usage.json", []byte("value"), map[string]string{"app": "soteria"}); err != nil {
t.Fatalf("save secret data with nil data/labels: %v", err)
}
updated, err := client.Clientset.CoreV1().Secrets("atlas").Get(context.Background(), "restic-usage", metav1.GetOptions{})
if err != nil {
t.Fatalf("get updated secret: %v", err)
}
if string(updated.Data["usage.json"]) != "value" {
t.Fatalf("expected updated secret payload, got %#v", updated.Data)
}
if updated.Labels["app"] != "soteria" {
t.Fatalf("expected labels to be initialized, got %#v", updated.Labels)
}
}
func TestSaveSecretDataWrapsGetAndWriteErrors(t *testing.T) {
t.Run("get error", func(t *testing.T) {
clientset := k8sfake.NewSimpleClientset()
clientset.PrependReactor("get", "secrets", func(action k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, errors.New("get exploded")
})
client := &Client{Clientset: clientset}
if err := client.SaveSecretData(context.Background(), "atlas", "restic-usage", "usage.json", []byte("value"), nil); err == nil || err.Error() == "get exploded" {
t.Fatalf("expected wrapped get error, got %v", err)
}
})
t.Run("create error", func(t *testing.T) {
clientset := k8sfake.NewSimpleClientset()
clientset.PrependReactor("get", "secrets", func(action k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, apierrors.NewNotFound(corev1.Resource("secrets"), "restic-usage")
})
clientset.PrependReactor("create", "secrets", func(action k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, errors.New("create exploded")
})
client := &Client{Clientset: clientset}
if err := client.SaveSecretData(context.Background(), "atlas", "restic-usage", "usage.json", []byte("value"), nil); err == nil || err.Error() == "create exploded" {
t.Fatalf("expected wrapped create error, got %v", err)
}
})
t.Run("update error", func(t *testing.T) {
clientset := k8sfake.NewSimpleClientset(&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{Name: "restic-usage", Namespace: "atlas"},
Data: map[string][]byte{},
})
clientset.PrependReactor("update", "secrets", func(action k8stesting.Action) (bool, runtime.Object, error) {
return true, nil, errors.New("update exploded")
})
client := &Client{Clientset: clientset}
if err := client.SaveSecretData(context.Background(), "atlas", "restic-usage", "usage.json", []byte("value"), nil); err == nil || err.Error() == "update exploded" {
t.Fatalf("expected wrapped update error, got %v", err)
}
})
}