Files
TREK/server/tests/setup.ts
T
Maurice 328b5fcb2b One Nominatim client for atlas and maps
Atlas throttled to the 1.1s OSM asks for and cached its answers in a 50k
map; maps did neither, so five interactive routes fired straight at the
service while the two atlas backfill loops politely waited their turn.
From Nominatim's side that is one instance ignoring the rate limit.

Both go through geo/nominatim.client.ts now. Three things the naive merge
would have got wrong:

- The shared client sends UA, the instance-identifying User-Agent, not the
  generic string atlas used. A shared generic UA is throttled harder.
- One cursor across five interactive routes and two background loops would
  have put a keystroke behind however many places the backfill enqueued, so
  there are two lanes over the one cursor and background yields.
- The cache key carries the query shape. Atlas asks at zoom 3 and 8, maps at
  18; a coordinate-only key answers a street lookup with a country.

The throttle cursor and the cache stay module state, the way the permissions
and FX caches do, because the bridges build their collaborators outside the
container and a second copy of the cursor is the bug being removed here.
GeocodingService owns only the cleanup timer's lifecycle, which atlas used to
start as an import-time side effect.

Also folds the three haversine implementations into common/geo.ts, keeping
the clamped form: asin of a value a hair over 1 is NaN, and a NaN distance
fails every comparison it feeds instead of throwing.

tests/setup.ts zeroes the interval. Nineteen maps cases drive these paths
back to back with real timers and were sleeping nineteen seconds for it.
2026-08-10 17:08:54 +02:00

38 lines
2.2 KiB
TypeScript

// Global test setup — runs before every test file.
// Environment variables must be set before any module import so that
// config.ts, database.ts, etc. pick them up at import time. (Importing from
// 'vitest' itself is safe: it is externalized and pulls in no app modules.)
import { afterEach } from 'vitest';
// Fixed encryption key (64 hex chars = 32 bytes) for at-rest crypto in tests
process.env.ENCRYPTION_KEY = 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2a3b4c5d6a7b8c9d0e1f2';
process.env.NODE_ENV = 'test';
process.env.COOKIE_SECURE = 'false';
process.env.LOG_LEVEL = 'error'; // suppress info/debug logs in test output
// Several services fire notification sends as unawaited dynamic-import chains
// (`import('…/notificationService').then(({ send }) => send(…).catch(…))`).
// Give those chains one macrotask turn to settle after every test, while the
// suite's DB and the worker environment are still alive — otherwise the last
// test in a file can leave the chain pending into worker teardown ("Cannot
// load ... after the environment was torn down"). Under the default "stack"
// hook order this afterEach runs after each test's own afterEach and before
// the suite's afterAll, i.e. before any afterAll closes its test DB.
// setImmediate is captured up front because some suites install fake timers.
const realSetImmediate = globalThis.setImmediate;
afterEach(async () => {
await new Promise((resolve) => realSetImmediate(resolve));
});
// Nominatim's rate limit is a property of the real service, not of the code
// under test. Nineteen maps cases stub fetch and drive those paths back to back;
// under the real 1.1s interval they would spend nineteen seconds asleep. The
// cases that are actually about the throttle set it back for themselves.
//
// Imported dynamically, and down here rather than at the top: the client pulls
// in maps.helpers, whose UA constant calls getAppUrl() at module load. A static
// import is hoisted above the assignments above it, so the URL would be read
// from an environment this file has not finished setting up yet.
const { setGeoThrottleInterval } = await import('../src/nest/geo/nominatim.client');
setGeoThrottleInterval(0);