Files
integrations/test/huawei_lte/test.huawei_lte.client_runtime.node.ts
T

179 lines
8.9 KiB
TypeScript

import { createServer, type IncomingMessage, type ServerResponse } from 'node:http';
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { HuaweiLteClient, HuaweiLteIntegration, HuaweiLteMapper, type IHuaweiLteRawData } from '../../ts/integrations/huawei_lte/index.js';
const xmlResponse = (itemsArg: Record<string, string | number | boolean>): string => {
return `<?xml version="1.0" encoding="UTF-8"?><response>${Object.entries(itemsArg).map(([key, value]) => `<${key}>${value}</${key}>`).join('')}</response>`;
};
const readBody = async (requestArg: IncomingMessage): Promise<string> => {
const chunks: Buffer[] = [];
for await (const chunk of requestArg) {
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
}
return Buffer.concat(chunks).toString('utf8');
};
tap.test('reads Huawei LTE snapshots over native local HTTP and writes real POST commands', async () => {
const requests: Array<{ method?: string; url?: string; body?: string }> = [];
const server = createServer((requestArg: IncomingMessage, responseArg: ServerResponse) => {
void (async () => {
const body = requestArg.method === 'POST' ? await readBody(requestArg) : undefined;
requests.push({ method: requestArg.method, url: requestArg.url, body });
responseArg.setHeader('content-type', 'application/xml');
responseArg.setHeader('__RequestVerificationToken', 'token-next');
const url = new URL(requestArg.url || '/', 'http://127.0.0.1');
if (url.pathname === '/') {
responseArg.setHeader('content-type', 'text/html');
responseArg.end('<html><head><meta name="csrf_token" content="token-1"></head></html>');
return;
}
if (url.pathname === '/api/device/information') {
responseArg.end(xmlResponse({ DeviceName: 'B535-232', SerialNumber: 'LIVE123', SoftwareVersion: '12.0.5.1', MacAddress1: 'AABBCCDDEEFF' }));
return;
}
if (url.pathname === '/api/device/basic_information') {
responseArg.end(xmlResponse({ devicename: 'B535-232' }));
return;
}
if (url.pathname === '/api/device/signal') {
responseArg.end(xmlResponse({ rsrp: '-90dBm', rsrq: '-11dB', sinr: '20dB' }));
return;
}
if (url.pathname === '/api/dialup/mobile-dataswitch' && requestArg.method === 'GET') {
responseArg.end(xmlResponse({ dataswitch: '1' }));
return;
}
if (url.pathname === '/api/monitoring/status') {
responseArg.end(xmlResponse({ ConnectionStatus: '901', WifiStatus: '1', CurrentWifiUser: '2' }));
return;
}
if (url.pathname === '/api/monitoring/check-notifications') {
responseArg.end(xmlResponse({ UnreadMessage: '1', SmsStorageFull: '0' }));
return;
}
if (url.pathname === '/api/monitoring/traffic-statistics') {
responseArg.end(xmlResponse({ CurrentDownloadRate: '128', CurrentUploadRate: '64', TotalDownload: '4096', TotalUpload: '8192' }));
return;
}
if (url.pathname === '/api/monitoring/month_statistics') {
responseArg.end(xmlResponse({ CurrentMonthDownload: '1000', CurrentMonthUpload: '2000' }));
return;
}
if (url.pathname === '/api/net/current-plmn') {
responseArg.end(xmlResponse({ FullName: 'Example Mobile', Numeric: '00101', State: '0' }));
return;
}
if (url.pathname === '/api/net/net-mode' && requestArg.method === 'GET') {
responseArg.end(xmlResponse({ NetworkMode: '03', NetworkBand: '3fffffff', LTEBand: '7fffffffffffffff' }));
return;
}
if (url.pathname === '/api/sms/sms-count') {
responseArg.end(xmlResponse({ LocalUnread: '1', LocalInbox: '3', SimMax: '50' }));
return;
}
if (url.pathname === '/api/wlan/wifi-feature-switch') {
responseArg.end(xmlResponse({ wifi24g_switch_enable: '1', wifi5g_enabled: '1' }));
return;
}
if (url.pathname === '/api/lan/HostInfo') {
responseArg.end('<?xml version="1.0" encoding="UTF-8"?><response><Hosts><Host><MacAddress>11:22:33:44:55:66</MacAddress><HostName>phone</HostName><IpAddress>192.168.8.10</IpAddress><Active>1</Active><InterfaceType>Wireless</InterfaceType></Host></Hosts></response>');
return;
}
if (url.pathname === '/api/wlan/multi-basic-settings') {
if (requestArg.method === 'GET') {
responseArg.end('<?xml version="1.0" encoding="UTF-8"?><response><Ssids><Ssid><Index>0</Index><WifiEnable>1</WifiEnable><WifiSsid>Main</WifiSsid><WifiMac>AA:BB:CC:DD:EE:FF</WifiMac><wifiisguestnetwork>0</wifiisguestnetwork></Ssid><Ssid><Index>1</Index><WifiEnable>1</WifiEnable><WifiSsid>Guest</WifiSsid><WifiMac>AA:BB:CC:DD:EE:00</WifiMac><wifiisguestnetwork>1</wifiisguestnetwork></Ssid></Ssids></response>');
return;
}
expect(body).toContain('<WifiEnable>0</WifiEnable>');
responseArg.end('<response>OK</response>');
return;
}
if (url.pathname === '/api/dialup/mobile-dataswitch' && requestArg.method === 'POST') {
expect(body).toContain('<dataswitch>0</dataswitch>');
responseArg.end('<response>OK</response>');
return;
}
if (url.pathname === '/api/sms/send-sms') {
expect(body).toContain('<Phone>+123</Phone>');
expect(body).toContain('<Content>hello</Content>');
responseArg.end('<response>OK</response>');
return;
}
responseArg.statusCode = 404;
responseArg.end('<error><code>100002</code><message>No support</message></error>');
})().catch((errorArg) => {
responseArg.statusCode = 500;
responseArg.end(String(errorArg));
});
});
await new Promise<void>((resolve) => server.listen(0, '127.0.0.1', resolve));
try {
const address = server.address();
const port = typeof address === 'object' && address ? address.port : 0;
const client = new HuaweiLteClient({ url: `http://127.0.0.1:${port}/`, timeoutMs: 1000 });
const snapshot = await client.getSnapshot();
await client.execute({ action: 'set_mobile_dataswitch', enabled: false });
await client.execute({ action: 'set_wifi_guest_network', enabled: false });
await client.execute({ action: 'send_sms', phoneNumbers: ['+123'], message: 'hello' });
expect(snapshot.online).toBeTrue();
expect(snapshot.source).toEqual('http');
expect(snapshot.device.serialNumber).toEqual('LIVE123');
expect(snapshot.device.macAddresses[0]).toEqual('aa:bb:cc:dd:ee:00');
expect(snapshot.signal.rsrp).toEqual(-90);
expect(snapshot.connection.mobileDataEnabled).toBeTrue();
expect(snapshot.connection.guestWifiEnabled).toBeTrue();
expect(snapshot.hosts[0].hostname).toEqual('phone');
expect(requests.some((requestArg) => requestArg.url === '/api/device/information')).toBeTrue();
expect(requests.some((requestArg) => requestArg.url === '/api/dialup/mobile-dataswitch' && requestArg.method === 'POST')).toBeTrue();
expect(requests.some((requestArg) => requestArg.url === '/api/sms/send-sms' && requestArg.method === 'POST')).toBeTrue();
} finally {
await new Promise<void>((resolve, reject) => server.close((errorArg) => errorArg ? reject(errorArg) : resolve()));
}
});
tap.test('does not report live command success for static snapshots', async () => {
const rawData: Partial<IHuaweiLteRawData> = {
deviceInformation: { DeviceName: 'Static LTE', SerialNumber: 'STATIC123' },
dialupMobileDataswitch: { dataswitch: '1' },
monitoringStatus: { ConnectionStatus: '901' },
};
const snapshot = HuaweiLteMapper.toSnapshot({ config: { name: 'Static LTE' }, rawData, online: true, source: 'manual' });
const runtime = await new HuaweiLteIntegration().setup({ snapshot }, {});
const result = await runtime.callService?.({ domain: 'switch', service: 'turn_off', target: { entityId: 'switch.static_lte_mobile_data' }, data: {} });
expect(result?.success).toBeFalse();
expect(result?.error).toContain('Static snapshots/manual data are read-only');
await runtime.destroy();
});
tap.test('delegates Huawei LTE commands to an injected executor', async () => {
const commands: unknown[] = [];
const rawData: Partial<IHuaweiLteRawData> = {
deviceInformation: { DeviceName: 'Executor LTE', SerialNumber: 'EXEC123' },
dialupMobileDataswitch: { dataswitch: '1' },
monitoringStatus: { ConnectionStatus: '901' },
};
const snapshot = HuaweiLteMapper.toSnapshot({ config: { name: 'Executor LTE' }, rawData, online: true, source: 'manual' });
const runtime = await new HuaweiLteIntegration().setup({
snapshot,
commandExecutor: {
execute: async (requestArg) => {
commands.push(requestArg);
return { accepted: true };
},
},
}, {});
const result = await runtime.callService?.({ domain: 'huawei_lte', service: 'reboot', target: {}, data: {} });
expect(result?.success).toBeTrue();
expect((commands[0] as { action?: string }).action).toEqual('reboot');
await runtime.destroy();
});
export default tap.start();