From 7a1c9ff53f1f2ebfc261b2e481cbe5ca83445dcf Mon Sep 17 00:00:00 2001 From: rcourtman Date: Tue, 2 Dec 2025 02:54:49 +0000 Subject: [PATCH] test: Add SaveNodesConfigAllowEmpty test and document deadlock Add test for SaveNodesConfigAllowEmpty which permits explicit deletion of all nodes. Document deadlock bug in saveNodesConfig where empty config protection tries to call LoadNodesConfig while holding write lock. --- internal/config/persistence_test.go | 41 +++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/internal/config/persistence_test.go b/internal/config/persistence_test.go index bc6dcfb..8fbddcc 100644 --- a/internal/config/persistence_test.go +++ b/internal/config/persistence_test.go @@ -1670,6 +1670,47 @@ func TestLoadNodesConfig_PMGHostNormalization(t *testing.T) { } } +// NOTE: TestSaveNodesConfig_BlocksEmptyWhenNodesExist is not included because +// the saveNodesConfig function has a deadlock bug - it holds c.mu.Lock() while +// calling LoadNodesConfig() which tries to acquire c.mu.RLock(). This makes +// the empty config protection path untestable without first fixing the bug. + +func TestSaveNodesConfigAllowEmpty_PermitsEmptyConfig(t *testing.T) { + tempDir := t.TempDir() + cp := config.NewConfigPersistence(tempDir) + if err := cp.EnsureConfigDir(); err != nil { + t.Fatalf("EnsureConfigDir: %v", err) + } + + // First save a valid config with nodes + pveInstances := []config.PVEInstance{ + { + Name: "pve-test", + Host: "https://pve.local:8006", + User: "root@pam", + }, + } + + if err := cp.SaveNodesConfig(pveInstances, nil, nil); err != nil { + t.Fatalf("SaveNodesConfig initial: %v", err) + } + + // SaveNodesConfigAllowEmpty should permit deleting all nodes + err := cp.SaveNodesConfigAllowEmpty(nil, nil, nil) + if err != nil { + t.Fatalf("SaveNodesConfigAllowEmpty should permit empty config, got: %v", err) + } + + // Verify nodes are now empty + loaded, err := cp.LoadNodesConfig() + if err != nil { + t.Fatalf("LoadNodesConfig: %v", err) + } + if len(loaded.PVEInstances) != 0 { + t.Errorf("expected 0 PVE instances after AllowEmpty save, got %d", len(loaded.PVEInstances)) + } +} + func TestCleanupOldBackupsNonExistentDirectory(t *testing.T) { tempDir := t.TempDir() cp := config.NewConfigPersistence(tempDir)