Add native local network integrations

This commit is contained in:
2026-05-05 18:45:46 +00:00
parent 282283d344
commit cfab8c593e
70 changed files with 9688 additions and 176 deletions
+86
View File
@@ -0,0 +1,86 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { AdguardClient, AdguardIntegration, type IAdguardSnapshot } from '../../ts/integrations/adguard/index.js';
const snapshot: IAdguardSnapshot = {
online: true,
host: '127.0.0.1',
port: 3000,
status: { running: true, version: 'v0.107.45', protection_enabled: false },
filtering: { enabled: true, filters: [{ name: 'Test', url: 'https://example.test/filter.txt', enabled: true, rules_count: 1 }] },
queryLog: { enabled: true, interval: 604800000, anonymize_client_ip: false, ignored: [], ignored_enabled: false },
safebrowsing: { enabled: false },
safesearch: { enabled: false },
parental: { enabled: false },
stats: { num_dns_queries: 1, num_blocked_filtering: 0, avg_processing_time: 0.01 },
};
tap.test('reads AdGuard Home snapshot from local HTTP API endpoints', async () => {
const originalFetch = globalThis.fetch;
const calls: Array<{ url: string; method?: string; authorization?: string }> = [];
globalThis.fetch = (async (urlArg: URL | RequestInfo, initArg?: RequestInit) => {
calls.push({ url: String(urlArg), method: initArg?.method, authorization: (initArg?.headers as Record<string, string> | undefined)?.authorization });
const path = new URL(String(urlArg)).pathname;
const responses: Record<string, unknown> = {
'/control/status': { running: true, version: 'v0.107.45', protection_enabled: true, http_port: 3000 },
'/control/filtering/status': { enabled: true, filters: [{ name: 'Filter', url: 'https://example.test/filter.txt', rules_count: 10, enabled: true }] },
'/control/querylog/config': { enabled: true, interval: 604800000, anonymize_client_ip: false, ignored: [], ignored_enabled: false },
'/control/safebrowsing/status': { enabled: true },
'/control/safesearch/status': { enabled: false },
'/control/parental/status': { enabled: false },
'/control/stats': { num_dns_queries: 40, num_blocked_filtering: 10, avg_processing_time: 0.02 },
'/control/version.json': { disabled: true },
};
return new Response(JSON.stringify(responses[path] || {}), { status: 200, headers: { 'content-type': 'application/json' } });
}) as typeof globalThis.fetch;
try {
const result = await new AdguardClient({ host: '127.0.0.1', port: 3000, ssl: false, username: 'admin', password: 'secret' }).getSnapshot();
expect(result.online).toBeTrue();
expect(result.status.version).toEqual('v0.107.45');
expect(result.stats.num_blocked_filtering).toEqual(10);
expect(calls.some((callArg) => callArg.url === 'http://127.0.0.1:3000/control/status')).toBeTrue();
expect(calls[0].authorization).toEqual(`Basic ${Buffer.from('admin:secret').toString('base64')}`);
} finally {
globalThis.fetch = originalFetch;
}
});
tap.test('executes live AdGuard commands only through HTTP client or executor', async () => {
const originalFetch = globalThis.fetch;
const calls: Array<{ url: string; method?: string; body?: string }> = [];
globalThis.fetch = (async (urlArg: URL | RequestInfo, initArg?: RequestInit) => {
calls.push({ url: String(urlArg), method: initArg?.method, body: initArg?.body as string | undefined });
return new Response('{}', { status: 200, headers: { 'content-type': 'application/json' } });
}) as typeof globalThis.fetch;
try {
const runtime = await new AdguardIntegration().setup({ host: '127.0.0.1', port: 3000, snapshot }, {});
const result = await runtime.callService?.({
domain: 'switch',
service: 'turn_on',
target: { entityId: 'switch.adguard_home_protection' },
});
expect(result?.success).toBeTrue();
expect(calls[0].url).toEqual('http://127.0.0.1:3000/control/protection');
expect(calls[0].method).toEqual('POST');
expect(JSON.parse(calls[0].body || '{}')).toEqual({ enabled: true });
await runtime.destroy();
} finally {
globalThis.fetch = originalFetch;
}
});
tap.test('does not report snapshot-only AdGuard commands as successful', async () => {
const runtime = await new AdguardIntegration().setup({ snapshot: { ...snapshot, host: undefined } }, {});
const protectionEntity = (await runtime.entities()).find((entityArg) => entityArg.attributes?.adguardSwitchKey === 'protection');
const result = await runtime.callService?.({
domain: 'switch',
service: 'turn_on',
target: { entityId: protectionEntity?.id },
});
expect(result?.success).toBeFalse();
expect(result?.error).toEqual('AdGuard Home live commands require config.host or commandExecutor; snapshot-only commands are not reported as successful.');
await runtime.destroy();
});
export default tap.start();