feat: mock gateway
This commit is contained in:
449
internal/mock/data.go
Normal file
449
internal/mock/data.go
Normal file
@@ -0,0 +1,449 @@
|
||||
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},
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user