todos-contra-el-fuego-web/smoke
vjrj 296dab4f38 smoke: REST API regression harness + baseline snapshots (Meteor 1.6.1.1)
Adds a standalone Node smoke test (smoke/) that exercises every REST endpoint
consumed by the Flutter app against a seeded local dev server and compares
responses to committed snapshots. This is the safety net for the Meteor upgrade:
it must stay byte-identical after every escala.

- smoke/seed.js: deterministic Mongo seed (fixed ObjectIds, geo indexes)
- smoke/run.js: calls endpoints, normalizes volatile fields, diffs snapshots
- smoke/smoke.sh: seed + run wrapper
- smoke/snapshots/: baseline captured on Meteor 1.6.1.1
- IPGeocoder.js: degrade gracefully when MaxMind DB absent (dev boot)
- settings-development.json: dev-only internalApiToken to enable the REST API
- .meteorignore: exclude smoke/ from the Meteor server build
2026-07-13 19:42:55 +02:00
..
snapshots smoke: REST API regression harness + baseline snapshots (Meteor 1.6.1.1) 2026-07-13 19:42:55 +02:00
README.md smoke: REST API regression harness + baseline snapshots (Meteor 1.6.1.1) 2026-07-13 19:42:55 +02:00
run.js smoke: REST API regression harness + baseline snapshots (Meteor 1.6.1.1) 2026-07-13 19:42:55 +02:00
seed.js smoke: REST API regression harness + baseline snapshots (Meteor 1.6.1.1) 2026-07-13 19:42:55 +02:00
smoke.sh smoke: REST API regression harness + baseline snapshots (Meteor 1.6.1.1) 2026-07-13 19:42:55 +02:00

REST smoke test

Regression harness for the REST API in imports/api/Rest/Rest.js — the API the Flutter app (fires_flutter/lib/models/fires_api.dart) depends on.

It calls every Flutter-consumed endpoint against a locally running dev server with deterministic seed data, normalizes the intrinsically volatile fields (uptime, generated ids, insert timestamps) and compares the responses to committed snapshots in smoke/snapshots/.

It must stay green after every Meteor upgrade escala. The snapshots are the contract: any drift is treated as an upgrade bug.

Reproducible local startup

  1. MongoDB (prod parity = 3.2; a dev-only instance in Docker):

    docker run -d --name tcef-mongo32 -p 27018:27017 mongo:3.2
    
  2. Meteor dev server (from the repo root):

    export PATH="$HOME/.meteor:$PATH"
    export MONGO_URL="mongodb://localhost:27018/fuegos"
    meteor --settings settings-development.json --port 3100
    

    settings-development.json carries a dev-only private.internalApiToken (dev-smoke-token) which is what enables the REST API. Without it the API routes are not even registered (see Rest.js).

    Note: IPGeocoder.js degrades gracefully when the MaxMind GeoLite2 DB is absent (it is provisioned by cron in production) so the server boots in a clean checkout.

Running the smoke test

./smoke/smoke.sh            # seed + compare against baseline snapshots
./smoke/smoke.sh --update   # seed + regenerate the baseline snapshots

Env overrides: MONGO_CONTAINER (default tcef-mongo32), MONGO_DB (fuegos), BASE_URL (http://localhost:3100).

What is covered

Snapshot Endpoint Flutter call
status_uptime GET status/uptime
status_active_fires_count GET status/active-fires-count
status_last_fire_check GET status/last-fire-check
status_last_fire_detected GET status/last-fire-detected
status_subs_public_union GET status/subs-public-union/:token getMonitoredAreas
fires_in GET fires-in/:token/:lat/:lng/:km
fires_in_full GET fires-in-full/:token/:lat/:lng/:km getFiresInLocation
mobile_users_post POST mobile/users createUser
mobile_subscriptions_post POST mobile/subscriptions subscribe
mobile_subscriptions_all GET mobile/subscriptions/all/:token/:mobileToken fetchYourLocations
mobile_subscriptions_delete DELETE mobile/subscriptions/:token/:mobileToken/:subsId unsubscribe
mobile_falsepositive_post POST mobile/falsepositive markFalsePositive

Normalized (volatile) fields

Compared structurally but blanked to a placeholder because they cannot be deterministic: status/uptimems; mobile/usersuserId, username, upsertResult.insertedId; mobile/subscriptions/allowner, createdAt, updatedAt; mobile/falsepositiveupsert.insertedId.

Everything else (ids of seeded docs, geometries, counts, jsend envelope, field names and types) is asserted byte-for-byte.