You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
2.9 KiB
130 lines
2.9 KiB
package simulation |
|
|
|
import ( |
|
"fmt" |
|
"os" |
|
"path/filepath" |
|
"testing" |
|
|
|
"encoding/json" |
|
"systemdesigngame/internal/design" |
|
) |
|
|
|
func TestNewEngineFromDesign(t *testing.T) { |
|
designInput := &design.Design{ |
|
Nodes: []design.Node{ |
|
{ |
|
ID: "web1", |
|
Type: "webserver", |
|
Props: map[string]interface{}{ |
|
"cpu": float64(2), |
|
"ramGb": float64(4), |
|
"rpsCapacity": float64(100), |
|
"monthlyCostUsd": float64(20), |
|
}, |
|
}, |
|
{ |
|
ID: "cache1", |
|
Type: "cache", |
|
Props: map[string]interface{}{ |
|
"label": "L1 Cache", |
|
"cacheTTL": float64(60), |
|
"maxEntries": float64(1000), |
|
"evictionPolicy": "LRU", |
|
}, |
|
}, |
|
}, |
|
Connections: []design.Connection{ |
|
{ |
|
Source: "web1", |
|
Target: "cache1", |
|
}, |
|
}, |
|
} |
|
|
|
engine := NewEngineFromDesign(*designInput, 10, 100) |
|
|
|
if len(engine.Nodes) != 2 { |
|
t.Fatalf("expected 2 nodes, got %d", len(engine.Nodes)) |
|
} |
|
|
|
if len(engine.Nodes["web1"].GetTargets()) != 1 { |
|
t.Fatalf("expected web1 to have 1 target, got %d", len(engine.Nodes["web1"].GetTargets())) |
|
} |
|
|
|
if engine.Nodes["web1"].GetTargets()[0] != "cache1" { |
|
t.Fatalf("expected web1 target to be cache1") |
|
} |
|
} |
|
|
|
func TestComplexSimulationRun(t *testing.T) { |
|
filePath := filepath.Join("testdata", "complex_design.json") |
|
data, err := os.ReadFile(filePath) |
|
if err != nil { |
|
t.Fatalf("Failed to read JSON file: %v", err) |
|
} |
|
|
|
var d design.Design |
|
if err := json.Unmarshal([]byte(data), &d); err != nil { |
|
t.Fatalf("Failed to unmarshal JSON: %v", err) |
|
} |
|
|
|
engine := NewEngineFromDesign(d, 10, 100) |
|
if engine == nil { |
|
t.Fatal("Engine should not be nil") |
|
} |
|
|
|
engine.Run() |
|
|
|
if len(engine.Timeline) == 0 { |
|
t.Fatal("Expected timeline snapshots after Run, got none") |
|
} |
|
|
|
// Optional: check that some nodes received or emitted requests |
|
for id, node := range engine.Nodes { |
|
if len(node.Emit()) > 0 { |
|
t.Logf("Node %s has activity", id) |
|
} |
|
} |
|
} |
|
|
|
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) |
|
} |
|
} |
|
}
|
|
|