Files
tyto/backend/internal/collectors/memory_test.go
vikingowl f4dbc55851 feat: add dashboard customization, alerts, PWA, and mobile support
Dashboard Editor & Layout:
- Full-screen visual editor for reorganizing cards
- Drag-and-drop cards between sections
- Toggle card visibility with persistence to localStorage
- Reset to default layout option

Alerts System:
- Threshold-based alerts for CPU, memory, temperature, disk, GPU
- Alert manager with duration requirements
- AlertsCard component with settings UI
- API endpoints for alerts CRUD

New Collectors:
- Docker container monitoring with parallel stats fetching
- Systemd service status via D-Bus
- Historical metrics storage (1 hour at 1s intervals)

PWA Support:
- Service worker with offline caching
- Web app manifest with SVG icons
- iOS PWA meta tags

Mobile Responsive:
- Collapsible hamburger menu on mobile
- Adaptive grid layouts for all screen sizes
- Touch-friendly hover states
- Safe area insets for notched devices

UI Enhancements:
- Light/dark theme toggle with persistence
- Keyboard shortcuts (T=theme, R=refresh, ?=help)
- Per-process expandable details in ProcessesCard
- Sparkline charts for historical data

Performance Fixes:
- Buffered SSE channels to prevent blocking
- Parallel Docker stats collection with timeout
- D-Bus timeout for systemd collector

Tests:
- Unit tests for CPU, memory, network collectors
- Alert manager tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 05:35:28 +01:00

108 lines
2.7 KiB
Go

package collectors
import (
"os"
"path/filepath"
"testing"
)
func TestMemoryCollector(t *testing.T) {
tmpDir := t.TempDir()
// Create mock /proc/meminfo
meminfoContent := `MemTotal: 32768000 kB
MemFree: 10240000 kB
MemAvailable: 20480000 kB
Buffers: 1024000 kB
Cached: 5120000 kB
SwapCached: 0 kB
Active: 8192000 kB
Inactive: 4096000 kB
SwapTotal: 8192000 kB
SwapFree: 6144000 kB
`
if err := os.WriteFile(filepath.Join(tmpDir, "meminfo"), []byte(meminfoContent), 0644); err != nil {
t.Fatal(err)
}
collector := NewMemoryCollector(tmpDir)
stats, err := collector.Collect()
if err != nil {
t.Fatalf("Collect failed: %v", err)
}
// Verify values (kB to bytes)
expectedTotal := uint64(32768000 * 1024)
if stats.Total != expectedTotal {
t.Errorf("Expected Total=%d, got %d", expectedTotal, stats.Total)
}
expectedAvailable := uint64(20480000 * 1024)
if stats.Available != expectedAvailable {
t.Errorf("Expected Available=%d, got %d", expectedAvailable, stats.Available)
}
expectedCached := uint64(5120000 * 1024)
if stats.Cached != expectedCached {
t.Errorf("Expected Cached=%d, got %d", expectedCached, stats.Cached)
}
expectedSwapTotal := uint64(8192000 * 1024)
if stats.SwapTotal != expectedSwapTotal {
t.Errorf("Expected SwapTotal=%d, got %d", expectedSwapTotal, stats.SwapTotal)
}
expectedSwapUsed := uint64((8192000 - 6144000) * 1024)
if stats.SwapUsed != expectedSwapUsed {
t.Errorf("Expected SwapUsed=%d, got %d", expectedSwapUsed, stats.SwapUsed)
}
// Used should be Total - Available
expectedUsed := expectedTotal - expectedAvailable
if stats.Used != expectedUsed {
t.Errorf("Expected Used=%d, got %d", expectedUsed, stats.Used)
}
}
func TestMemoryCollector_MissingFile(t *testing.T) {
tmpDir := t.TempDir()
collector := NewMemoryCollector(tmpDir)
stats, err := collector.Collect()
// Should return error or empty stats
if err == nil && stats.Total == 0 {
// This is acceptable - empty stats on missing file
return
}
if err != nil {
// This is also acceptable
return
}
t.Error("Expected either error or zero Total for missing meminfo")
}
func TestMemoryCollector_MalformedFile(t *testing.T) {
tmpDir := t.TempDir()
// Create malformed meminfo
meminfoContent := `MemTotal: invalid
MemFree: also invalid
`
if err := os.WriteFile(filepath.Join(tmpDir, "meminfo"), []byte(meminfoContent), 0644); err != nil {
t.Fatal(err)
}
collector := NewMemoryCollector(tmpDir)
stats, err := collector.Collect()
// Should handle gracefully
if err != nil {
return // Error is acceptable
}
// If no error, values should be zero (failed to parse)
if stats.Total != 0 {
t.Errorf("Expected Total=0 for malformed input, got %d", stats.Total)
}
}