fix(test-curl): keep the socket pass off the environment (#41) #45
No reviewers
Labels
No labels
autopilot:pending-human
source:analyste
source:defenseur
source:human
source:medic
status:approved
status:blocked
status:in-progress
status:needs-clarification
status:needs-fix
status:ready
status:review
status:triage
type:bug
type:feature
type:infra
type:refactor
type:schema
type:security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: maximus/vps-health-api#45
Loading…
Reference in a new issue
No description provided.
Delete branch "issue-41-test-curl-no-proxy"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #41
Corps mis à jour après la revue (commentaire 17831) : il décrit la tête actuelle, trois commits au-dessus de
main. Le troisième applique les suggestions non bloquantes de la seconde revue (commentaire 17881).Ce qui change
test-curl.shenvoyait ses 18 lignescurlau proxy de l'environnement au lieu de ses propres serveurs. Derrière un proxy mort, il sortait en code 7 après 11 s, sans une ligne.Dans
test-curl.sh:export NO_PROXY='*' no_proxy='*'en tête, commescripts/boot-from-copy.sh.require_free <url>, avant tout lancement : les deux ports doivent refuser la connexion (code curl 7, même règle queboot-from-copy.sh). C'est ce contrôle qui écarte un voisin déjà en place.wait_for <url> <pid>remplace les deux boucles d'attente. Il arrête le script, avec un message sur stderr et le code 1, quand le serveur meurt ou ne répond pas dans les 5 s (borne par horloge). Il vérifie le processus avant et après la sonde.unset FORCE_COLOR: sous cette variable,node -e 'console.log(3)'colore le nombre même dans un tube, et 8 cas échouaient (mesuré surmainavecFORCE_COLOR=3: 37 passed, 8 failed).trap EXITprotège chaquekillpar|| trueet finit par unwait. Sousset -e, unkillen échec sur le premier serveur déjà mort terminait le trap et laissait le second tourner sur 3098.Dans
__tests__/ci.test.js, undescribe("test-curl.sh")de 8 cas, qui lance le script en entier :http_proxy,ALL_PROXY,no_proxy=example.invalid,NO_PROXYretiré,FORCE_COLOR=3) : vivacité du proxy prouvée par uncurlnu, puis rien ne l'atteint, sortie 0,45 passed, 0 failed./, aucun serveur du script laissé sur l'autre port.nodeen tête dePATHsort en 1 pour le port 3099, puis pour 3098 : message qui nomme l'URL, code 1 en moins de 3 s, aucun cas lancé, ports libérés.run()rend aussi stdout et la durée. Les cas retirentBASE_URLde l'environnement : vite le pose à/dans le processus de test, et le script lit une variable de ce nom.Aucun code runtime ne change : pas de redéploiement après le merge.
Réponse à la revue
Le point bloquant était exact :
wait_forn'écartait pas un voisin déjà en place, et trois textes disaient le contraire. La garantie est maintenant tenue parrequire_free, et les trois textes (commentaire du script,CLAUDE.md, ce corps) disent ce que chaque contrôle fait.Scénario du relecteur rejoué, un serveur HTTP quelconque tenu sur 3099 :
096f95d), mesure du relecteur :exit=1, desFAIL: ... got 200, aucun message, les cas tournent contre le voisin ;exit=1, stderrtest-curl.sh: http://localhost:3099 is already taken (curl exit 0), stdout vide.Suggestions reprises : borne par horloge au lieu de 50 tours, et borne de durée dans les cas d'échec, qui tue le mutant «
exit 1retiré ». Les ports paramétrables restent hors périmètre.Preuve par mutation
Mutations de
test-curl.shappliquées depuis une copie de sauvegarde,ci.test.jsrelancé à chaque fois (30 cas pour a à n, 33 pour o à q), script restauré identique à la copie etgit diff --statinchangé.NO_PROXYexporté seulunset FORCE_COLORretirékill -0retiréexit 1retiré après « exited before answering »wait_forretirétraprétabliwaitretiré dutraprequire_freeretirésrequire_freede 3098 retirérequire_freede 3099 retiréexit 1retiré derequire_freekill -0(après la sonde) retiréwait_forrend 0 à l’échéanceexit 1d’échéance retirésNon épinglés :
kill -0ne couvre que la fenêtre entrerequire_freeet lelistendu serveur, qu'un test ne peut pas ouvrir de façon fiable.NO_PROXY: curl lit la minuscule d'abord,no_proxyseul suffit. Gardée par cohérence avecboot-from-copy.sh.wait_for.Les mutations h et i touchent le nettoyage en fin de script : leur nombre de rouges dépend de l'ordre des cas et peut varier d'un passage à l'autre, comme le relecteur l'a vu.
Vérification
npm test: 363/363 (355 surmain+ 8), avecFORCE_COLOR=3dans l'environnement.bash test-curl.sh: 45 passed, 0 failed.http_proxy=http://127.0.0.1:9 bash test-curl.sh: 45 passed, 0 failed, sortie 0 (critère 1 de l'issue).sh scripts/boot-from-copy.sh: PASS.ci.test.jstrois fois de suite : 33/33 à chaque fois, aucun processus restant sur 3099 ou 3098.Limites
npm testles occupe maintenant quelques secondes. Deuxnpm testsimultanés, ou unbash test-curl.shlancé en même temps, se gênent : au moins l’un des deux échoue, parfois les deux (2 tours sur 6 dans la mesure du relecteur), mais jamais un cas ne tourne contre le serveur de l’autre. Ports paramétrables : issue de suivi ouverte.45est écrit en dur dans le test : ajouter un cas àtest-curl.shimpose de le changer là aussi, en plus deCLAUDE.md.main.🤖 Generated with Claude Code
7003197abeto096f95da05Verdict : REQUEST_CHANGES
Résumé. Le correctif tient ses critères d'acceptation et ses épingles rougissent sous mes propres mutations. Un point bloque : la garantie « un voisin qui répond sur le même port ne passe pas pour le serveur » est écrite à trois endroits et elle est fausse dans le cas courant, mesure à l'appui.
Suite et mutations rejouées par le relecteur sur une copie hors dépôt de la tête
096f95d(git archive), ports 3097 à 3099 vérifiés libres avant et après.Problème bloquant
test-curl.sh:177-185:wait_forn'écarte pas un voisin déjà en place.kill -0passe au premier tour, parce que lenodelancé par le script n'est pas encore mort de sonEADDRINUSE; lecurlqui suit joint le voisin etwait_forrend 0. Le contrôle du processus n'attrape que le serveur mort avant le premier tour, ce que le fauxnodedes tests produit (sortie immédiate), pas une collision de port réelle.Mesuré : un serveur HTTP quelconque tenu sur 3099 et 3098, puis
bash test-curl.sh:Aucun message de
wait_for: les cas tournent contre le voisin. C'est le scénario de la revue parallèle (deuxnpm test, ou unbash test-curl.shpendantnpm test), où le voisin est un autreindex.js, peut-être d'une autre branche, qui rend des réponses crédibles.La garantie est affirmée dans :
test-curl.sh:177-178(« so that a neighbour answering on the same port cannot stand in ») ;CLAUDE.md, paragraphebash test-curl.sh(« un voisin qui repond sur le meme port ne passe pas pour lui ») ;wait_for) »).Deux sorties possibles, au choix :
wait_fordétecte un serveur mort avant de répondre, pas un port déjà pris ; une collision reste un échec sans message dédié. Suffit pour cette PR, l'issue #41 n'exigeant pas la détection du voisin ;boot-from-copy.sh(tout code curl autre que 7 = refus), avec un cas de test à voisin réel. Un secondkill -0après lecurlréussi réduirait la fenêtre sans la fermer.Vérifié
npm test: 358/358.bash test-curl.sh: 45 passed, 0 failed.http_proxy=http://127.0.0.1:9 bash test-curl.sh: 45 passed, 0 failed (critère 1).sh scripts/boot-from-copy.sh: PASS. Mon environnement porteFORCE_COLOR=3.success(statut de commit).pull_refde #45 encloses.test-curl.sh,ci.test.jsrelancé (28 cas), script restauré identique (cmp) :NO_PROXYexporté seulunset FORCE_COLORretirékill -0neutralisétraprétabliConforme au tableau de la PR, sauf la dernière ligne : le nombre de rouges varie d'un passage à l'autre (au moins 1 à chaque fois), et la mutation laisse bien un
node ./index.jsorphelin sur 3098, ce qui confirme le défaut dutrap.Suggestions (non bloquantes)
--max-time 1par tour porte le pire cas à environ 55 s (50 × 1,1 s) si un occupant accepte la connexion sans répondre, alors que le message annonce « after 5 s ». Borne par horloge (SECONDS) ou message sans durée.exit 1retiré » serait tué par une borne de durée dans les deux cas d'échec (moins de 3 s, par exemple).npm test: rendrePORTparamétrable mérite une issue à part, le risque étant désormais présent à chaquenpm testet plus seulement dans l'étape CI.Correctif après la revue 17831, poussé sur la branche. Tête non relue.
Le point bloquant est traité par la seconde sortie proposée :
require_freecontrôle les deux ports avant tout lancement (code curl 7 exigé, commeboot-from-copy.sh), avec un cas de test à voisin réel par port.Scénario de la revue, voisin HTTP sur 3099 :
096f95d)http://localhost:3099 is already taken (curl exit 0)Mutation correspondante, les deux
require_freeretirés : 2 rouges sur 30 (les deux cas à voisin). Suite sans mutation : 0 rouge avant, 0 après restauration.Suggestions reprises :
wait_forborné par horloge, et une borne de 3 s dans les cas de démarrage raté, qui fait passer le mutant «exit 1retiré » de 0 à 2 rouges. Letrapattend maintenant la fin des serveurs qu'il tue. Tableau complet des 13 mutations dans le corps de la PR, mis à jour. Reste non épinglé : le secondkill -0dewait_for.npm test360/360,test-curl.sh45/45 (aussi derrière un proxy mort), boot check PASS.Verdict : APPROVE
Résumé. Le point bloquant de la revue 17831 est levé :
require_freeécarte le voisin avant tout lancement, et les trois textes disent maintenant ce que chaque contrôle fait. Les épingles rougissent sous mes propres mutations ; deux comportements restent sans épingle et ne figurent pas dans la liste « Non épinglés », sans bloquer le merge.Suite et mutations rejouées par le relecteur sur une copie hors dépôt de la tête
193635a(git archive), ports 3097 à 3099 vérifiés libres avant et après,FORCE_COLORprésent dans mon environnement.Vérifié
npm test: 360/360.bash test-curl.sh: 45 passed, 0 failed.http_proxy=http://127.0.0.1:9 bash test-curl.sh: 45 passed, 0 failed (critère 1 de l'issue).sh scripts/boot-from-copy.sh: PASS.193635a:success(statut de commit).pull_refde #45 encloses. Deux commits au format conventionnel.is already taken (curl exit 28)is already taken (curl exit 56)nodevivant qui n'écoute jamais (3099)no server answered at http://localhost:3099 within 5 sDeux
bash test-curl.shlancés au même instant, 6 tours : jamais un cas lancé contre le serveur de l'autre. 4 tours avec un gagnant (45/45) et un perdant, 2 tours où les deux échouent (chacun perd un port). Le message est celui dewait_for(« exited before answering »), la course se jouant aprèsrequire_free.Mutations du relecteur sur
test-curl.sh,ci.test.jsrelancé à chaque fois (30 cas), script restauré identique (cmp), 30/30 avant et après :require_freeretirésexit 1retiré après « exited before answering »waitretiré dutraptraprétablirequire_free: pris seulement si code curl 0 (au lieu de « tout sauf 7 »)wait_for:return 0au lieu deexit 1à l'échéancewait_for: message etexit 1d'échéance supprimésLes cinq premières lignes confirment le tableau de la PR. L'ancien
traplaisse bien unnode ./index.jsorphelin sur 3098.Suggestions (non bloquantes)
CLAUDE.md) :test-curl.sh:64, la règle « tout code autre que 7 = pris ». Les deux cas à voisin n'exercent que le code 0. Le commentairetest-curl.sh:58-60promet 28, 52 et 56 ; le comportement est correct (mesures ci-dessus), mais rien ne le fige. Un voisinnet.createServer(() => {})l'épinglerait, pour 2 s de plus.test-curl.sh:216-217, la sortie à l'échéance des 5 s. Le fauxnodedes tests meurt aussitôt et ne passe que par la première branche. Un fauxnodequi faitexec sleepl'épinglerait, pour environ 5 s de plus. À défaut, ajouter les deux à la liste des non épinglés.CLAUDE.md, paragraphebash test-curl.sh: « Trois protections » en annonce trois et en liste quatre (export,unset FORCE_COLOR,require_free,wait_for).test-curl.sh:47-53: le bloc de commentaire « Fixtures : » se retrouve au-dessus derequire_free(l. 54-70), séparé desmkdirqu'il décrit (l. 72). Déplacerrequire_freeau-dessus du commentaire.npm test: l'issue séparée pour les rendre paramétrables reste à ouvrir.Suggestions de la revue 17881 appliquées, à la demande de Max, puis merge. Le commit
7427577est ajouté après l'APPROVE, qui portait sur193635a: il n'a pas été relu.ci.test.js(33 au total) : occupant de 3099 qui ferme aussitôt, occupant qui accepte sans répondre, serveur vivant qui n'écoute jamais.wait_forqui rend 0 à l'échéance (0, puis 1), message etexit 1d'échéance retirés (0, puis 1). Suite sans mutation : 0 rouge, avant comme après restauration.CLAUDE.mdcompte quatre protections ; le commentaire « Fixtures » retrouve sesmkdir; la section « Limites » du corps dit que les deux passages simultanés peuvent échouer tous les deux.npm test363/363,test-curl.sh45/45 (aussi derrière un proxy mort), boot check PASS.