/** * Tests for the Storage Details UI component. * * Tests cover: * - Rendering of storage details accordion * - Accordion toggle behavior * - Filesystem table rendering with warning thresholds * - ZFS and LVM section rendering * - Inspector mode drawer * - Feature flag badges (ZFS, LVM) */ import { describe, it, expect, beforeEach, vi } from 'vitest'; // Mock storage_details data fixtures const mockLinuxDebianStorageDetails = { os_type: 'linux-debian', status: 'ok', collected_at: '2025-12-19T10:00:00Z', commands_run: [ { cmd: 'lsblk', status: 'ok' }, { cmd: 'findmnt', status: 'ok' }, { cmd: 'df', status: 'ok' } ], partial_failures: [], summary: { total_bytes: 500107862016, used_bytes: 125026965504, free_bytes: 349600112640, used_pct: 25.0 }, filesystems: [ { device: '/dev/sda2', fstype: 'ext4', size_bytes: 499570991104, used_bytes: 125026965504, avail_bytes: 349600112640, use_pct: 26, mountpoint: '/' } ], block_devices: [ { name: 'sda', type: 'disk', size: 500107862016, model: 'Samsung SSD 860' } ], lvm: { pvs: [], vgs: [], lvs: [] }, zfs: { pools: [], datasets: [] }, feature_flags: { has_lvm: false, has_zfs: false, has_lsblk: true, has_findmnt: true } }; const mockTrueNASStorageDetails = { os_type: 'truenas-core', status: 'ok', collected_at: '2025-12-19T10:00:00Z', commands_run: [ { cmd: 'df', status: 'ok' }, { cmd: 'zpool list', status: 'ok' }, { cmd: 'zfs list', status: 'ok' } ], partial_failures: [], summary: { total_bytes: 4000787030016, used_bytes: 2800550921011, free_bytes: 1200236109005, used_pct: 70.0 }, filesystems: [], block_devices: [], lvm: { pvs: [], vgs: [], lvs: [] }, zfs: { pools: [ { name: 'tank', size_bytes: 4000787030016, alloc_bytes: 2800550921011, free_bytes: 1200236109005, cap_pct: 70, health: 'ONLINE' } ], datasets: [ { name: 'tank/apps', used_bytes: 107374182400, avail_bytes: 1200236109005, mountpoint: '/mnt/tank/apps', type: 'filesystem' } ] }, feature_flags: { has_lvm: false, has_zfs: true, has_lsblk: false, has_findmnt: false } }; const mockHighUsageStorageDetails = { os_type: 'linux-debian', status: 'ok', collected_at: '2025-12-19T10:00:00Z', commands_run: [{ cmd: 'df', status: 'ok' }], partial_failures: [], summary: { total_bytes: 100000000000, used_bytes: 92000000000, free_bytes: 8000000000, used_pct: 92.0 }, filesystems: [ { device: '/dev/sda1', fstype: 'ext4', size_bytes: 100000000000, used_bytes: 92000000000, avail_bytes: 8000000000, use_pct: 92, mountpoint: '/' } ], block_devices: [], lvm: { pvs: [], vgs: [], lvs: [] }, zfs: { pools: [], datasets: [] }, feature_flags: { has_lvm: false, has_zfs: false, has_lsblk: true, has_findmnt: true } }; describe('Storage Details UI Component', () => { describe('renderStorageDetailsSection', () => { it('should return empty string when storage_details is null', () => { const metrics = { storage_details: null }; const result = renderStorageDetailsSection(metrics, 'host-1'); expect(result).toBe(''); }); it('should return empty string when storage_details is undefined', () => { const metrics = {}; const result = renderStorageDetailsSection(metrics, 'host-1'); expect(result).toBe(''); }); it('should render accordion header with correct title', () => { const metrics = { storage_details: mockLinuxDebianStorageDetails }; const result = renderStorageDetailsSection(metrics, 'host-1'); expect(result).toContain('Stockage détaillé'); expect(result).toContain('fa-database'); }); it('should show status badge', () => { const metrics = { storage_details: mockLinuxDebianStorageDetails }; const result = renderStorageDetailsSection(metrics, 'host-1'); expect(result).toContain('OK'); }); it('should show feature chips for ZFS', () => { const metrics = { storage_details: mockTrueNASStorageDetails }; const result = renderStorageDetailsSection(metrics, 'host-1'); expect(result).toContain('ZFS'); }); it('should show usage percentage in summary', () => { const metrics = { storage_details: mockLinuxDebianStorageDetails }; const result = renderStorageDetailsSection(metrics, 'host-1'); expect(result).toContain('25%'); }); }); describe('Filesystem Table', () => { it('should render filesystem table with columns', () => { const html = renderFilesystemsTable(mockLinuxDebianStorageDetails.filesystems); expect(html).toContain('Mount'); expect(html).toContain('Device'); expect(html).toContain('FS'); expect(html).toContain('Taille'); }); it('should show mountpoint in table', () => { const html = renderFilesystemsTable(mockLinuxDebianStorageDetails.filesystems); expect(html).toContain('/'); }); it('should highlight high usage filesystems', () => { const html = renderFilesystemsTable(mockHighUsageStorageDetails.filesystems); expect(html).toContain('text-red-400'); expect(html).toContain('92%'); }); it('should filter out virtual filesystems', () => { const filesystems = [ { device: '/dev/sda1', mountpoint: '/', use_pct: 50 }, { device: 'tmpfs', mountpoint: '/run', use_pct: 10 }, { device: 'devtmpfs', mountpoint: '/dev', use_pct: 0 } ]; const html = renderFilesystemsTable(filesystems); expect(html).not.toContain('/run'); expect(html).not.toContain('/dev'); }); }); describe('ZFS Section', () => { it('should render ZFS pools', () => { const html = renderZfsSection(mockTrueNASStorageDetails.zfs); expect(html).toContain('tank'); expect(html).toContain('fa-water'); }); it('should show pool health status', () => { const html = renderZfsSection(mockTrueNASStorageDetails.zfs); expect(html).toContain('ONLINE'); expect(html).toContain('text-green-400'); }); it('should show pool usage percentage', () => { const html = renderZfsSection(mockTrueNASStorageDetails.zfs); expect(html).toContain('70%'); }); it('should render datasets list', () => { const html = renderZfsSection(mockTrueNASStorageDetails.zfs); expect(html).toContain('tank/apps'); }); it('should return empty string when no ZFS', () => { const html = renderZfsSection({ pools: [], datasets: [] }); expect(html).toBe(''); }); }); describe('Inspector Mode', () => { it('should show inspector button', () => { const metrics = { storage_details: mockLinuxDebianStorageDetails }; const result = renderStorageDetailsSection(metrics, 'host-1'); expect(result).toContain('fa-info-circle'); expect(result).toContain('toggleStorageInspector'); }); it('should show OS type in inspector', () => { const html = renderInspectorDrawer(mockLinuxDebianStorageDetails, 'host-1', true); expect(html).toContain('linux-debian'); expect(html).toContain('OS détecté'); }); it('should show commands run in inspector', () => { const html = renderInspectorDrawer(mockLinuxDebianStorageDetails, 'host-1', true); expect(html).toContain('lsblk'); expect(html).toContain('findmnt'); expect(html).toContain('df'); }); it('should show collection timestamp', () => { const html = renderInspectorDrawer(mockLinuxDebianStorageDetails, 'host-1', true); expect(html).toContain('Collecté le'); }); }); describe('Warning Thresholds', () => { it('should apply warning class for usage >= 75%', () => { const fs = { use_pct: 80, mountpoint: '/var' }; const colorClass = getPctColor(fs.use_pct); expect(colorClass).toBe('bg-yellow-500'); }); it('should apply critical class for usage >= 90%', () => { const fs = { use_pct: 95, mountpoint: '/' }; const colorClass = getPctColor(fs.use_pct); expect(colorClass).toBe('bg-red-500'); }); it('should apply normal class for usage < 75%', () => { const fs = { use_pct: 50, mountpoint: '/home' }; const colorClass = getPctColor(fs.use_pct); expect(colorClass).toBe('bg-green-500'); }); }); describe('Byte Formatting', () => { it('should format bytes to GB', () => { const result = formatBytes(107374182400); // 100 GB expect(result).toBe('100 GB'); }); it('should format bytes to TB for large values', () => { const result = formatBytes(1099511627776); // 1 TB expect(result).toBe('1.0 TB'); }); it('should return empty string for zero', () => { const result = formatBytes(0); expect(result).toBe(''); }); it('should handle small values', () => { const result = formatBytes(1073741824); // 1 GB expect(result).toBe('1.0 GB'); }); }); }); // Helper functions to test (would be extracted from main.js in real implementation) function renderStorageDetailsSection(metrics, hostId) { const storageDetails = metrics?.storage_details; if (!storageDetails) return ''; const status = storageDetails.status || 'unknown'; const flags = storageDetails.feature_flags || {}; const summary = storageDetails.summary || {}; const chips = []; if (flags.has_zfs) chips.push('ZFS'); if (flags.has_lvm) chips.push('LVM'); const usedPct = summary.used_pct ? Number(summary.used_pct).toFixed(0) : null; const statusBadge = status === 'ok' ? 'bg-green-500/20 text-green-400' : status === 'partial' ? 'bg-yellow-500/20 text-yellow-400' : 'bg-red-500/20 text-red-400'; const statusText = status === 'ok' ? 'OK' : status === 'partial' ? 'Partiel' : 'Erreur'; return `
| Mount | Device | FS | Taille |
|---|