86 lines
4.1 KiB
JavaScript
86 lines
4.1 KiB
JavaScript
import assert from 'node:assert/strict';
|
|
import fs from 'node:fs/promises';
|
|
import os from 'node:os';
|
|
import path from 'node:path';
|
|
import { spawnSync } from 'node:child_process';
|
|
import test from 'node:test';
|
|
import { SAMPLE_GPX } from '../test-support/gpx-fixtures.js';
|
|
|
|
const script = path.resolve(import.meta.dirname, '../scripts/upload-presentation-route.sh');
|
|
|
|
async function uploadFixture(t) {
|
|
const runtime = await fs.mkdtemp(path.join(os.tmpdir(), 'wegwichtel-presentation-'));
|
|
t.after(() => fs.rm(runtime, { recursive: true, force: true }));
|
|
const bin = path.join(runtime, 'bin');
|
|
await fs.mkdir(bin);
|
|
const gpxPath = path.join(runtime, 'track.gpx');
|
|
const jsonPath = path.join(runtime, 'stations.json');
|
|
const logPath = path.join(runtime, 'requests.jsonl');
|
|
const metadata = {
|
|
name: 'Testweg', description: 'Synthetic upload data',
|
|
pois: [
|
|
{ title: 'Start', description: 'First station', lat: 52.5200, lon: 13.4050, triggerRadiusM: 25, sequence: 0 },
|
|
{ title: 'Ende', description: 'Last station', lat: 52.5216, lon: 13.4090, triggerRadiusM: 30, sequence: 1 }
|
|
]
|
|
};
|
|
await fs.writeFile(gpxPath, SAMPLE_GPX);
|
|
await fs.writeFile(jsonPath, JSON.stringify(metadata));
|
|
// Capture curl arguments locally. No requests are sent to a real server.
|
|
await fs.writeFile(path.join(bin, 'curl'), `#!/usr/bin/env python3
|
|
import json, os, sys
|
|
from pathlib import Path
|
|
log = Path(os.environ['TEST_REQUEST_LOG'])
|
|
count = len(log.read_text().splitlines()) if log.exists() else 0
|
|
with log.open('a') as output:
|
|
output.write(json.dumps(sys.argv[1:]) + '\\n')
|
|
if os.environ.get('TEST_FAIL_POI') == '1' and count == 1:
|
|
sys.exit(22)
|
|
print(json.dumps({'id': 101}))
|
|
`, { mode: 0o755 });
|
|
return {
|
|
gpxPath, jsonPath, logPath, metadata,
|
|
env: { ...process.env, PATH: `${bin}${path.delimiter}${process.env.PATH}`, TEST_REQUEST_LOG: logPath }
|
|
};
|
|
}
|
|
|
|
test('presentation uploader accepts explicit test files and posts route and stations through the API', async t => {
|
|
const fixture = await uploadFixture(t);
|
|
const result = spawnSync('bash', [script, 'https://example.invalid/api', fixture.gpxPath, fixture.jsonPath], {
|
|
env: fixture.env, encoding: 'utf8', timeout: 10000
|
|
});
|
|
assert.equal(result.status, 0, result.stderr);
|
|
const requests = (await fs.readFile(fixture.logPath, 'utf8')).trim().split('\n').map(line => JSON.parse(line));
|
|
assert.equal(requests.length, 3);
|
|
assert.ok(requests[0].includes('https://example.invalid/api/routes'));
|
|
assert.ok(requests[0].includes(`gpx=@${fixture.gpxPath};type=application/gpx+xml`));
|
|
for (const [index, poi] of fixture.metadata.pois.entries()) {
|
|
assert.ok(requests[index + 1].includes('https://example.invalid/api/routes/101/pois'));
|
|
assert.ok(requests[index + 1].includes(`title=${poi.title}`));
|
|
assert.ok(requests[index + 1].includes(`sequence=${poi.sequence}`));
|
|
assert.ok(requests[index + 1].includes('POST'));
|
|
}
|
|
assert.match(result.stdout, /Server-ID: 101/);
|
|
});
|
|
|
|
test('presentation uploader reports missing files before any HTTP request', async t => {
|
|
const fixture = await uploadFixture(t);
|
|
for (const args of [[], ['https://example.invalid/api', fixture.gpxPath, `${fixture.jsonPath}.missing`]]) {
|
|
const result = spawnSync('bash', [script, ...args], { env: fixture.env, encoding: 'utf8', timeout: 10000 });
|
|
assert.equal(result.status, 2);
|
|
assert.match(result.stderr, /Aufruf:/);
|
|
}
|
|
await assert.rejects(fs.access(fixture.logPath), { code: 'ENOENT' });
|
|
});
|
|
|
|
test('presentation uploader removes an incomplete route if a station upload fails', async t => {
|
|
const fixture = await uploadFixture(t);
|
|
const result = spawnSync('bash', [script, 'https://example.invalid/api', fixture.gpxPath, fixture.jsonPath], {
|
|
env: { ...fixture.env, TEST_FAIL_POI: '1' }, encoding: 'utf8', timeout: 10000
|
|
});
|
|
assert.notEqual(result.status, 0);
|
|
const requests = (await fs.readFile(fixture.logPath, 'utf8')).trim().split('\n').map(line => JSON.parse(line));
|
|
assert.equal(requests.length, 3);
|
|
assert.ok(requests[2].includes('DELETE'));
|
|
assert.ok(requests[2].includes('https://example.invalid/api/routes/101'));
|
|
});
|