Browse Source

Polish up the Run method

pull/1/head
Stephanie Gredell 7 months ago
parent
commit
0fc1b842f4
  1. 35
      internal/simulation/engine.go
  2. 41
      internal/simulation/engine_test.go

35
internal/simulation/engine.go

@ -184,8 +184,13 @@ func (e *Engine) Run() {
e.Timeline = e.Timeline[:0] e.Timeline = e.Timeline[:0]
for tick := 0; tick < e.Duration; tick++ { for tick := 0; tick < e.Duration; tick++ {
entries := e.findEntryPoints()
if len(entries) == 0 {
fmt.Println("[ERROR] No entry points found! Simulation will not inject requests.")
}
// inject new requests // inject new requests
for _, node := range e.findEntryPoints() { for _, node := range entries {
if shouldInject(tick) { if shouldInject(tick) {
req := &Request{ req := &Request{
ID: generateRequestID(tick), ID: generateRequestID(tick),
@ -206,23 +211,26 @@ func (e *Engine) Run() {
} }
for id, node := range e.Nodes { for id, node := range e.Nodes {
snapshot.NodeHealth[id] = NodeState{
QueueSize: len(node.GetQueue()),
Alive: node.IsAlive(),
}
// tick all nodes // tick all nodes
node.Tick(tick, currentTimeMs) node.Tick(tick, currentTimeMs)
emitted := node.Emit()
// emit and forward requests to connected nodes // emit and forward requests to connected nodes
for _, req := range emitted { for _, req := range node.Emit() {
for _, targetID := range node.GetTargets() { for _, targetID := range node.GetTargets() {
if target, ok := e.Nodes[targetID]; ok && target.IsAlive() { if target, ok := e.Nodes[targetID]; ok && target.IsAlive() && !hasVisited(req, targetID) {
target.Receive(req) // Deep copy request and update path
newReq := *req
newReq.Path = append([]string{}, req.Path...)
newReq.Path = append(newReq.Path, targetID)
target.Receive(&newReq)
} }
} }
} }
snapshot.NodeHealth[id] = NodeState{
QueueSize: len(emitted),
Alive: node.IsAlive(),
}
} }
e.Timeline = append(e.Timeline, snapshot) e.Timeline = append(e.Timeline, snapshot)
@ -271,3 +279,12 @@ func asString(v interface{}) string {
return s return s
} }
func hasVisited(req *Request, nodeID string) bool {
for _, id := range req.Path {
if id == nodeID {
return true
}
}
return false
}

41
internal/simulation/engine_test.go

@ -1,6 +1,7 @@
package simulation package simulation
import ( import (
"fmt"
"os" "os"
"path/filepath" "path/filepath"
"testing" "testing"
@ -87,3 +88,43 @@ func TestComplexSimulationRun(t *testing.T) {
} }
} }
func TestSimulationRunEndToEnd(t *testing.T) {
data, err := os.ReadFile("testdata/simple_design.json")
fmt.Print(data)
if err != nil {
t.Fatalf("Failed to read test data: %v", err)
}
var design design.Design
if err := json.Unmarshal(data, &design); err != nil {
t.Fatalf("Failed to unmarshal JSON: %v", err)
}
engine := NewEngineFromDesign(design, 20, 100) // 20 ticks, 100ms per tick
engine.Run()
if len(engine.Timeline) != 20 {
t.Errorf("Expected 20 timeline entries, got %d", len(engine.Timeline))
}
anyTraffic := false
for _, snapshot := range engine.Timeline {
for _, nodeState := range snapshot.NodeHealth {
if nodeState.QueueSize > 0 {
anyTraffic = true
break
}
}
}
if !anyTraffic {
t.Errorf("Expected at least one node to have non-zero queue size over time")
}
// Optional: check a few expected node IDs
for _, id := range []string{"node-1", "node-2"} {
if _, ok := engine.Nodes[id]; !ok {
t.Errorf("Expected node %s to be present in simulation", id)
}
}
}

Loading…
Cancel
Save