fix(node): surface corrupted persisted state during load
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
4c8bced1e7
commit
6a70c6f234
4 changed files with 50 additions and 6 deletions
|
|
@ -104,6 +104,9 @@ func NewNodeManager() (*NodeManager, error) {
|
|||
|
||||
// NewNodeManagerFromPaths loads or creates a node identity store at explicit paths.
|
||||
//
|
||||
// Missing files are treated as a fresh install; malformed or partial identity
|
||||
// state is returned as an error so callers can handle it explicitly.
|
||||
//
|
||||
// nodeManager, err := NewNodeManagerFromPaths("/srv/p2p/private.key", "/srv/p2p/node.json")
|
||||
func NewNodeManagerFromPaths(keyPath, configPath string) (*NodeManager, error) {
|
||||
nm := &NodeManager{
|
||||
|
|
@ -111,12 +114,15 @@ func NewNodeManagerFromPaths(keyPath, configPath string) (*NodeManager, error) {
|
|||
configPath: configPath,
|
||||
}
|
||||
|
||||
// Try to load existing identity
|
||||
if err := nm.loadIdentity(); err != nil {
|
||||
// Identity doesn't exist yet, that's ok
|
||||
// Missing files indicate a first run; anything else is a load failure.
|
||||
if !fsExists(keyPath) && !fsExists(configPath) {
|
||||
return nm, nil
|
||||
}
|
||||
|
||||
if err := nm.loadIdentity(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return nm, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,6 +170,22 @@ func TestIdentity_NodeIdentity_Good(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestIdentity_NodeManagerFromPaths_CorruptIdentity_Bad(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
keyPath, configPath := testNodeManagerPaths(tmpDir)
|
||||
|
||||
testWriteFile(t, configPath, []byte(`{"id":"node-1","name":"broken","publicKey":"not-json"`), 0o600)
|
||||
|
||||
nm, err := NewNodeManagerFromPaths(keyPath, configPath)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when loading a corrupted node identity")
|
||||
}
|
||||
|
||||
if nm != nil {
|
||||
t.Fatal("expected nil node manager when identity data is corrupted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIdentity_NodeRoles_Good(t *testing.T) {
|
||||
tests := []struct {
|
||||
role NodeRole
|
||||
|
|
|
|||
12
node/peer.go
12
node/peer.go
|
|
@ -136,6 +136,9 @@ func NewPeerRegistry() (*PeerRegistry, error) {
|
|||
|
||||
// NewPeerRegistryFromPath loads or creates a peer registry at an explicit path.
|
||||
//
|
||||
// Missing files are treated as an empty registry; malformed registry files are
|
||||
// returned as errors so callers can repair the persisted state.
|
||||
//
|
||||
// peerRegistry, err := NewPeerRegistryFromPath("/srv/p2p/peers.json")
|
||||
func NewPeerRegistryFromPath(peersPath string) (*PeerRegistry, error) {
|
||||
pr := &PeerRegistry{
|
||||
|
|
@ -146,13 +149,16 @@ func NewPeerRegistryFromPath(peersPath string) (*PeerRegistry, error) {
|
|||
allowedPublicKeys: make(map[string]bool),
|
||||
}
|
||||
|
||||
// Try to load existing peers
|
||||
if err := pr.load(); err != nil {
|
||||
// No existing peers, that's ok
|
||||
// Missing files indicate a first run; any existing file must parse cleanly.
|
||||
if !fsExists(peersPath) {
|
||||
pr.rebuildKDTree()
|
||||
return pr, nil
|
||||
}
|
||||
|
||||
if err := pr.load(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pr.rebuildKDTree()
|
||||
return pr, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,22 @@ func TestPeer_Registry_NewPeerRegistry_Good(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestPeer_Registry_NewPeerRegistryFromPath_CorruptFile_Bad(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
peersPath := testJoinPath(tmpDir, "peers.json")
|
||||
|
||||
testWriteFile(t, peersPath, []byte(`{"id":"peer-1"`), 0o600)
|
||||
|
||||
pr, err := NewPeerRegistryFromPath(peersPath)
|
||||
if err == nil {
|
||||
t.Fatal("expected error when loading a corrupted peer registry")
|
||||
}
|
||||
|
||||
if pr != nil {
|
||||
t.Fatal("expected nil peer registry when persisted data is corrupted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPeer_Registry_AddPeer_Good(t *testing.T) {
|
||||
pr, cleanup := setupTestPeerRegistry(t)
|
||||
defer cleanup()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue