Analytics: Laenderzuordnung
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3a48e6e677
commit
8b107019c3
4 files changed
+297
-2
No files matched your search
@@ -0,0 +1,110 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { mkdtempSync, writeFileSync } from 'node:fs';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { loadGeo } from '../src/geo.js';
|
||||
|
||||
const CSV = [
|
||||
'1.0.0.0,1.0.0.255,AU',
|
||||
'5.9.0.0,5.9.255.255,DE',
|
||||
'5.10.0.0,5.10.0.9,ZZ',
|
||||
'8.8.8.0,8.8.8.255,US',
|
||||
'255.255.255.0,255.255.255.255,FR',
|
||||
'2001:db8::,2001:db8:ffff:ffff:ffff:ffff:ffff:ffff,AT',
|
||||
'2a01:4f8::,2a01:4f8:ffff:ffff:ffff:ffff:ffff:ffff,DE',
|
||||
'2a02:1::1,2a02:1::ff,CH',
|
||||
'',
|
||||
].join('\n');
|
||||
|
||||
function fixture(content) {
|
||||
const dir = mkdtempSync(join(tmpdir(), 'geo-'));
|
||||
const f = join(dir, 'geo.csv');
|
||||
writeFileSync(f, content);
|
||||
return f;
|
||||
}
|
||||
|
||||
test('IPv4: Treffer und Grenzen', () => {
|
||||
const g = loadGeo(fixture(CSV));
|
||||
assert.equal(g.size, 8);
|
||||
assert.equal(g.lookup('5.9.0.0'), 'DE');
|
||||
assert.equal(g.lookup('5.9.123.4'), 'DE');
|
||||
assert.equal(g.lookup('5.9.255.255'), 'DE');
|
||||
assert.equal(g.lookup('5.8.255.255'), '');
|
||||
assert.equal(g.lookup('5.10.0.0'), '');
|
||||
assert.equal(g.lookup('1.0.0.255'), 'AU');
|
||||
assert.equal(g.lookup('1.0.1.0'), '');
|
||||
assert.equal(g.lookup('0.0.0.1'), '');
|
||||
assert.equal(g.lookup('255.255.255.255'), 'FR');
|
||||
assert.equal(g.lookup('8.8.8.8'), 'US');
|
||||
});
|
||||
|
||||
test('IPv6: Treffer, Grenzen, Kurzschreibweise', () => {
|
||||
const g = loadGeo(fixture(CSV));
|
||||
assert.equal(g.lookup('2a01:4f8::'), 'DE');
|
||||
assert.equal(g.lookup('2a01:4f8:1:2:3:4:5:6'), 'DE');
|
||||
assert.equal(g.lookup('2A01:04F8:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF'), 'DE');
|
||||
assert.equal(g.lookup('2a01:4f9::'), '');
|
||||
assert.equal(g.lookup('2a01:4f7:ffff:ffff:ffff:ffff:ffff:ffff'), '');
|
||||
assert.equal(g.lookup('2001:db8::1'), 'AT');
|
||||
assert.equal(g.lookup('2a02:1::1'), 'CH');
|
||||
assert.equal(g.lookup('2a02:1::ff'), 'CH');
|
||||
assert.equal(g.lookup('2a02:1::100'), '');
|
||||
assert.equal(g.lookup('2a02:1::'), '');
|
||||
assert.equal(g.lookup('::1'), '');
|
||||
});
|
||||
|
||||
test('IPv4-gemappte IPv6-Adressen zählen als IPv4', () => {
|
||||
const g = loadGeo(fixture(CSV));
|
||||
assert.equal(g.lookup('::ffff:5.9.1.1'), 'DE');
|
||||
assert.equal(g.lookup('::FFFF:8.8.8.8'), 'US');
|
||||
assert.equal(g.lookup('::ffff:808:808'), 'US');
|
||||
assert.equal(g.lookup('::ffff:9.9.9.9'), '');
|
||||
});
|
||||
|
||||
test('ZZ, ungültige Eingaben, unsortierte Datei', () => {
|
||||
const g = loadGeo(fixture(CSV));
|
||||
assert.equal(g.lookup('5.10.0.5'), '');
|
||||
for (const bad of ['', 'abc', '1.2.3', '256.1.1.1', '1.2.3.4.5', '2001:db8::zz', ':::', '1::2::3', null, undefined, 42]) {
|
||||
assert.equal(g.lookup(bad), '', String(bad));
|
||||
}
|
||||
const u = loadGeo(fixture('8.8.8.0,8.8.8.255,US\n1.0.0.0,1.0.0.255,AU\n2a01:4f8::,2a01:4f8::ff,DE\n2001:db8::,2001:db8::ff,AT\n'));
|
||||
assert.equal(u.lookup('1.0.0.7'), 'AU');
|
||||
assert.equal(u.lookup('8.8.8.8'), 'US');
|
||||
assert.equal(u.lookup('2001:db8::7'), 'AT');
|
||||
assert.equal(u.lookup('2a01:4f8::7'), 'DE');
|
||||
});
|
||||
|
||||
test('fehlende Datei: alles leer, eine Warnung, kein Absturz', () => {
|
||||
const warns = [];
|
||||
const orig = console.warn;
|
||||
console.warn = (...a) => warns.push(a.join(' '));
|
||||
try {
|
||||
const g = loadGeo('/nicht/vorhanden/geo.csv');
|
||||
assert.equal(g.lookup('5.9.1.1'), '');
|
||||
assert.equal(g.lookup('2a01:4f8::1'), '');
|
||||
assert.equal(g.size, 0);
|
||||
} finally { console.warn = orig; }
|
||||
assert.equal(warns.length, 1);
|
||||
assert.match(warns[0], /nicht lesbar/);
|
||||
});
|
||||
|
||||
test('600k Zeilen: lädt zügig, Heap bleibt klein', () => {
|
||||
const lines = [];
|
||||
for (let i = 0; i < 400000; i++) lines.push(`${(i * 4096) >>> 24}.${((i * 4096) >>> 16) & 255}.${((i * 4096) >>> 8) & 255}.0,${(i * 4096) >>> 24}.${((i * 4096) >>> 16) & 255}.${((i * 4096 + 255) >>> 8) & 255}.255,${i % 7 ? 'DE' : 'AT'}`);
|
||||
for (let i = 0; i < 200000; i++) lines.push(`2a00:${(i >> 8).toString(16)}:${(i & 255).toString(16)}::,2a00:${(i >> 8).toString(16)}:${(i & 255).toString(16)}:ffff:ffff:ffff:ffff:ffff,${i % 5 ? 'DE' : 'FR'}`);
|
||||
const f = fixture(lines.join('\n'));
|
||||
lines.length = 0;
|
||||
globalThis.gc?.();
|
||||
const before = process.memoryUsage().heapUsed; const rss0 = process.memoryUsage().rss;
|
||||
const t0 = Date.now();
|
||||
const g = loadGeo(f);
|
||||
const ms = Date.now() - t0;
|
||||
globalThis.gc?.();
|
||||
const grow = (process.memoryUsage().heapUsed - before) / 1048576;
|
||||
console.log(`# geo 600k: ${ms} ms, Heap +${grow.toFixed(1)} MB, RSS +${((process.memoryUsage().rss - rss0) / 1048576).toFixed(0)} MB, Zeilen ${g.size}`);
|
||||
assert.equal(g.size, 600000);
|
||||
assert.equal(g.lookup('0.0.16.5'), 'DE');
|
||||
assert.equal(g.lookup('2a00:0:1::5'), 'DE');
|
||||
assert.ok(grow < 100, `Heap +${grow} MB`);
|
||||
});
|
||||
Reference in new issue
Block a user