fix: resolve simulator test compilation errors
- Fix SimulateCSIData to accept []*Walker instead of []*SimWalker - Remove unused imports (path/filepath, time) from virtual_state_test.go - Fix assignment mismatch for CreateVirtualNode error handling - Fix deadlock in VirtualNodeStore by using saveLocked() when mutex is held - Refactor CreateAPNode to avoid race condition with state modification Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
eaad8f789a
commit
1d80c9ba36
3 changed files with 78 additions and 25 deletions
|
|
@ -486,3 +486,30 @@ func IsInFirstFresnelZone(tx, rx, point Point) bool {
|
|||
return FresnelZoneNumber(tx, rx, point) == 1
|
||||
}
|
||||
|
||||
// SimulateCSIData simulates CSI data for a set of links and walkers.
|
||||
// Returns a map of link IDs to their maximum deltaRMS value across all walkers,
|
||||
// but only includes links where deltaRMS is >= threshold.
|
||||
func (pm *PropagationModel) SimulateCSIData(links []Link, walkers []*Walker, threshold float64) map[string]float64 {
|
||||
results := make(map[string]float64)
|
||||
|
||||
for _, link := range links {
|
||||
maxDeltaRMS := 0.0
|
||||
|
||||
// Compute deltaRMS for each walker position
|
||||
for _, walker := range walkers {
|
||||
deltaRMS := pm.ComputeLinkActivity(link, walker.Position, threshold)
|
||||
if deltaRMS > maxDeltaRMS {
|
||||
maxDeltaRMS = deltaRMS
|
||||
}
|
||||
}
|
||||
|
||||
// Only include links that meet the threshold
|
||||
if maxDeltaRMS >= threshold {
|
||||
linkID := link.TX.ID + "->" + link.RX.ID
|
||||
results[linkID] = maxDeltaRMS
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,8 +117,8 @@ func (s *VirtualNodeStore) CreateNode(id, name string, nodeType NodeType, positi
|
|||
|
||||
s.nodes[id] = state
|
||||
|
||||
// Persist to disk
|
||||
if err := s.save(); err != nil {
|
||||
// Persist to disk (mutex already held)
|
||||
if err := s.saveLocked(); err != nil {
|
||||
delete(s.nodes, id)
|
||||
return nil, fmt.Errorf("save node: %w", err)
|
||||
}
|
||||
|
|
@ -133,19 +133,47 @@ func (s *VirtualNodeStore) CreateVirtualNode(id, name string, position Point) (*
|
|||
|
||||
// CreateAPNode creates a new access point node (for passive radar)
|
||||
func (s *VirtualNodeStore) CreateAPNode(id, name, bssid string, channel int, position Point) (*VirtualNodeState, error) {
|
||||
state, err := s.CreateNode(id, name, NodeTypeAP, position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if s.closed {
|
||||
return nil, fmt.Errorf("store is closed")
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
state.Role = RoleTX
|
||||
state.APBSSID = bssid
|
||||
state.APChannel = channel
|
||||
state.UpdatedAt = time.Now()
|
||||
s.mu.Unlock()
|
||||
if _, exists := s.nodes[id]; exists {
|
||||
return nil, fmt.Errorf("node %s already exists", id)
|
||||
}
|
||||
|
||||
if err := s.save(); err != nil {
|
||||
// Validate position is within space bounds
|
||||
minX, minY, minZ, maxX, maxY, maxZ := s.space.Bounds()
|
||||
if position.X < minX || position.X > maxX ||
|
||||
position.Y < minY || position.Y > maxY ||
|
||||
position.Z < minZ || position.Z > maxZ {
|
||||
return nil, fmt.Errorf("position (%f, %f, %f) is outside space bounds [%f, %f, %f] to [%f, %f, %f]",
|
||||
position.X, position.Y, position.Z, minX, minY, minZ, maxX, maxY, maxZ)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
state := &VirtualNodeState{
|
||||
ID: id,
|
||||
Name: name,
|
||||
Type: NodeTypeAP,
|
||||
Role: RoleTX,
|
||||
Position: position,
|
||||
Enabled: true,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
Metadata: make(map[string]interface{}),
|
||||
Tags: make([]string, 0),
|
||||
APBSSID: bssid,
|
||||
APChannel: channel,
|
||||
}
|
||||
|
||||
s.nodes[id] = state
|
||||
|
||||
// Persist to disk (mutex already held)
|
||||
if err := s.saveLocked(); err != nil {
|
||||
delete(s.nodes, id)
|
||||
return nil, fmt.Errorf("save AP node: %w", err)
|
||||
}
|
||||
|
||||
|
|
@ -196,7 +224,7 @@ func (s *VirtualNodeStore) UpdateNodePosition(id string, position Point) error {
|
|||
state.Position = position
|
||||
state.UpdatedAt = time.Now()
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// UpdateNodeRole updates a node's role
|
||||
|
|
@ -216,7 +244,7 @@ func (s *VirtualNodeStore) UpdateNodeRole(id string, role NodeRole) error {
|
|||
state.Role = role
|
||||
state.UpdatedAt = time.Now()
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// SetNodeEnabled enables or disables a node
|
||||
|
|
@ -236,7 +264,7 @@ func (s *VirtualNodeStore) SetNodeEnabled(id string, enabled bool) error {
|
|||
state.Enabled = enabled
|
||||
state.UpdatedAt = time.Now()
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// UpdateNodeMetadata updates a node's metadata
|
||||
|
|
@ -256,7 +284,7 @@ func (s *VirtualNodeStore) UpdateNodeMetadata(id string, metadata map[string]int
|
|||
state.Metadata = metadata
|
||||
state.UpdatedAt = time.Now()
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// AddTag adds a tag to a node
|
||||
|
|
@ -283,7 +311,7 @@ func (s *VirtualNodeStore) AddTag(id, tag string) error {
|
|||
state.Tags = append(state.Tags, tag)
|
||||
state.UpdatedAt = time.Now()
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// RemoveTag removes a tag from a node
|
||||
|
|
@ -315,7 +343,7 @@ func (s *VirtualNodeStore) RemoveTag(id, tag string) error {
|
|||
state.Tags = newTags
|
||||
state.UpdatedAt = time.Now()
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// DeleteNode removes a node from the store
|
||||
|
|
@ -333,7 +361,7 @@ func (s *VirtualNodeStore) DeleteNode(id string) error {
|
|||
|
||||
delete(s.nodes, id)
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// ListNodes returns all nodes
|
||||
|
|
@ -448,7 +476,7 @@ func (s *VirtualNodeStore) UpdateSpace(space *Space) error {
|
|||
}
|
||||
}
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// Clear removes all nodes from the store
|
||||
|
|
@ -462,7 +490,7 @@ func (s *VirtualNodeStore) Clear() error {
|
|||
|
||||
s.nodes = make(map[string]*VirtualNodeState)
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// ToNodeSet converts the stored nodes to a NodeSet for simulation
|
||||
|
|
@ -540,7 +568,7 @@ func (s *VirtualNodeStore) ImportFromNodeSet(nodeSet *NodeSet) error {
|
|||
s.nodes[node.ID] = state
|
||||
}
|
||||
|
||||
return s.save()
|
||||
return s.saveLocked()
|
||||
}
|
||||
|
||||
// Close closes the store and releases resources
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@ package simulator
|
|||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Test helper to create a temporary store
|
||||
|
|
@ -804,7 +802,7 @@ func TestVirtualNodeStore_Close(t *testing.T) {
|
|||
}
|
||||
|
||||
// Operations should fail after close
|
||||
err = store.CreateVirtualNode("node-2", "Should Fail", NewPoint(2.0, 3.0, 1.5))
|
||||
_, err = store.CreateVirtualNode("node-2", "Should Fail", NewPoint(2.0, 3.0, 1.5))
|
||||
if err == nil {
|
||||
t.Error("Expected error when creating node after close")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue