Files
pulse/testBackupHealthFix.html
T
courtmanr@gmail.com cbd6964ac8 fix: improve backup health monitoring and add comprehensive validation
Enhanced backup health status calculations with more accurate age-based
categorization and improved UI filtering. Added comprehensive backup data
validation test suite and ground truth testing framework.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-02 15:20:59 +01:00

153 lines
6.0 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>Test Backup Health Fix</title>
<style>
body { font-family: Arial, sans-serif; padding: 20px; }
.status { margin: 20px 0; padding: 15px; border: 1px solid #ccc; background: #f0f0f0; }
.success { background: #d4edda; border-color: #c3e6cb; }
.error { background: #f8d7da; border-color: #f5c6cb; }
pre { background: #f4f4f4; padding: 10px; overflow-x: auto; }
</style>
</head>
<body>
<h1>Backup Health Fix Test</h1>
<div id="status" class="status">
<h3>Instructions:</h3>
<ol>
<li>Start the Pulse server: <code>npm run dev</code></li>
<li>Open this file in a browser</li>
<li>Open the browser console to see debug logs</li>
<li>Click "Connect to Pulse" below</li>
<li>Look for "[Backup Health Debug]" messages in the console</li>
</ol>
</div>
<button onclick="connectToPulse()">Connect to Pulse</button>
<div id="results"></div>
<script>
async function connectToPulse() {
const statusDiv = document.getElementById('status');
const resultsDiv = document.getElementById('results');
statusDiv.innerHTML = '<p>Connecting to Pulse WebSocket...</p>';
try {
const ws = new WebSocket('ws://localhost:7655');
ws.onopen = () => {
console.log('[Test] Connected to Pulse');
statusDiv.innerHTML = '<p>Connected! Check the browser console for debug logs.</p>';
statusDiv.className = 'status success';
// Request initial data
ws.send(JSON.stringify({ type: 'requestData' }));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'stateUpdate') {
console.log('[Test] Received state update');
analyzeBackupData(data);
}
};
ws.onerror = (error) => {
console.error('[Test] WebSocket error:', error);
statusDiv.innerHTML = '<p>Error connecting to Pulse. Make sure the server is running.</p>';
statusDiv.className = 'status error';
};
ws.onclose = () => {
console.log('[Test] WebSocket closed');
};
} catch (error) {
console.error('[Test] Error:', error);
statusDiv.innerHTML = '<p>Error: ' + error.message + '</p>';
statusDiv.className = 'status error';
}
}
function analyzeBackupData(data) {
const resultsDiv = document.getElementById('results');
// Count guests
const totalGuests = (data.vmsData || []).length + (data.containersData || []).length;
// Analyze backup ages
const now = Date.now() / 1000;
const categories = {
'<24h': 0,
'1-7d': 0,
'7-14d': 0,
'>14d': 0,
'none': 0
};
const allGuests = [...(data.vmsData || []), ...(data.containersData || [])];
allGuests.forEach(guest => {
let mostRecentBackup = null;
// Check PBS backups
if (data.pbs && Array.isArray(data.pbs)) {
data.pbs.forEach(pbsInstance => {
if (pbsInstance.datastores) {
pbsInstance.datastores.forEach(ds => {
if (ds.snapshots) {
ds.snapshots.forEach(snap => {
if (snap['backup-id'] == guest.vmid) {
const backupTime = snap['backup-time'];
if (!mostRecentBackup || backupTime > mostRecentBackup) {
mostRecentBackup = backupTime;
}
}
});
}
});
}
});
}
if (!mostRecentBackup) {
categories.none++;
} else {
const ageSeconds = now - mostRecentBackup;
const ageDays = ageSeconds / (24 * 60 * 60);
if (ageDays < 1) categories['<24h']++;
else if (ageDays <= 7) categories['1-7d']++;
else if (ageDays <= 14) categories['7-14d']++;
else categories['>14d']++;
}
});
// Calculate expected health score
const totalIssues = categories['>14d'] + categories.none;
const expectedHealthScore = Math.round(((totalGuests - totalIssues) / totalGuests) * 100);
const html = `
<div class="status">
<h3>Expected Results:</h3>
<pre>
Total Guests: ${totalGuests}
Health Distribution:
<24h: ${categories['<24h']} guests
1-7d: ${categories['1-7d']} guests
7-14d: ${categories['7-14d']} guests
>14d: ${categories['>14d']} guests
none: ${categories.none} guests
Expected Health Score: ${expectedHealthScore}%
</pre>
<p><strong>Check the browser console for "[Backup Health Debug]" messages to see what the UI is actually calculating.</strong></p>
</div>
`;
resultsDiv.innerHTML = html;
}
</script>
</body>
</html>