test(décisions): horloge murale figée au démarrage de chaque processus (brief 4 T0.5)
Constaté le 2026-10-16 : sur un code inchangé, la vérification échouait une heure après la génération de la référence. testTheLearningLogIsFedByTheCycle date ses entrées sur QDateTime::currentDateTimeUtc() (l'heure courante plus trois jours) : la référence ne valait que dans l'heure UTC où elle avait été produite. L'enregistreur définit clock_gettime : avec ETM_DECISIONS_EPOCH, CLOCK_REALTIME part de cet instant au premier appel puis avance au rythme réel ; les horloges monotones (QTimer, QElapsedTimer) ne sont pas touchées. Le lanceur pose 2026-10-16T05:00:00Z, l'heure où la référence a été générée : la référence commitée n'est pas régénérée, elle est reproduite à l'octet (md5 ea2c1db7…, 23 739 lignes). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ac6dedbd53
commit
e5c649e69a
@ -33,6 +33,9 @@
|
||||
* Deux exécutions du même code doivent donner le même fichier à l'octet près : c'est ainsi que
|
||||
* cette liste a été établie (2026-10-16), et c'est ainsi qu'on vérifiera un ajout.
|
||||
*
|
||||
* L'horloge murale du processus est figée à son démarrage (ETM_DECISIONS_EPOCH, posé par le
|
||||
* lanceur) : voir `clock_gettime` plus bas.
|
||||
*
|
||||
* Le contrôle ne doit pas pouvoir disparaître en silence (AGENTS.md) : un cycle sur un
|
||||
* gestionnaire qui n'est pas un EnergyArbitrator s'écrit `"arbitre": false`, et le lanceur
|
||||
* refuse un fichier où aucun cycle n'a été enregistré.
|
||||
@ -53,6 +56,34 @@
|
||||
|
||||
#include "../../../energyplugin/etm/scheduler/rulebasedscheduler.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <time.h>
|
||||
|
||||
/* L'HORLOGE MURALE FIGÉE AU DÉMARRAGE. Des scénarios bâtissent leurs dates sur
|
||||
* QDateTime::currentDateTimeUtc() (testTheLearningLogIsFedByTheCycle : l'heure courante, plus
|
||||
* trois jours) : sans ceci, la référence ne vaudrait que dans l'heure UTC où elle a été générée
|
||||
* — constaté le 2026-10-16, une heure plus tard, sur un code inchangé.
|
||||
*
|
||||
* Avec ETM_DECISIONS_EPOCH=<secondes Unix>, CLOCK_REALTIME part de cet instant au premier appel
|
||||
* du processus, puis avance au rythme réel. Les horloges monotones (QTimer, QElapsedTimer) ne
|
||||
* sont pas touchées. L'exécutable définit `clock_gettime` : Qt et la libstdc++, qui l'appellent
|
||||
* par la PLT, résolvent vers celle-ci avant celle de la libc. */
|
||||
extern "C" int clock_gettime(clockid_t horloge, struct timespec *ts) noexcept
|
||||
{
|
||||
using Reelle = int (*)(clockid_t, struct timespec *);
|
||||
static const Reelle reelle = reinterpret_cast<Reelle>(dlsym(RTLD_NEXT, "clock_gettime"));
|
||||
const int r = reelle(horloge, ts);
|
||||
if (r != 0 || (horloge != CLOCK_REALTIME && horloge != CLOCK_REALTIME_COARSE))
|
||||
return r;
|
||||
static const char *const epoque = getenv("ETM_DECISIONS_EPOCH");
|
||||
if (!epoque)
|
||||
return r;
|
||||
// Initialisation d'une statique locale : une seule fois, au premier appel, et sûre entre fils.
|
||||
static const long long decalage = atoll(epoque) - static_cast<long long>(ts->tv_sec);
|
||||
ts->tv_sec += decalage;
|
||||
return r;
|
||||
}
|
||||
|
||||
#define REEL_CYCLE __real__ZN20SmartChargingManager20simulationCallUpdateERK9QDateTime
|
||||
#define ENVEL_CYCLE __wrap__ZN20SmartChargingManager20simulationCallUpdateERK9QDateTime
|
||||
#define REEL_PLAN __real__ZN18RuleBasedScheduler7getPlanERK14SurplusContext
|
||||
|
||||
@ -32,6 +32,11 @@ esac
|
||||
TRAVAIL="$(mktemp -d)"
|
||||
trap 'rm -rf "$TRAVAIL"' EXIT
|
||||
|
||||
# L'HORLOGE MURALE de chaque processus part de cet instant (voir decisionrecorder.cpp) : des
|
||||
# scénarios datent leurs entrées sur l'heure courante, et la référence doit valoir à toute heure.
|
||||
# 2026-10-16T05:00:00Z, début d'heure : un test qui arrondit à l'heure a 60 min de marge.
|
||||
EPOQUE=1792126800
|
||||
|
||||
export NYMEA_PLUGINS_PATH="$BUILD/tests/mocks/plugins/energymocks:/usr/lib/x86_64-linux-gnu/nymea/plugins"
|
||||
|
||||
# UN /tmp PRIVÉ ET VIDE PAR PROCESSUS. libnymea range l'état du serveur de test sous
|
||||
@ -41,7 +46,7 @@ export NYMEA_PLUGINS_PATH="$BUILD/tests/mocks/plugins/energymocks:/usr/lib/x86_6
|
||||
# isolation, le résultat dépendrait de l'historique de la machine, pas du code.
|
||||
lancer() { # $1 = fonction, $2 = fichier NDJSON du test
|
||||
rm -f "$2"
|
||||
( cd "$BIN_DIR" && ETM_DECISIONS_OUT="$2" \
|
||||
( cd "$BIN_DIR" && ETM_DECISIONS_OUT="$2" ETM_DECISIONS_EPOCH="$EPOQUE" \
|
||||
systemd-run --user --scope -q -p MemoryMax=2G -p MemorySwapMax=0 \
|
||||
bwrap --dev-bind / / --tmpfs /tmp --bind "$BUILD" "$BUILD" --bind "$TRAVAIL" "$TRAVAIL" \
|
||||
--chdir "$BIN_DIR" \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user