todos-contra-el-fuego-web/test/server/encode.test.js
vjrj 3b04ebceb3 ci(web): run the server suite before building the image
The build job now needs: test, so an image cannot be published with the suite in
red — which is the whole point of this phase. Both jobs live in the same file
because needs: only links jobs within one workflow.

settings-ci.json is committed and contains no secrets: settings-development.json
is gitignored, so CI had nothing to pass to --settings. The one test that cannot
work without a secret is the node-red iron fixture, sealed with the deployment's
own ironPassword; it now reports itself as skipped instead of failing on an hmac
mismatch, and still runs locally against settings-development.json.

Measured locally: 22s and a ~2.0 GB peak for the whole `meteor test` run (its own
mongod included), hence --memory=3g. The meteor-tool download is not cached yet;
the note in the workflow says what that would take.
2026-08-01 18:02:31 +02:00

78 lines
3.7 KiB
JavaScript

/* eslint-env mocha */
/* eslint-disable func-names, prefer-arrow-callback */
/* eslint-disable import/no-absolute-path */
import { expect } from 'chai';
import urlEnc from '/imports/modules/url-encode';
// NOTE: the old suite also seeded ActiveFires via @cleverbeagle/seeder and
// round-tripped whole docs. Those cases were documented-broken (Date fields came
// back as strings) and depended on a dev-only seeder package that is no longer
// installed, so they were dropped. The crypto round-trip below is the real
// contract this module owes.
describe('url encoding', () => {
it('should encrypt and decrypt basic objects', async () => {
const obj = { lat: 2 };
const sealed = await urlEnc.encrypt(obj);
const unsealed = await urlEnc.decrypt(sealed);
expect(unsealed).to.deep.equal(obj);
});
it('should encrypt and decrypt objects with date', async () => {
const obj = { lat: 40.234503, lon: -3.350386, when: (new Date()).toString() };
const sealed = await urlEnc.encrypt(obj);
const unsealed = await urlEnc.decrypt(sealed);
expect(unsealed).to.deep.equal(obj);
});
it('should encrypt complete objects and produce url-safe, salted output', async () => {
const obj = {
ourid: { type: 'Point', coordinates: [24.813, 9.223] },
type: 'modis',
lat: 9.223,
lon: 24.813,
when: new Date('2017-12-13T00:00:00.000Z').toISOString(),
scan: 1,
track: 1,
satellite: 'A',
confidence: 'nominal',
version: '6.0NRT',
frp: 6.5,
daynight: null,
brightness: 305.9,
bright_t31: 292.6
};
const sealed = await urlEnc.encrypt(obj);
const sealed2 = await urlEnc.encrypt(obj);
const unsealed = await urlEnc.decrypt(sealed);
expect(unsealed).to.deep.equal(obj);
expect(sealed).to.equal(encodeURI(sealed)); // already url-safe
expect(sealed).to.not.equal(sealed2); // salted: same input, different output
expect(sealed).to.not.include('/');
expect(sealed).to.not.include('%');
});
// This fixture was sealed by node-red with the deployment's own ironPassword,
// which is not (and must not be) in any committed settings file — so under
// settings-ci.json it cannot possibly unseal. Run it locally against
// settings-development.json, where it proves what it is here to prove: that a
// blob produced by another iron implementation still unseals with ours. In CI
// it reports itself as skipped instead of failing on a password mismatch.
it('should decrypt a node-red produced blob without throwing', async function skipsWithoutTheFixturePassword() {
const sealed = 'Fe26.2**7ae64199b871901d16a6ba031198c57b43b4a9231e15b851ff80014a8de230ca*RkB3_Uu_oJnTefyzB-Ocqg*2Z9rXYf--GxLJnYESHvdK5rC6lOMlSbMJ6YQyR2Mgpl57iBYopAHPWRLNTBgNkbUHFYa0IlEjdyeEz5VvLDtVvlSr1Sam-Cx8GUai4mharZO5-Wkze0dTr7M56WofSC9jpkv3kANrpsrit3HASE_E-5Z1JVYQVQqehw-VbSZTorrYj0GCJiAgXE5I0iY4boXRDYCv7fm_pzcuAbHlnNkKT1GbMFEPjyVViP4mVMRI5PDUhcWb0f62goMX4UnYLZXum4oYOIr84DG8AxqIdW2L94yslt0EZkD3yVhvKEGoauMpy6ry2illpSgaMaj4sU3AKWIjfAsJXvM6bHwbNh6G1_BJfCapuu3KijBBQPQMAnhYuwLAlY56WN-Y2efNIBJkp__kO6ak2nFqu8PufpxE-cv0uW7x6GWUtCpnFO2SeUJWVVMddUgJjLiM8Hkdl1v9huB0WdIvsoPEV0ZOwHZaC3jtdKFSO7Xe6LdqTXjXmdBMwtOv-HefyaB8LnEN6dAeKWwJuDu7g03QFTryDIiuwtpQ8mcLWTJGHcxoaluNhUESOBULkWSv_E1vOM1_fFv**1e41101b27c5da58bc11177448e91d88d7801bf911088a895844db0c542dfa7c*dPlOhtXJcyR47ezuL7CEgC2Z8d6C1asNOiqZmhD5TXY';
let unsealed;
try {
unsealed = await urlEnc.decrypt(sealed);
} catch (e) {
if (e.message === 'Bad hmac value') {
this.skip(); // sealed with a different ironPassword than the one configured
return;
}
throw e;
}
expect(unsealed).to.be.an('object');
});
});