test: Add tests for convertDockerSwarmInfo, namespacePathsForDatastore, preserveFailedStorageBackups
- convertDockerSwarmInfo: 66.7%→100% (4 cases for nil, empty, populated structs) - namespacePathsForDatastore: 92.3%→100% (removed unreachable dead code) - preserveFailedStorageBackups: 91.3%→100% (6 cases for filtering, deduplication)
This commit is contained in:
parent
0bfc9ed447
commit
e7bc06033a
3 changed files with 254 additions and 3 deletions
|
|
@ -8134,9 +8134,6 @@ func namespacePathsForDatastore(ds models.PBSDatastore) []string {
|
||||||
seen[path] = struct{}{}
|
seen[path] = struct{}{}
|
||||||
paths = append(paths, path)
|
paths = append(paths, path)
|
||||||
}
|
}
|
||||||
if len(paths) == 0 {
|
|
||||||
paths = append(paths, "")
|
|
||||||
}
|
|
||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import (
|
||||||
|
|
||||||
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
||||||
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
||||||
|
agentsdocker "github.com/rcourtman/pulse-go-rewrite/pkg/agents/docker"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestParseDurationEnv(t *testing.T) {
|
func TestParseDurationEnv(t *testing.T) {
|
||||||
|
|
@ -1677,3 +1678,110 @@ func TestSchedulerHealth(t *testing.T) {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestConvertDockerSwarmInfo(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input *agentsdocker.SwarmInfo
|
||||||
|
expected *models.DockerSwarmInfo
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "nil input returns nil",
|
||||||
|
input: nil,
|
||||||
|
expected: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "empty struct returns empty struct",
|
||||||
|
input: &agentsdocker.SwarmInfo{},
|
||||||
|
expected: &models.DockerSwarmInfo{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "all fields populated",
|
||||||
|
input: &agentsdocker.SwarmInfo{
|
||||||
|
NodeID: "node-abc123",
|
||||||
|
NodeRole: "manager",
|
||||||
|
LocalState: "active",
|
||||||
|
ControlAvailable: true,
|
||||||
|
ClusterID: "cluster-xyz789",
|
||||||
|
ClusterName: "my-swarm",
|
||||||
|
Scope: "swarm",
|
||||||
|
Error: "",
|
||||||
|
},
|
||||||
|
expected: &models.DockerSwarmInfo{
|
||||||
|
NodeID: "node-abc123",
|
||||||
|
NodeRole: "manager",
|
||||||
|
LocalState: "active",
|
||||||
|
ControlAvailable: true,
|
||||||
|
ClusterID: "cluster-xyz789",
|
||||||
|
ClusterName: "my-swarm",
|
||||||
|
Scope: "swarm",
|
||||||
|
Error: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "worker node with error",
|
||||||
|
input: &agentsdocker.SwarmInfo{
|
||||||
|
NodeID: "node-worker1",
|
||||||
|
NodeRole: "worker",
|
||||||
|
LocalState: "pending",
|
||||||
|
ControlAvailable: false,
|
||||||
|
ClusterID: "",
|
||||||
|
ClusterName: "",
|
||||||
|
Scope: "local",
|
||||||
|
Error: "connection refused",
|
||||||
|
},
|
||||||
|
expected: &models.DockerSwarmInfo{
|
||||||
|
NodeID: "node-worker1",
|
||||||
|
NodeRole: "worker",
|
||||||
|
LocalState: "pending",
|
||||||
|
ControlAvailable: false,
|
||||||
|
ClusterID: "",
|
||||||
|
ClusterName: "",
|
||||||
|
Scope: "local",
|
||||||
|
Error: "connection refused",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result := convertDockerSwarmInfo(tt.input)
|
||||||
|
|
||||||
|
if tt.expected == nil {
|
||||||
|
if result != nil {
|
||||||
|
t.Errorf("expected nil, got %+v", result)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if result == nil {
|
||||||
|
t.Fatal("expected non-nil result")
|
||||||
|
}
|
||||||
|
|
||||||
|
if result.NodeID != tt.expected.NodeID {
|
||||||
|
t.Errorf("NodeID: expected %q, got %q", tt.expected.NodeID, result.NodeID)
|
||||||
|
}
|
||||||
|
if result.NodeRole != tt.expected.NodeRole {
|
||||||
|
t.Errorf("NodeRole: expected %q, got %q", tt.expected.NodeRole, result.NodeRole)
|
||||||
|
}
|
||||||
|
if result.LocalState != tt.expected.LocalState {
|
||||||
|
t.Errorf("LocalState: expected %q, got %q", tt.expected.LocalState, result.LocalState)
|
||||||
|
}
|
||||||
|
if result.ControlAvailable != tt.expected.ControlAvailable {
|
||||||
|
t.Errorf("ControlAvailable: expected %v, got %v", tt.expected.ControlAvailable, result.ControlAvailable)
|
||||||
|
}
|
||||||
|
if result.ClusterID != tt.expected.ClusterID {
|
||||||
|
t.Errorf("ClusterID: expected %q, got %q", tt.expected.ClusterID, result.ClusterID)
|
||||||
|
}
|
||||||
|
if result.ClusterName != tt.expected.ClusterName {
|
||||||
|
t.Errorf("ClusterName: expected %q, got %q", tt.expected.ClusterName, result.ClusterName)
|
||||||
|
}
|
||||||
|
if result.Scope != tt.expected.Scope {
|
||||||
|
t.Errorf("Scope: expected %q, got %q", tt.expected.Scope, result.Scope)
|
||||||
|
}
|
||||||
|
if result.Error != tt.expected.Error {
|
||||||
|
t.Errorf("Error: expected %q, got %q", tt.expected.Error, result.Error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,6 +92,152 @@ func TestPreserveFailedStorageBackupsSkipsDuplicates(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPreserveFailedStorageBackupsEmptyPreserveMap(t *testing.T) {
|
||||||
|
instance := "pve01"
|
||||||
|
current := []models.StorageBackup{
|
||||||
|
{ID: "backup1", Instance: instance, Storage: "local"},
|
||||||
|
}
|
||||||
|
snapshot := models.StateSnapshot{
|
||||||
|
PVEBackups: models.PVEBackups{
|
||||||
|
StorageBackups: []models.StorageBackup{
|
||||||
|
{ID: "backup2", Instance: instance, Storage: "nas-share"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, storages := preserveFailedStorageBackups(instance, snapshot, nil, current)
|
||||||
|
|
||||||
|
if len(merged) != 1 {
|
||||||
|
t.Fatalf("expected current unchanged with 1 backup, got %d", len(merged))
|
||||||
|
}
|
||||||
|
if storages != nil {
|
||||||
|
t.Fatalf("expected nil storages list, got %v", storages)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also test empty map (not nil)
|
||||||
|
merged2, storages2 := preserveFailedStorageBackups(instance, snapshot, map[string]struct{}{}, current)
|
||||||
|
if len(merged2) != 1 {
|
||||||
|
t.Fatalf("expected current unchanged with 1 backup, got %d", len(merged2))
|
||||||
|
}
|
||||||
|
if storages2 != nil {
|
||||||
|
t.Fatalf("expected nil storages list for empty map, got %v", storages2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPreserveFailedStorageBackupsNoMatchingBackups(t *testing.T) {
|
||||||
|
instance := "pve01"
|
||||||
|
current := []models.StorageBackup{
|
||||||
|
{ID: "backup1", Instance: instance, Storage: "local"},
|
||||||
|
}
|
||||||
|
snapshot := models.StateSnapshot{
|
||||||
|
PVEBackups: models.PVEBackups{
|
||||||
|
StorageBackups: []models.StorageBackup{
|
||||||
|
{ID: "backup2", Instance: instance, Storage: "other-storage"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
toPreserve := map[string]struct{}{
|
||||||
|
"nas-share": {}, // Storage not in snapshot
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, storages := preserveFailedStorageBackups(instance, snapshot, toPreserve, current)
|
||||||
|
|
||||||
|
if len(merged) != 1 {
|
||||||
|
t.Fatalf("expected current unchanged with 1 backup, got %d", len(merged))
|
||||||
|
}
|
||||||
|
if storages != nil {
|
||||||
|
t.Fatalf("expected nil storages list when no matches, got %v", storages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPreserveFailedStorageBackupsWrongInstance(t *testing.T) {
|
||||||
|
instance := "pve01"
|
||||||
|
current := []models.StorageBackup{
|
||||||
|
{ID: "backup1", Instance: instance, Storage: "local"},
|
||||||
|
}
|
||||||
|
snapshot := models.StateSnapshot{
|
||||||
|
PVEBackups: models.PVEBackups{
|
||||||
|
StorageBackups: []models.StorageBackup{
|
||||||
|
{ID: "backup2", Instance: "pve02", Storage: "nas-share"}, // Wrong instance
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
toPreserve := map[string]struct{}{
|
||||||
|
"nas-share": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, storages := preserveFailedStorageBackups(instance, snapshot, toPreserve, current)
|
||||||
|
|
||||||
|
if len(merged) != 1 {
|
||||||
|
t.Fatalf("expected current unchanged (wrong instance skipped), got %d backups", len(merged))
|
||||||
|
}
|
||||||
|
if storages != nil {
|
||||||
|
t.Fatalf("expected nil storages list, got %v", storages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPreserveFailedStorageBackupsStorageNotInPreserveMap(t *testing.T) {
|
||||||
|
instance := "pve01"
|
||||||
|
current := []models.StorageBackup{
|
||||||
|
{ID: "backup1", Instance: instance, Storage: "local"},
|
||||||
|
}
|
||||||
|
snapshot := models.StateSnapshot{
|
||||||
|
PVEBackups: models.PVEBackups{
|
||||||
|
StorageBackups: []models.StorageBackup{
|
||||||
|
{ID: "backup2", Instance: instance, Storage: "nas-share"},
|
||||||
|
{ID: "backup3", Instance: instance, Storage: "other-storage"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
toPreserve := map[string]struct{}{
|
||||||
|
"nas-share": {}, // Only nas-share should be preserved
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, storages := preserveFailedStorageBackups(instance, snapshot, toPreserve, current)
|
||||||
|
|
||||||
|
if len(merged) != 2 {
|
||||||
|
t.Fatalf("expected 2 backups (original + nas-share), got %d", len(merged))
|
||||||
|
}
|
||||||
|
if len(storages) != 1 || storages[0] != "nas-share" {
|
||||||
|
t.Fatalf("expected [nas-share], got %v", storages)
|
||||||
|
}
|
||||||
|
// Verify other-storage was not added
|
||||||
|
for _, b := range merged {
|
||||||
|
if b.Storage == "other-storage" {
|
||||||
|
t.Fatal("other-storage should not have been preserved")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPreserveFailedStorageBackupsSortedStorageNames(t *testing.T) {
|
||||||
|
instance := "pve01"
|
||||||
|
current := []models.StorageBackup{}
|
||||||
|
snapshot := models.StateSnapshot{
|
||||||
|
PVEBackups: models.PVEBackups{
|
||||||
|
StorageBackups: []models.StorageBackup{
|
||||||
|
{ID: "backup1", Instance: instance, Storage: "zebra-storage"},
|
||||||
|
{ID: "backup2", Instance: instance, Storage: "alpha-storage"},
|
||||||
|
{ID: "backup3", Instance: instance, Storage: "middle-storage"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
toPreserve := map[string]struct{}{
|
||||||
|
"zebra-storage": {},
|
||||||
|
"alpha-storage": {},
|
||||||
|
"middle-storage": {},
|
||||||
|
}
|
||||||
|
|
||||||
|
merged, storages := preserveFailedStorageBackups(instance, snapshot, toPreserve, current)
|
||||||
|
|
||||||
|
if len(merged) != 3 {
|
||||||
|
t.Fatalf("expected 3 backups, got %d", len(merged))
|
||||||
|
}
|
||||||
|
expected := []string{"alpha-storage", "middle-storage", "zebra-storage"}
|
||||||
|
if !slices.Equal(storages, expected) {
|
||||||
|
t.Fatalf("expected sorted storages %v, got %v", expected, storages)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestStorageNamesForNode(t *testing.T) {
|
func TestStorageNamesForNode(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue