126 lines
3.7 KiB
Go
126 lines
3.7 KiB
Go
package server
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"scm.bstein.dev/bstein/soteria/internal/api"
|
|
"scm.bstein.dev/bstein/soteria/internal/config"
|
|
"scm.bstein.dev/bstein/soteria/internal/k8s"
|
|
)
|
|
|
|
type startTestKubeClient struct {
|
|
*fakeKubeClient
|
|
mu sync.Mutex
|
|
loadCalls int
|
|
listPVCCalls int
|
|
}
|
|
|
|
func (k *startTestKubeClient) LoadSecretData(ctx context.Context, namespace, secretName, key string) ([]byte, error) {
|
|
k.mu.Lock()
|
|
k.loadCalls++
|
|
k.mu.Unlock()
|
|
return k.fakeKubeClient.LoadSecretData(ctx, namespace, secretName, key)
|
|
}
|
|
|
|
func (k *startTestKubeClient) ListBoundPVCs(ctx context.Context) ([]k8s.PVCSummary, error) {
|
|
k.mu.Lock()
|
|
k.listPVCCalls++
|
|
k.mu.Unlock()
|
|
return k.fakeKubeClient.ListBoundPVCs(ctx)
|
|
}
|
|
|
|
func (k *startTestKubeClient) counts() (int, int) {
|
|
k.mu.Lock()
|
|
defer k.mu.Unlock()
|
|
return k.loadCalls, k.listPVCCalls
|
|
}
|
|
|
|
func newStartTestServer(cfg *config.Config, client kubeClient) *Server {
|
|
return &Server{
|
|
cfg: cfg,
|
|
client: client,
|
|
longhorn: &fakeLonghornClient{},
|
|
metrics: newTelemetry(),
|
|
ui: newUIRenderer(),
|
|
policies: map[string]api.BackupPolicy{},
|
|
jobUsage: map[string]resticJobUsageCacheEntry{},
|
|
usageStore: map[string]resticPersistedUsageEntry{},
|
|
}
|
|
}
|
|
|
|
func TestStartRunsInitialLoadAndTickerLoopWithoutB2(t *testing.T) {
|
|
client := &startTestKubeClient{
|
|
fakeKubeClient: &fakeKubeClient{
|
|
pvcs: []k8s.PVCSummary{{Namespace: "apps", Name: "data", VolumeName: "vol-data", Phase: "Bound"}},
|
|
},
|
|
}
|
|
srv := newStartTestServer(&config.Config{
|
|
Namespace: "atlas",
|
|
PolicySecretName: "soteria-policies",
|
|
UsageSecretName: "soteria-usage",
|
|
BackupDriver: "longhorn",
|
|
BackupMaxAge: 24 * time.Hour,
|
|
MetricsRefreshInterval: 10 * time.Millisecond,
|
|
PolicyEvalInterval: 10 * time.Millisecond,
|
|
B2Enabled: false,
|
|
}, client)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
srv.Start(ctx)
|
|
time.Sleep(35 * time.Millisecond)
|
|
cancel()
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
loadCalls, listPVCCalls := client.counts()
|
|
if loadCalls < 2 {
|
|
t.Fatalf("expected initial policy/usage secret loads, got %d", loadCalls)
|
|
}
|
|
if listPVCCalls < 2 {
|
|
t.Fatalf("expected inventory refresh to run initially and on ticker, got %d", listPVCCalls)
|
|
}
|
|
if srv.metrics.inventoryRefreshTime == 0 {
|
|
t.Fatalf("expected inventory metrics to be recorded after start loop")
|
|
}
|
|
}
|
|
|
|
func TestStartRunsB2TickerAndStoresRefreshFailures(t *testing.T) {
|
|
client := &startTestKubeClient{
|
|
fakeKubeClient: &fakeKubeClient{
|
|
pvcs: []k8s.PVCSummary{{Namespace: "apps", Name: "data", VolumeName: "vol-data", Phase: "Bound"}},
|
|
},
|
|
}
|
|
srv := newStartTestServer(&config.Config{
|
|
Namespace: "atlas",
|
|
PolicySecretName: "soteria-policies",
|
|
UsageSecretName: "soteria-usage",
|
|
BackupDriver: "longhorn",
|
|
BackupMaxAge: 24 * time.Hour,
|
|
MetricsRefreshInterval: 10 * time.Millisecond,
|
|
PolicyEvalInterval: 10 * time.Millisecond,
|
|
B2Enabled: true,
|
|
B2Endpoint: "https://",
|
|
B2AccessKeyID: "atlas-key",
|
|
B2SecretAccessKey: "atlas-secret",
|
|
B2ScanInterval: 10 * time.Millisecond,
|
|
B2ScanTimeout: 10 * time.Millisecond,
|
|
}, client)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
srv.Start(ctx)
|
|
time.Sleep(35 * time.Millisecond)
|
|
cancel()
|
|
time.Sleep(20 * time.Millisecond)
|
|
|
|
usage := srv.getB2Usage()
|
|
if !usage.Enabled || usage.Error == "" || !strings.Contains(usage.Error, "S3 endpoint host is empty") {
|
|
t.Fatalf("expected B2 ticker refresh failure snapshot, got %#v", usage)
|
|
}
|
|
if srv.metrics.b2ScanTimestamp == 0 {
|
|
t.Fatalf("expected B2 scan metrics to be recorded during start loop")
|
|
}
|
|
}
|