329 lines
11 KiB
TypeScript
329 lines
11 KiB
TypeScript
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
|
import { Qenv } from '@push.rocks/qenv';
|
|
import * as unifi from '../ts/index.js';
|
|
|
|
// =============================================================================
|
|
// SITE INFO - Pretty print comprehensive site information
|
|
// Tests may use live production keys to test specific features at scale.
|
|
// Make sure to avoid dangerous, destructive or security relevant operations.
|
|
// =============================================================================
|
|
|
|
const testQenv = new Qenv('./', './.nogit/');
|
|
|
|
let testController: unifi.UnifiController;
|
|
|
|
// Helper to print section headers
|
|
const printHeader = (title: string) => {
|
|
console.log('');
|
|
console.log('='.repeat(60));
|
|
console.log(` ${title}`);
|
|
console.log('='.repeat(60));
|
|
};
|
|
|
|
// Helper to print sub-section headers
|
|
const printSubHeader = (title: string) => {
|
|
console.log('');
|
|
console.log(`--- ${title} ---`);
|
|
};
|
|
|
|
// Helper to format bytes
|
|
const formatBytes = (bytes: number): string => {
|
|
if (bytes === 0) return '0 B';
|
|
const k = 1024;
|
|
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`;
|
|
};
|
|
|
|
tap.test('setup - create UnifiController', async () => {
|
|
const host = await testQenv.getEnvVarOnDemand('UNIFI_CONSOLE_IP');
|
|
const apiKey = await testQenv.getEnvVarOnDemand('UNIFI_NETWORK_DEV_KEY');
|
|
|
|
testController = new unifi.UnifiController({
|
|
host,
|
|
apiKey,
|
|
controllerType: 'unifi-os',
|
|
verifySsl: false,
|
|
});
|
|
|
|
expect(testController.isAuthenticated()).toBeTrue();
|
|
});
|
|
|
|
tap.test('INFO - Sites Overview', async () => {
|
|
printHeader('SITES OVERVIEW');
|
|
|
|
const sites = await testController.listSites();
|
|
console.log(`Total Sites: ${sites.length}`);
|
|
|
|
for (const site of sites) {
|
|
console.log('');
|
|
console.log(` Site: ${site.name || site.desc || 'Unnamed'}`);
|
|
console.log(` ID: ${site._id}`);
|
|
console.log(` Description: ${site.desc || 'N/A'}`);
|
|
if (site.role) console.log(` Role: ${site.role}`);
|
|
}
|
|
});
|
|
|
|
tap.test('INFO - Devices by Type', async () => {
|
|
printHeader('DEVICES');
|
|
|
|
const devices = await testController.deviceManager.listDevices();
|
|
const accessPoints = await testController.deviceManager.getAccessPoints();
|
|
const switches = await testController.deviceManager.getSwitches();
|
|
const gateways = await testController.deviceManager.getGateways();
|
|
|
|
console.log(`Total Devices: ${devices.length}`);
|
|
console.log(` - Access Points: ${accessPoints.length}`);
|
|
console.log(` - Switches: ${switches.length}`);
|
|
console.log(` - Gateways: ${gateways.length}`);
|
|
|
|
// Access Points
|
|
if (accessPoints.length > 0) {
|
|
printSubHeader('Access Points');
|
|
for (const ap of accessPoints) {
|
|
const status = ap.isOnline() ? 'ONLINE' : 'OFFLINE';
|
|
console.log(` [${status}] ${ap.getDisplayName()}`);
|
|
console.log(` Model: ${ap.model} | IP: ${ap.ip || 'N/A'}`);
|
|
console.log(` MAC: ${ap.mac} | Version: ${ap.version || 'N/A'}`);
|
|
if (ap.uptime) {
|
|
const uptimeHours = Math.floor(ap.uptime / 3600);
|
|
const uptimeDays = Math.floor(uptimeHours / 24);
|
|
console.log(` Uptime: ${uptimeDays}d ${uptimeHours % 24}h`);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Switches
|
|
if (switches.length > 0) {
|
|
printSubHeader('Switches');
|
|
for (const sw of switches) {
|
|
const status = sw.isOnline() ? 'ONLINE' : 'OFFLINE';
|
|
console.log(` [${status}] ${sw.getDisplayName()}`);
|
|
console.log(` Model: ${sw.model} | IP: ${sw.ip || 'N/A'}`);
|
|
console.log(` MAC: ${sw.mac} | Ports: ${sw.port_table?.length || 'N/A'}`);
|
|
}
|
|
}
|
|
|
|
// Gateways
|
|
if (gateways.length > 0) {
|
|
printSubHeader('Gateways');
|
|
for (const gw of gateways) {
|
|
const status = gw.isOnline() ? 'ONLINE' : 'OFFLINE';
|
|
console.log(` [${status}] ${gw.getDisplayName()}`);
|
|
console.log(` Model: ${gw.model} | IP: ${gw.ip || 'N/A'}`);
|
|
}
|
|
}
|
|
});
|
|
|
|
tap.test('INFO - Networks (VLANs)', async () => {
|
|
printHeader('NETWORKS');
|
|
|
|
const response = await testController.getNetworks() as any;
|
|
const networks = response?.data || [];
|
|
|
|
console.log(`Total Networks: ${networks.length}`);
|
|
|
|
for (const net of networks) {
|
|
console.log('');
|
|
console.log(` Network: ${net.name}`);
|
|
console.log(` Purpose: ${net.purpose || 'N/A'}`);
|
|
if (net.vlan_enabled) {
|
|
console.log(` VLAN ID: ${net.vlan}`);
|
|
}
|
|
if (net.ip_subnet) {
|
|
console.log(` Subnet: ${net.ip_subnet}`);
|
|
}
|
|
if (net.dhcpd_enabled !== undefined) {
|
|
console.log(` DHCP: ${net.dhcpd_enabled ? 'Enabled' : 'Disabled'}`);
|
|
if (net.dhcpd_enabled && net.dhcpd_start && net.dhcpd_stop) {
|
|
console.log(` DHCP Range: ${net.dhcpd_start} - ${net.dhcpd_stop}`);
|
|
}
|
|
}
|
|
if (net.igmp_snooping !== undefined) {
|
|
console.log(` IGMP Snooping: ${net.igmp_snooping ? 'Enabled' : 'Disabled'}`);
|
|
}
|
|
}
|
|
});
|
|
|
|
tap.test('INFO - Wireless Networks (WLANs)', async () => {
|
|
printHeader('WIRELESS NETWORKS');
|
|
|
|
const response = await testController.getWlans() as any;
|
|
const wlans = response?.data || [];
|
|
|
|
console.log(`Total WLANs: ${wlans.length}`);
|
|
|
|
for (const wlan of wlans) {
|
|
console.log('');
|
|
console.log(` SSID: ${wlan.name}`);
|
|
console.log(` Enabled: ${wlan.enabled !== false ? 'Yes' : 'No'}`);
|
|
console.log(` Security: ${wlan.security || 'open'}`);
|
|
if (wlan.wpa_mode) {
|
|
console.log(` WPA Mode: ${wlan.wpa_mode}`);
|
|
}
|
|
if (wlan.networkconf_id) {
|
|
console.log(` Network ID: ${wlan.networkconf_id}`);
|
|
}
|
|
if (wlan.is_guest !== undefined) {
|
|
console.log(` Guest Network: ${wlan.is_guest ? 'Yes' : 'No'}`);
|
|
}
|
|
if (wlan.hide_ssid !== undefined) {
|
|
console.log(` Hidden: ${wlan.hide_ssid ? 'Yes' : 'No'}`);
|
|
}
|
|
if (wlan.wlan_band) {
|
|
console.log(` Band: ${wlan.wlan_band}`);
|
|
}
|
|
}
|
|
});
|
|
|
|
tap.test('INFO - Firewall Rules', async () => {
|
|
printHeader('FIREWALL RULES');
|
|
|
|
const response = await testController.getFirewallRules() as any;
|
|
const rules = response?.data || [];
|
|
|
|
console.log(`Total Firewall Rules: ${rules.length}`);
|
|
|
|
for (const rule of rules) {
|
|
const enabled = rule.enabled !== false ? 'ON' : 'OFF';
|
|
console.log('');
|
|
console.log(` [${enabled}] ${rule.name || 'Unnamed Rule'}`);
|
|
console.log(` Action: ${rule.action || 'N/A'} | Ruleset: ${rule.ruleset || 'N/A'}`);
|
|
if (rule.src_firewallgroup_ids?.length > 0) {
|
|
console.log(` Source Groups: ${rule.src_firewallgroup_ids.length}`);
|
|
}
|
|
if (rule.dst_firewallgroup_ids?.length > 0) {
|
|
console.log(` Dest Groups: ${rule.dst_firewallgroup_ids.length}`);
|
|
}
|
|
if (rule.protocol) {
|
|
console.log(` Protocol: ${rule.protocol}`);
|
|
}
|
|
}
|
|
|
|
if (rules.length === 0) {
|
|
console.log(' No custom firewall rules configured');
|
|
}
|
|
});
|
|
|
|
tap.test('INFO - Port Forwards', async () => {
|
|
printHeader('PORT FORWARDS');
|
|
|
|
const response = await testController.getPortForwards() as any;
|
|
const forwards = response?.data || [];
|
|
|
|
console.log(`Total Port Forwards: ${forwards.length}`);
|
|
|
|
for (const fwd of forwards) {
|
|
const enabled = fwd.enabled !== false ? 'ON' : 'OFF';
|
|
console.log('');
|
|
console.log(` [${enabled}] ${fwd.name || 'Unnamed'}`);
|
|
console.log(` External: ${fwd.dst_port || 'N/A'} -> Internal: ${fwd.fwd}:${fwd.fwd_port || fwd.dst_port}`);
|
|
console.log(` Protocol: ${fwd.proto || 'tcp_udp'}`);
|
|
}
|
|
|
|
if (forwards.length === 0) {
|
|
console.log(' No port forwards configured');
|
|
}
|
|
});
|
|
|
|
tap.test('INFO - Connected Clients Summary', async () => {
|
|
printHeader('CLIENTS SUMMARY');
|
|
|
|
const allClients = await testController.clientManager.listActiveClients();
|
|
const wirelessClients = await testController.clientManager.getWirelessClients();
|
|
const wiredClients = await testController.clientManager.getWiredClients();
|
|
|
|
console.log(`Total Active Clients: ${allClients.length}`);
|
|
console.log(` - Wireless: ${wirelessClients.length}`);
|
|
console.log(` - Wired: ${wiredClients.length}`);
|
|
|
|
// Calculate total bandwidth
|
|
let totalTx = 0;
|
|
let totalRx = 0;
|
|
for (const client of allClients) {
|
|
totalTx += client.tx_bytes || 0;
|
|
totalRx += client.rx_bytes || 0;
|
|
}
|
|
|
|
console.log('');
|
|
console.log(`Total Data Transfer:`);
|
|
console.log(` - Upload (TX): ${formatBytes(totalTx)}`);
|
|
console.log(` - Download (RX): ${formatBytes(totalRx)}`);
|
|
console.log(` - Combined: ${formatBytes(totalTx + totalRx)}`);
|
|
|
|
// Top 5 clients by data usage
|
|
printSubHeader('Top 5 Clients by Data Usage');
|
|
const sortedClients = [...allClients].sort((a, b) =>
|
|
(b.getDataUsage() || 0) - (a.getDataUsage() || 0)
|
|
).slice(0, 5);
|
|
|
|
for (const client of sortedClients) {
|
|
const usage = client.getDataUsage();
|
|
console.log(` ${client.getDisplayName()}`);
|
|
console.log(` IP: ${client.ip || 'N/A'} | Usage: ${formatBytes(usage)}`);
|
|
console.log(` Type: ${client.getConnectionType()}`);
|
|
}
|
|
});
|
|
|
|
tap.test('INFO - System Health', async () => {
|
|
printHeader('SYSTEM HEALTH');
|
|
|
|
const response = await testController.getHealth() as any;
|
|
const healthData = response?.data || [];
|
|
|
|
for (const subsystem of healthData) {
|
|
const status = subsystem.status === 'ok' ? 'OK' : subsystem.status?.toUpperCase() || 'UNKNOWN';
|
|
console.log(` [${status}] ${subsystem.subsystem}`);
|
|
|
|
if (subsystem.num_user !== undefined) {
|
|
console.log(` Users: ${subsystem.num_user}`);
|
|
}
|
|
if (subsystem.num_guest !== undefined) {
|
|
console.log(` Guests: ${subsystem.num_guest}`);
|
|
}
|
|
if (subsystem.num_ap !== undefined) {
|
|
console.log(` APs: ${subsystem.num_ap}`);
|
|
}
|
|
if (subsystem.num_adopted !== undefined) {
|
|
console.log(` Adopted: ${subsystem.num_adopted}`);
|
|
}
|
|
if (subsystem.tx_bytes_r !== undefined) {
|
|
console.log(` TX Rate: ${formatBytes(subsystem.tx_bytes_r)}/s`);
|
|
}
|
|
if (subsystem.rx_bytes_r !== undefined) {
|
|
console.log(` RX Rate: ${formatBytes(subsystem.rx_bytes_r)}/s`);
|
|
}
|
|
}
|
|
});
|
|
|
|
tap.test('INFO - Recent Alerts', async () => {
|
|
printHeader('RECENT ALERTS');
|
|
|
|
const response = await testController.getAlerts() as any;
|
|
const alerts = response?.data || [];
|
|
|
|
console.log(`Total Alerts: ${alerts.length}`);
|
|
|
|
// Show last 10 alerts
|
|
const recentAlerts = alerts.slice(0, 10);
|
|
|
|
for (const alert of recentAlerts) {
|
|
const time = alert.time ? new Date(alert.time).toLocaleString() : 'Unknown time';
|
|
const archived = alert.archived ? '[ARCHIVED]' : '';
|
|
console.log('');
|
|
console.log(` ${time} ${archived}`);
|
|
console.log(` Type: ${alert.key || 'N/A'}`);
|
|
if (alert.msg) {
|
|
console.log(` Message: ${alert.msg}`);
|
|
}
|
|
}
|
|
|
|
if (alerts.length === 0) {
|
|
console.log(' No alerts');
|
|
} else if (alerts.length > 10) {
|
|
console.log(` ... and ${alerts.length - 10} more alerts`);
|
|
}
|
|
});
|
|
|
|
export default tap.start();
|