87 lines
4.6 KiB
TypeScript
87 lines
4.6 KiB
TypeScript
|
|
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();
|