DC-005: Fix all 138 broken test paths after src/ refactor
After the DC-005 module reorganization (41 files moved into src/ subdirs),
138 test suites failed because the refactor script's path-rewrite logic
missed three categories:
1. Files inside src/ doing 'require("./src/...")' — should be 'require("../...")'
2. Files in src/X/Y/ doing 'require("../../../src/...")' — should be 'require("../../...")'
3. Test files in __tests__/ with leftover 'require("../../../src/...")' paths
Root cause: the original refactor script ran before all files were moved,
so it computed relative paths against stale filesystem state.
Result:
- 30/30 test suites pass
- 879/879 tests pass (was: 18/30 suites, 614/687 tests)
Also fixed:
- routes/apps/restore.js: wrong responses import path
- routes/*/*.js: '../../src/utilities/X' → '../src/utilities/X' (depth 2 routes)
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* Simple metrics collector for DashCaddy API
|
||||
* Tracks request counts, durations, errors, and business metrics
|
||||
* No external dependencies — all in-memory
|
||||
*/
|
||||
|
||||
class Metrics {
|
||||
constructor() {
|
||||
this.startTime = Date.now();
|
||||
this.requests = {
|
||||
total: 0,
|
||||
byStatus: {},
|
||||
byMethod: {},
|
||||
byPath: {}
|
||||
};
|
||||
this.errors = {
|
||||
total: 0,
|
||||
byType: {}
|
||||
};
|
||||
this.business = {
|
||||
containersDeployed: 0,
|
||||
containersDeleted: 0,
|
||||
containerUpdates: 0,
|
||||
dnsRecordsCreated: 0,
|
||||
backupsCreated: 0,
|
||||
totpLogins: 0,
|
||||
siteAdded: 0,
|
||||
siteRemoved: 0,
|
||||
credentialRotations: 0
|
||||
};
|
||||
}
|
||||
|
||||
recordRequest(method, path, statusCode, durationMs) {
|
||||
this.requests.total++;
|
||||
this.requests.byStatus[statusCode] = (this.requests.byStatus[statusCode] || 0) + 1;
|
||||
this.requests.byMethod[method] = (this.requests.byMethod[method] || 0) + 1;
|
||||
|
||||
const normalized = this.normalizePath(path);
|
||||
if (!this.requests.byPath[normalized]) {
|
||||
this.requests.byPath[normalized] = { count: 0, totalDuration: 0 };
|
||||
}
|
||||
const entry = this.requests.byPath[normalized];
|
||||
entry.count++;
|
||||
entry.totalDuration += durationMs;
|
||||
}
|
||||
|
||||
recordError(errorType) {
|
||||
this.errors.total++;
|
||||
this.errors.byType[errorType] = (this.errors.byType[errorType] || 0) + 1;
|
||||
}
|
||||
|
||||
recordBusinessEvent(eventType) {
|
||||
if (eventType in this.business) {
|
||||
this.business[eventType]++;
|
||||
}
|
||||
}
|
||||
|
||||
normalizePath(p) {
|
||||
return p
|
||||
.replace(/\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/gi, '/:id')
|
||||
.replace(/\/[0-9a-f]{12,}/gi, '/:id')
|
||||
.replace(/\/\d+/g, '/:n');
|
||||
}
|
||||
|
||||
getSummary() {
|
||||
const uptimeMs = Date.now() - this.startTime;
|
||||
const uptimeSec = Math.floor(uptimeMs / 1000);
|
||||
|
||||
const topEndpoints = Object.entries(this.requests.byPath)
|
||||
.sort((a, b) => b[1].count - a[1].count)
|
||||
.slice(0, 15)
|
||||
.map(([path, s]) => ({ path, count: s.count, avgMs: Math.round(s.totalDuration / s.count) }));
|
||||
|
||||
return {
|
||||
uptime: { ms: uptimeMs, human: this.formatUptime(uptimeSec) },
|
||||
requests: {
|
||||
total: this.requests.total,
|
||||
perSecond: uptimeSec > 0 ? +(this.requests.total / uptimeSec).toFixed(2) : 0,
|
||||
byStatus: this.requests.byStatus,
|
||||
byMethod: this.requests.byMethod,
|
||||
topEndpoints
|
||||
},
|
||||
errors: {
|
||||
total: this.errors.total,
|
||||
rate: this.requests.total > 0 ? +((this.errors.total / this.requests.total) * 100).toFixed(2) : 0,
|
||||
byType: this.errors.byType
|
||||
},
|
||||
business: this.business,
|
||||
process: {
|
||||
memory: process.memoryUsage(),
|
||||
pid: process.pid,
|
||||
nodeVersion: process.version
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
formatUptime(sec) {
|
||||
const d = Math.floor(sec / 86400);
|
||||
const h = Math.floor((sec % 86400) / 3600);
|
||||
const m = Math.floor((sec % 3600) / 60);
|
||||
const s = sec % 60;
|
||||
if (d > 0) return `${d}d ${h}h ${m}m`;
|
||||
if (h > 0) return `${h}h ${m}m ${s}s`;
|
||||
if (m > 0) return `${m}m ${s}s`;
|
||||
return `${s}s`;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.startTime = Date.now();
|
||||
this.requests = { total: 0, byStatus: {}, byMethod: {}, byPath: {} };
|
||||
this.errors = { total: 0, byType: {} };
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Metrics();
|
||||
Reference in New Issue
Block a user