Vaste wachttijden in tests: de linux-gate viel negen keer om, de poort ertegen mat bijna niets #1911

Closed
opened 2026-09-01 19:48:10 +00:00 by brenno · 3 comments
Owner

Wat er misging

image_carousel_delete_test.dart liet de linux-gate tussen 21-08 en 01-09 negen keer omvallen (taken 2594, 3099, 3404, 3658, 4283, 4366, 4974, 4986, 5317). Elke keer een andere testnaam, dus het las als toeval — het was negen keer dezelfde regel.

pumpPicker wachtte 300 ms wandelklok en nam daarna aan dat de mapscan van de afbeeldingkiezer klaar was. Op de runner (vier kernen, --concurrency=14) is hij dat soms niet: _loading staat nog op true, de Verwijderen-knop staat niet in de boom, en tester.tap vindt niets. Welke test dat trof, hing van de planning af.

Lokaal gereproduceerd door dezelfde wachttijd naar 0 te zetten: alle zeven tests vallen om met exact de faalmelding uit het joblog.

Wat er niet werkte

De poort hiervoor bestaat al (_fixedDelayInRunAsync in tool/check_conventions.dart), en heeft dit anderhalve maand niet gezien:

  • hij zocht de kale schrijfwijze Future.delayed(, terwijl 126 van de 129 wachtpunten in test/ Future<void>.delayed( schrijven;
  • hij keek 400 tekens voorbij de runAsync( — minder dan één pumpWidget met een widgetboom erin, en juist dáár stond het wachtpunt dat de gate deed omvallen.

Netto zag hij 3 van de 129 en meldde groen.

Gedaan

  • alle wachtpunten in image_carousel_delete_test wachten op de uitkomst (pumpUntil); het bestand draait nu in 2 s;
  • de poort kent het typeargument en telt haakjes tot het einde van de aanroep;
  • test/fixed_delay_ratchet_test.dart houdt beide blinde vlekken vast (allebei bewezen rood tegen de oude poort);
  • de achterstand die daardoor zichtbaar werd staat als krimp-alleen basislijn fixedDelayBaseline: 25 bestanden, 37 wachtpunten.

Wat er open blijft

De basislijn scheidt twee soorten. Bewuste uitzondering (7 wachtpunten, redenen staan in pump_until.dart): media_lifecycle, media_previews_video_coverage, image_carousel_picker_smoke, shell_s3_actions, shell_webdav_actions.

Schuld (30 wachtpunten), waarvan bewezen rood op de gate:

  • callout_accessibility_test (5) — omgevallen 31-08 (taak 5001) en 01-09 (taak 5200). Meest waarschijnlijke volgende storing.
  • callout_reveal_test — omgevallen 01-09 (taak 5200); zijn wachtpunt staat in een helper en de poort ziet hem daarom niet.
  • document_editor_screen_test (3) — vijf keer omgevallen op 24/25-08.
  • export_dialog_pdf_end_to_end_test (1) — omgevallen 24-08; toen is alleen het getal verhoogd.

Die callout-tests draaien zelf al binnen runAsync, waar pumpUntil niet kan (geneste runAsync is verboden). Daar is een variant voor nodig die binnen runAsync polt.

## Wat er misging `image_carousel_delete_test.dart` liet de linux-gate tussen 21-08 en 01-09 **negen keer** omvallen (taken 2594, 3099, 3404, 3658, 4283, 4366, 4974, 4986, 5317). Elke keer een andere testnaam, dus het las als toeval — het was negen keer dezelfde regel. `pumpPicker` wachtte 300 ms wandelklok en nam daarna aan dat de mapscan van de afbeeldingkiezer klaar was. Op de runner (vier kernen, `--concurrency=14`) is hij dat soms niet: `_loading` staat nog op true, de Verwijderen-knop staat niet in de boom, en `tester.tap` vindt niets. Welke test dat trof, hing van de planning af. Lokaal gereproduceerd door dezelfde wachttijd naar 0 te zetten: alle zeven tests vallen om met exact de faalmelding uit het joblog. ## Wat er niet werkte De poort hiervoor bestaat al (`_fixedDelayInRunAsync` in `tool/check_conventions.dart`), en heeft dit anderhalve maand niet gezien: - hij zocht de kale schrijfwijze `Future.delayed(`, terwijl **126 van de 129** wachtpunten in `test/` `Future<void>.delayed(` schrijven; - hij keek 400 tekens voorbij de `runAsync(` — minder dan één `pumpWidget` met een widgetboom erin, en juist dáár stond het wachtpunt dat de gate deed omvallen. Netto zag hij 3 van de 129 en meldde groen. ## Gedaan - alle wachtpunten in `image_carousel_delete_test` wachten op de uitkomst (`pumpUntil`); het bestand draait nu in 2 s; - de poort kent het typeargument en telt haakjes tot het einde van de aanroep; - `test/fixed_delay_ratchet_test.dart` houdt beide blinde vlekken vast (allebei bewezen rood tegen de oude poort); - de achterstand die daardoor zichtbaar werd staat als krimp-alleen basislijn `fixedDelayBaseline`: 25 bestanden, 37 wachtpunten. ## Wat er open blijft De basislijn scheidt twee soorten. **Bewuste uitzondering** (7 wachtpunten, redenen staan in `pump_until.dart`): media_lifecycle, media_previews_video_coverage, image_carousel_picker_smoke, shell_s3_actions, shell_webdav_actions. **Schuld** (30 wachtpunten), waarvan bewezen rood op de gate: - `callout_accessibility_test` (5) — omgevallen 31-08 (taak 5001) en 01-09 (taak 5200). Meest waarschijnlijke volgende storing. - `callout_reveal_test` — omgevallen 01-09 (taak 5200); zijn wachtpunt staat in een helper en de poort ziet hem daarom niet. - `document_editor_screen_test` (3) — vijf keer omgevallen op 24/25-08. - `export_dialog_pdf_end_to_end_test` (1) — omgevallen 24-08; toen is alleen het getal verhoogd. Die callout-tests draaien zelf al binnen `runAsync`, waar `pumpUntil` niet kan (geneste `runAsync` is verboden). Daar is een variant voor nodig die binnen `runAsync` polt.
Author
Owner

Opgepakt op tak fix/carousel-delete-flake.

Opgepakt op tak `fix/carousel-delete-flake`.
Author
Owner

De twee callout-bestanden zijn er alsnog bij gepakt en zitten in dezelfde PR.

Ze kregen een andere behandeling dan de carousel-test, om twee redenen. Ze draaien zelf al binnen `runAsync`, waar een geneste `runAsync` — en dus `pumpUntil` — niet kan. En twee van de toetsen bewijzen afwezigheid: de geredigeerde dia en de niet-onthulde groep tekenen met opzet niets, en dat is in de widgetboom niet te onderscheiden van "nog niet gedecodeerd". Er valt daar dus niets aan te wijzen om op te wachten; die toetsen slaagden ook wanneer er nog niets getekend wás.

Dus niet beter wachten maar het wachten weghalen: de test laadt het beeld voor (`test/support/warm_image_cache.dart`), waarna `resolveIntrinsicSize` zijn maat synchroon teruggeeft en de overlay in de eerste build tekent. Dat pad bestaat al voor de rasterexports, die hun beelden om precies dezelfde reden voorladen.

Bewezen dragend: zonder de voorlaadaanroep vallen precies de drie toetsen om die op gerenderde inhoud toetsen, en de andere twee niet.

Basislijn van 25 naar 24 bestanden, 37 naar 32 wachtpunten.

Wat open blijft: document_editor_screen_test (5× rood op 24/25-08) en export_dialog_pdf_end_to_end_test (24-08), plus de 23 nog niet rood geziene wachtpunten. En één blinde vlek in de poort zelf — een wachtpunt in een helper die vanuit runAsync wordt aangeroepen staat er niet lexicaal in, dus die ziet hij niet. callout_reveal_test had precies die vorm. Dat staat nu als zodanig in CHECKS.md.

De twee callout-bestanden zijn er alsnog bij gepakt en zitten in dezelfde PR. Ze kregen een andere behandeling dan de carousel-test, om twee redenen. Ze draaien zelf al binnen \`runAsync\`, waar een geneste \`runAsync\` — en dus \`pumpUntil\` — niet kan. En twee van de toetsen bewijzen *afwezigheid*: de geredigeerde dia en de niet-onthulde groep tekenen met opzet niets, en dat is in de widgetboom niet te onderscheiden van "nog niet gedecodeerd". Er valt daar dus niets aan te wijzen om op te wachten; die toetsen slaagden ook wanneer er nog niets getekend wás. Dus niet beter wachten maar het wachten weghalen: de test laadt het beeld voor (\`test/support/warm_image_cache.dart\`), waarna \`resolveIntrinsicSize\` zijn maat synchroon teruggeeft en de overlay in de eerste build tekent. Dat pad bestaat al voor de rasterexports, die hun beelden om precies dezelfde reden voorladen. Bewezen dragend: zonder de voorlaadaanroep vallen precies de drie toetsen om die op gerenderde inhoud toetsen, en de andere twee niet. Basislijn van 25 naar 24 bestanden, 37 naar 32 wachtpunten. Wat open blijft: `document_editor_screen_test` (5× rood op 24/25-08) en `export_dialog_pdf_end_to_end_test` (24-08), plus de 23 nog niet rood geziene wachtpunten. En één blinde vlek in de poort zelf — een wachtpunt in een helper die vanuit `runAsync` wordt *aangeroepen* staat er niet lexicaal in, dus die ziet hij niet. `callout_reveal_test` had precies die vorm. Dat staat nu als zodanig in CHECKS.md.
Author
Owner

Vervolg gemerged als 4ac8502bc (#1915). Daarmee zijn de drie punten die hierboven open bleven, dicht.

De poortblinde vlek. De meting loopt over de AST met een call-graph binnen het bestand, dus een wachtpunt in een hulp die vánuit runAsync wordt aangeroepen telt mee. Op de huidige boom vindt de AST exact dezelfde verzameling als de tekstversie — callout_reveal_test was het enige geval en dat was al om. Het is dus preventie, geen nieuwe vondst. Bijvangst: commentaar en stringliteralen vallen vanzelf buiten de meting, dus de drie tekstfilters konden weg. En een bestand dat niet parseert wordt gemeld in plaats van overgeslagen.

De schuld. De twee bewezen rode bestanden zijn om. Twee van die vier wachtpunten waren bij nader inzien al pollussen mét afbreekvoorwaarde — de poort ziet dat verschil niet en boekte ze onterecht als gok. Basislijn 24 → 22 bestanden, 32 → 28 wachtpunten; alle resterende zijn nog niet rood gezien.

Wat géén poort dekt. De test die vijf keer omviel faalde niet op een wandelklok maar op twee kale pump()-frames vóór een assertie over een asynchrone terugval — een gok in frames. Die test wacht nu op de uitkomst, maar er is geen poort omheen gebouwd: ik heb er één geval van en weet niet hoe breed het is. Staat als beperking in CHECKS.md.

De joblogs. Nagemeten over veertien dagen: van 2.562 geslaagde taken missen er 212 hun log, van 445 gefaalde / 152 afgebroken / 11 overgeslagen taken nul. Het log dat je bij een rode poort nodig hebt is er dus altijd; alleen groene runs zijn soms niet na te lezen. De API geeft ook in Forgejo 16.0.1 nog 404 op elke logroute. Geen actie nodig, wel goed om te weten voordat iemand er weer naar gaat zoeken.

Vervolg gemerged als `4ac8502bc` ([#1915](https://pawprint.vigilis.online/LibreKAT/Ocideck/pulls/1915)). Daarmee zijn de drie punten die hierboven open bleven, dicht. **De poortblinde vlek.** De meting loopt over de AST met een call-graph binnen het bestand, dus een wachtpunt in een hulp die vánuit `runAsync` wordt aangeroepen telt mee. Op de huidige boom vindt de AST exact dezelfde verzameling als de tekstversie — `callout_reveal_test` was het enige geval en dat was al om. Het is dus preventie, geen nieuwe vondst. Bijvangst: commentaar en stringliteralen vallen vanzelf buiten de meting, dus de drie tekstfilters konden weg. En een bestand dat niet parseert wordt gemeld in plaats van overgeslagen. **De schuld.** De twee bewezen rode bestanden zijn om. Twee van die vier wachtpunten waren bij nader inzien al pollussen mét afbreekvoorwaarde — de poort ziet dat verschil niet en boekte ze onterecht als gok. Basislijn 24 → 22 bestanden, 32 → 28 wachtpunten; alle resterende zijn nog niet rood gezien. **Wat géén poort dekt.** De test die vijf keer omviel faalde niet op een wandelklok maar op twee kale `pump()`-frames vóór een assertie over een asynchrone terugval — een gok in frames. Die test wacht nu op de uitkomst, maar er is geen poort omheen gebouwd: ik heb er één geval van en weet niet hoe breed het is. Staat als beperking in CHECKS.md. **De joblogs.** Nagemeten over veertien dagen: van 2.562 geslaagde taken missen er 212 hun log, van 445 gefaalde / 152 afgebroken / 11 overgeslagen taken **nul**. Het log dat je bij een rode poort nodig hebt is er dus altijd; alleen groene runs zijn soms niet na te lezen. De API geeft ook in Forgejo 16.0.1 nog 404 op elke logroute. Geen actie nodig, wel goed om te weten voordat iemand er weer naar gaat zoeken.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#1911
No description provided.