Files
spore-gateway/internal/mock/data.go
Patrick Balsiger 3c3fb886a3 feat: mock gateway
2025-10-24 14:24:14 +02:00

450 lines
12 KiB
Go

package mock
import (
"fmt"
"math/rand"
"time"
"spore-gateway/pkg/client"
"spore-gateway/pkg/registry"
)
// GenerateMockClusterMembers generates mock cluster member data
func GenerateMockClusterMembers(nodes map[string]*NodeInfo) []client.ClusterMember {
members := make([]client.ClusterMember, 0, len(nodes))
for _, node := range nodes {
member := client.ClusterMember{
IP: node.IP,
Hostname: node.Hostname,
Status: string(node.Status),
Latency: node.Latency,
LastSeen: node.LastSeen.Unix(),
Labels: node.Labels,
Resources: map[string]interface{}{
"freeHeap": 32768 + rand.Intn(32768),
"cpuFreqMHz": 80 + rand.Intn(160),
"flashChipSize": 4194304,
},
}
members = append(members, member)
}
return members
}
// GenerateMockTaskStatus generates mock task status data
func GenerateMockTaskStatus() *client.TaskStatusResponse {
tasks := []client.TaskInfo{
{
Name: "HeartbeatTask",
Interval: 5000,
Enabled: true,
Running: true,
AutoStart: true,
},
{
Name: "SensorReadTask",
Interval: 10000,
Enabled: true,
Running: true,
AutoStart: true,
},
{
Name: "StatusUpdateTask",
Interval: 30000,
Enabled: true,
Running: false,
AutoStart: false,
},
{
Name: "CleanupTask",
Interval: 60000,
Enabled: false,
Running: false,
AutoStart: false,
},
}
activeTasks := 0
for _, task := range tasks {
if task.Running {
activeTasks++
}
}
return &client.TaskStatusResponse{
Summary: client.TaskSummary{
TotalTasks: len(tasks),
ActiveTasks: activeTasks,
},
Tasks: tasks,
System: client.SystemInfo{
FreeHeap: 32768 + int64(rand.Intn(32768)),
Uptime: int64(time.Now().Unix() - 3600*24), // 24 hours uptime
},
}
}
// GenerateMockSystemStatus generates mock system status data
func GenerateMockSystemStatus(labels map[string]string) *client.SystemStatusResponse {
return &client.SystemStatusResponse{
FreeHeap: 32768 + int64(rand.Intn(32768)),
ChipID: int64(rand.Int31()),
SDKVersion: "3.1.0",
CPUFreqMHz: 80 + rand.Intn(160),
FlashChipSize: 4194304,
Labels: labels,
}
}
// GenerateMockCapabilities generates mock API endpoint capabilities
func GenerateMockCapabilities() *client.CapabilitiesResponse {
return &client.CapabilitiesResponse{
Endpoints: []client.EndpointInfo{
{
URI: "/api/node/status",
Method: "GET",
Parameters: []client.ParameterInfo{
{
Name: "detailed",
Type: "boolean",
Required: false,
Description: "Include detailed system information",
Location: "query",
Default: "false",
},
},
},
{
URI: "/api/cluster/members",
Method: "GET",
Parameters: []client.ParameterInfo{},
},
{
URI: "/api/tasks/status",
Method: "GET",
Parameters: []client.ParameterInfo{},
},
{
URI: "/api/node/update",
Method: "POST",
Parameters: []client.ParameterInfo{
{
Name: "firmware",
Type: "file",
Required: true,
Description: "Firmware binary file",
Location: "body",
},
},
},
{
URI: "/api/node/config",
Method: "POST",
Parameters: []client.ParameterInfo{
{
Name: "labels",
Type: "json",
Required: true,
Description: "Node labels in JSON format",
Location: "body",
},
},
},
{
URI: "/api/sensors/read",
Method: "GET",
Parameters: []client.ParameterInfo{
{
Name: "sensor",
Type: "string",
Required: false,
Description: "Specific sensor to read",
Location: "query",
Values: []string{"temperature", "humidity", "pressure"},
},
},
},
},
}
}
// GenerateMockFirmwareList generates mock firmware registry data
func GenerateMockFirmwareList() []registry.GroupedFirmware {
return []registry.GroupedFirmware{
{
Name: "spore-firmware",
Firmware: []registry.FirmwareRecord{
{
Name: "spore-firmware",
Version: "1.0.0",
Size: 524288,
Labels: map[string]string{
"stable": "true",
"env": "production",
},
Path: "/firmware/spore-firmware/1.0.0",
},
{
Name: "spore-firmware",
Version: "1.1.0",
Size: 548864,
Labels: map[string]string{
"stable": "true",
"env": "production",
},
Path: "/firmware/spore-firmware/1.1.0",
},
{
Name: "spore-firmware",
Version: "1.2.0",
Size: 573440,
Labels: map[string]string{
"stable": "false",
"env": "beta",
},
Path: "/firmware/spore-firmware/1.2.0",
},
},
},
{
Name: "sensor-firmware",
Firmware: []registry.FirmwareRecord{
{
Name: "sensor-firmware",
Version: "2.0.0",
Size: 262144,
Labels: map[string]string{
"stable": "true",
"type": "sensor",
},
Path: "/firmware/sensor-firmware/2.0.0",
},
{
Name: "sensor-firmware",
Version: "2.1.0",
Size: 286720,
Labels: map[string]string{
"stable": "true",
"type": "sensor",
},
Path: "/firmware/sensor-firmware/2.1.0",
},
},
},
}
}
// GenerateMockFirmwareBinary generates mock firmware binary data
func GenerateMockFirmwareBinary(size int) []byte {
// Generate some pseudo-random but deterministic binary data
data := make([]byte, size)
for i := range data {
data[i] = byte(i % 256)
}
return data
}
// NodeInfo is an alias to avoid import cycle
type NodeInfo struct {
IP string
Hostname string
Status string
Latency int64
LastSeen time.Time
Labels map[string]string
}
// ResourceMetrics represents resource usage metrics for a node
type ResourceMetrics struct {
Timestamp int64 `json:"timestamp"`
NodeIP string `json:"node_ip"`
Hostname string `json:"hostname"`
CPU CPUMetrics `json:"cpu"`
Memory MemoryMetrics `json:"memory"`
Network NetworkMetrics `json:"network"`
Flash FlashMetrics `json:"flash"`
Labels map[string]string `json:"labels"`
}
// CPUMetrics represents CPU usage metrics
type CPUMetrics struct {
Frequency int `json:"frequency_mhz"`
UsagePercent float64 `json:"usage_percent"`
Temperature float64 `json:"temperature_c,omitempty"`
}
// MemoryMetrics represents memory usage metrics
type MemoryMetrics struct {
Total int64 `json:"total_bytes"`
Free int64 `json:"free_bytes"`
Used int64 `json:"used_bytes"`
UsagePercent float64 `json:"usage_percent"`
}
// NetworkMetrics represents network usage metrics
type NetworkMetrics struct {
BytesSent int64 `json:"bytes_sent"`
BytesReceived int64 `json:"bytes_received"`
PacketsSent int64 `json:"packets_sent"`
PacketsRecv int64 `json:"packets_received"`
RSSI int `json:"rssi_dbm,omitempty"`
SignalQuality float64 `json:"signal_quality_percent,omitempty"`
}
// FlashMetrics represents flash storage metrics
type FlashMetrics struct {
Total int64 `json:"total_bytes"`
Used int64 `json:"used_bytes"`
Free int64 `json:"free_bytes"`
UsagePercent float64 `json:"usage_percent"`
}
// MonitoringResourcesResponse represents the monitoring resources endpoint response
type MonitoringResourcesResponse struct {
Timestamp string `json:"timestamp"`
Nodes []ResourceMetrics `json:"nodes"`
Summary ResourceSummary `json:"summary"`
}
// ResourceSummary provides aggregate statistics across all nodes
type ResourceSummary struct {
TotalNodes int `json:"total_nodes"`
AvgCPUUsage float64 `json:"avg_cpu_usage_percent"`
AvgMemoryUsage float64 `json:"avg_memory_usage_percent"`
AvgFlashUsage float64 `json:"avg_flash_usage_percent"`
TotalBytesSent int64 `json:"total_bytes_sent"`
TotalBytesRecv int64 `json:"total_bytes_received"`
}
// GenerateMockMonitoringResources generates meaningful mock monitoring data for all nodes
func GenerateMockMonitoringResources(nodes map[string]*NodeInfo) *MonitoringResourcesResponse {
now := time.Now()
metrics := make([]ResourceMetrics, 0, len(nodes))
var totalCPU, totalMemoryPercent, totalFlash float64
var totalBytesSent, totalBytesRecv int64
for _, node := range nodes {
// Generate realistic resource usage based on node characteristics
cpuFreq := 80 + rand.Intn(160)
cpuUsage := 15.0 + rand.Float64()*45.0 // 15-60% usage
// Memory metrics
nodeMemoryTotal := int64(65536 + rand.Intn(65536)) // 64-128KB
freeMemory := int64(32768 + rand.Intn(32768)) // 32-64KB free
usedMemory := nodeMemoryTotal - freeMemory
memoryUsagePercent := float64(usedMemory) / float64(nodeMemoryTotal) * 100
// Flash metrics
flashTotal := int64(4194304) // 4MB
flashUsed := int64(1048576 + rand.Intn(2097152)) // 1-3MB used
flashFree := flashTotal - flashUsed
flashUsagePercent := float64(flashUsed) / float64(flashTotal) * 100
// Network metrics (simulating accumulated traffic)
bytesSent := int64(1000000 + rand.Intn(5000000)) // 1-6MB
bytesRecv := int64(2000000 + rand.Intn(8000000)) // 2-10MB
packetsSent := int64(10000 + rand.Intn(50000))
packetsRecv := int64(15000 + rand.Intn(75000))
// WiFi signal metrics
rssi := -30 - rand.Intn(60) // -30 to -90 dBm
signalQuality := float64(100+rssi+90) / 60.0 * 100 // Convert RSSI to quality percentage
if signalQuality < 0 {
signalQuality = 0
} else if signalQuality > 100 {
signalQuality = 100
}
metric := ResourceMetrics{
Timestamp: now.Unix(),
NodeIP: node.IP,
Hostname: node.Hostname,
CPU: CPUMetrics{
Frequency: cpuFreq,
UsagePercent: cpuUsage,
Temperature: 45.0 + rand.Float64()*20.0, // 45-65°C
},
Memory: MemoryMetrics{
Total: nodeMemoryTotal,
Free: freeMemory,
Used: usedMemory,
UsagePercent: memoryUsagePercent,
},
Network: NetworkMetrics{
BytesSent: bytesSent,
BytesReceived: bytesRecv,
PacketsSent: packetsSent,
PacketsRecv: packetsRecv,
RSSI: rssi,
SignalQuality: signalQuality,
},
Flash: FlashMetrics{
Total: flashTotal,
Used: flashUsed,
Free: flashFree,
UsagePercent: flashUsagePercent,
},
Labels: node.Labels,
}
metrics = append(metrics, metric)
// Accumulate for summary
totalCPU += cpuUsage
totalMemoryPercent += memoryUsagePercent
totalFlash += flashUsagePercent
totalBytesSent += bytesSent
totalBytesRecv += bytesRecv
}
// Calculate averages
nodeCount := len(nodes)
var avgCPU, avgMemory, avgFlash float64
if nodeCount > 0 {
avgCPU = totalCPU / float64(nodeCount)
avgMemory = totalMemoryPercent / float64(nodeCount)
avgFlash = totalFlash / float64(nodeCount)
}
return &MonitoringResourcesResponse{
Timestamp: now.Format(time.RFC3339),
Nodes: metrics,
Summary: ResourceSummary{
TotalNodes: nodeCount,
AvgCPUUsage: avgCPU,
AvgMemoryUsage: avgMemory,
AvgFlashUsage: avgFlash,
TotalBytesSent: totalBytesSent,
TotalBytesRecv: totalBytesRecv,
},
}
}
// GenerateMockProxyResponse generates a mock response for proxy calls
func GenerateMockProxyResponse(method, uri string) map[string]interface{} {
switch uri {
case "/api/sensors/read":
return map[string]interface{}{
"temperature": 22.5 + rand.Float64()*5,
"humidity": 45.0 + rand.Float64()*20,
"pressure": 1013.0 + rand.Float64()*10,
"timestamp": time.Now().Unix(),
}
case "/api/led/control":
return map[string]interface{}{
"status": "success",
"message": "LED state updated",
"state": "on",
}
default:
return map[string]interface{}{
"status": "success",
"message": fmt.Sprintf("Mock response for %s %s", method, uri),
"data": map[string]interface{}{"mock": true},
}
}
}