Files
Deep-Package-Inspection/test/architecture_test.js

119 lines
8.2 KiB
JavaScript

// test/architecture_test.js
// TDD: Verifikasi arsitektur 2 container BackOne DPI
const fs = require('fs');
const path = require('path');
const ROOT = path.join(__dirname, '..');
function readFile(relPath) {
return fs.readFileSync(path.join(ROOT, relPath), 'utf8');
}
let passed = 0;
let failed = 0;
function test(name, condition, detail = '') {
if (condition) {
console.log(` ✓ PASS: ${name}`);
passed++;
} else {
console.log(` ✗ FAIL: ${name}${detail ? ' — ' + detail : ''}`);
failed++;
}
}
console.log('\n══════════════════════════════════════════════════════');
console.log(' BackOne DPI — TDD Architecture Verification');
console.log('══════════════════════════════════════════════════════\n');
// ─── TEST GROUP 1: Backend bersih dari SQLite/Netify API ───────────────────
console.log('[GROUP 1] Backend — Isolasi dari SQLite & Netify API');
const serverCode = readFile('backend/server.js');
const dashCode = readFile('backend/routes/dashboard.js') +
readFile('backend/routes/dashboard/helpers.js') +
readFile('backend/routes/dashboard/summary.js') +
readFile('backend/routes/dashboard/apps.js') +
readFile('backend/routes/dashboard/devices.js') +
readFile('backend/routes/dashboard/flows.js') +
readFile('backend/routes/dashboard/threats.js') +
readFile('backend/routes/dashboard/geo.js') +
readFile('backend/routes/dashboard/tls.js') +
readFile('backend/routes/dashboard/telemetry.js') +
readFile('backend/routes/dashboard/events.js') +
readFile('backend/routes/dashboard/agents.js');
const authCode = readFile('backend/routes/auth.js');
test('server.js tidak memanggil ingestionService', !serverCode.includes('ingestionService'));
test('server.js tidak import database.js (SQLite)', !serverCode.includes("require('./database')") && !serverCode.includes("require('../database')"));
test('server.js tidak memanggil startScheduler', !serverCode.includes('startScheduler'));
test('dashboard.js tidak import database.js', !dashCode.includes("require('../database')"));
test('dashboard.js tidak import scheduler.js lama', !dashCode.includes("require('../scheduler')"));
test('dashboard.js tidak memanggil netify.ai API', !dashCode.includes('netify.ai') && !dashCode.includes('fetchTopApps'));
test('auth.js tidak import database.js', !authCode.includes("require('../database')"));
test('auth.js tidak menggunakan better-sqlite3', !authCode.includes('better-sqlite3') && !authCode.includes('getDB()'));
console.log('');
// ─── TEST GROUP 2: Multi-tenant isolation ──────────────────────────────────
console.log('[GROUP 2] Dashboard — Multi-Tenant Agent UUID Isolation');
test('dashboard.js punya getBaseFilter() helper', dashCode.includes('function getBaseFilter'));
test('getBaseFilter menambahkan agent_uuid filter', dashCode.includes('filter.agent_uuid = req.user.agent_uuid'));
test('getBaseFilter menambahkan site_uuid filter', dashCode.includes('filter.site_uuid = req.user.site_uuid') || dashCode.includes('filter.site_uuid ='));
test('/apps pakai getBaseFilter', dashCode.includes("router.get('/apps'") && dashCode.includes('getBaseFilter'));
test('/devices pakai getBaseFilter', dashCode.includes("router.get('/devices'") && dashCode.includes('getBaseFilter'));
test('/flows pakai getBaseFilter', dashCode.includes("router.get('/flows'") && dashCode.includes('getBaseFilter'));
test('/threats pakai getBaseFilter', dashCode.includes("router.get('/threats'") && dashCode.includes('getBaseFilter'));
test('/summary pakai getBaseFilter', dashCode.includes("router.get('/summary'") && dashCode.includes('getBaseFilter'));
test('/agents endpoint hanya untuk SUPER_ADMIN', dashCode.includes("SUPER_ADMIN") && dashCode.includes("router.get('/agents'"));
console.log('');
// ─── TEST GROUP 3: Proxy 2 mode ────────────────────────────────────────────
console.log('[GROUP 3] Proxy — 2 Mode Pengambilan Data');
const schedulerCode = readFile('proxy/scheduler.js');
const collectorCode = readFile('proxy/collector.js');
test('scheduler.js membaca PROXY_COLLECT_MODE env', schedulerCode.includes('PROXY_COLLECT_MODE'));
test('scheduler.js membaca PROXY_AGENT_UUID env', schedulerCode.includes('PROXY_AGENT_UUID'));
test("scheduler.js mendukung mode 'all'", schedulerCode.includes("COLLECT_MODE === 'agent'"));
test('collector.js export collectAllAgents()', collectorCode.includes('collectAllAgents'));
test('collector.js export collectSpecificAgent()', collectorCode.includes('collectSpecificAgent'));
test('collector.js tag data dengan agent_uuid', collectorCode.includes('agent_uuid: agentUuid'));
test('collector.js tag data dengan site_uuid', collectorCode.includes('site_uuid: SITE_UUID') || collectorCode.includes('site_uuid: SITE_UUID') || collectorCode.includes('site_uuid: siteUuid'));
console.log('');
// ─── TEST GROUP 4: Docker Compose 2 Container Groups ─────────────────────
console.log('[GROUP 4] Docker Compose — 2 Container Groups + 2 Networks');
const composeCode = readFile('docker-compose.yml');
test('docker-compose.yml tidak punya service: mongodb', !composeCode.includes('mongodb:'));
test('docker-compose.yml punya service: proxy', composeCode.includes('proxy:'));
test('docker-compose.yml punya service: backend', composeCode.includes('backend:'));
test('docker-compose.yml punya service: frontend', composeCode.includes('frontend:'));
test('docker-compose.yml punya network: backone-infra', composeCode.includes('backone-infra'));
test('docker-compose.yml punya network: backone-app', composeCode.includes('backone-app'));
test('proxy connect ke backone-infra (Container 1)', composeCode.includes('backone-infra'));
test('backend connect ke backone-app (Container 2)', composeCode.includes('backone-app'));
test('proxy tidak depends on mongodb', !composeCode.includes('service_healthy'));
test('env PROXY_COLLECT_MODE di docker-compose', composeCode.includes('PROXY_COLLECT_MODE'));
test('env PROXY_AGENT_UUID di docker-compose', composeCode.includes('PROXY_AGENT_UUID'));
test('PROXY_URL dikirim ke backend', composeCode.includes('PROXY_URL=http://proxy:4000'));
console.log('');
// ─── TEST GROUP 5: MongoDB Schemas sinkron ────────────────────────────────
console.log('[GROUP 5] MongoDB Schemas — Proxy & Backend Sinkron');
const proxySchema = readFile('proxy/models/Schemas.js');
const backendSchema = readFile('backend/models/Schemas.js');
const sharedFields = ['agent_uuid', 'site_uuid', 'timestamp', 'bandwidth_down', 'bandwidth_up', 'ip_address', 'mac_address', 'flow_id', 'src_ip', 'dst_ip', 'threat_type', 'severity'];
for (const field of sharedFields) {
test(`Field '${field}' ada di kedua schema`, proxySchema.includes(field) && backendSchema.includes(field));
}
console.log('');
// ─── SUMMARY ──────────────────────────────────────────────────────────────
console.log('══════════════════════════════════════════════════════');
console.log(` Results: ${passed} PASSED | ${failed} FAILED`);
console.log('══════════════════════════════════════════════════════\n');
if (failed > 0) process.exit(1);