test(executor): restore the catastrophic matchers vs step timeout test
It was dropped by mistake when the save-state tests were rewritten (GO-008).
- commit
- c19a4816b929a0ccc9ab47ba6b219863926cb13b
- author
- brice · · 2026-10-14 02:53 UTC
- parent
- 1955003
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
1 file · +36 -0
M internal/executor/results_test.go +36 -0
| @@ -394,3 +394,39 @@ func TestEmbeddedScopeSharesTheOuterStep(t *testing.T) { | |||
| 394 | 394 | t.Errorf("%v", g) | |
| 395 | 395 | } | |
| 396 | 396 | } | |
| 397 | + | ||
| 398 | + | // Several catastrophic matchers and a step timeout: the step ends at its | |
| 399 | + | // timeout, not after every matcher has used its 3 attempts on every line | |
| 400 | + | // (GO-004). Without the cancellation of the matchers the 8 matchers x 3 | |
| 401 | + | // attempts x 1 s of the first line alone hold the step for 24 s. | |
| 402 | + | func TestCatastrophicMatchersDoNotHoldAStepPastItsTimeout(t *testing.T) { | |
| 403 | + | needTools(t, "bash") | |
| 404 | + | var matchers []string | |
| 405 | + | var adds []string | |
| 406 | + | for i := range 8 { | |
| 407 | + | matchers = append(matchers, fmt.Sprintf(`{"owner":"bad%d","pattern":[{"regexp":"^((a+)+)$","message":1}]}`, i)) | |
| 408 | + | } | |
| 409 | + | adds = append(adds, `echo '{"problemMatcher":[`+strings.Join(matchers, ",")+`]}' > bad.json`) | |
| 410 | + | start := time.Now() | |
| 411 | + | rr, _ := runResults(t, wfHead+` steps: | |
| 412 | + | - name: slow lines | |
| 413 | + | timeout-minutes: 1 | |
| 414 | + | run: | | |
| 415 | + | `+adds[0]+` | |
| 416 | + | echo "::add-matcher::bad.json" | |
| 417 | + | for i in 1 2 3 4 5 6; do echo "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!"; done | |
| 418 | + | sleep 30 | |
| 419 | + | `, func(c *Config) { c.StepTimeoutSkew = -(60*time.Second - 1500*time.Millisecond) }) | |
| 420 | + | took := time.Since(start) | |
| 421 | + | if took > 8*time.Second { | |
| 422 | + | t.Errorf("the step overran its timeout: %v", took) | |
| 423 | + | } | |
| 424 | + | log := logOf(rr.step(t, "slow lines")) | |
| 425 | + | if !strings.Contains(log, "The action 'slow lines' has timed out after 1 minutes.") { | |
| 426 | + | t.Errorf("no timeout message:\n%s", log) | |
| 427 | + | } | |
| 428 | + | // the lines that were not matched are still logged | |
| 429 | + | if strings.Count(log, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!") < 6 { | |
| 430 | + | t.Errorf("lines lost after the cancellation:\n%s", log) | |
| 431 | + | } | |
| 432 | + | } | |
| @@ -394,3 +394,39 @@ func TestEmbeddedScopeSharesTheOuterStep(t *testing.T) { | |||||
| 394 | t.Errorf("%v", g) | 394 | t.Errorf("%v", g) | ||
| 395 | } | 395 | } | ||
| 396 | } | 396 | } | ||
| 397 | + | ||||
| 398 | + | // Several catastrophic matchers and a step timeout: the step ends at its | |||
| 399 | + | // timeout, not after every matcher has used its 3 attempts on every line | |||
| 400 | + | // (GO-004). Without the cancellation of the matchers the 8 matchers x 3 | |||
| 401 | + | // attempts x 1 s of the first line alone hold the step for 24 s. | |||
| 402 | + | func TestCatastrophicMatchersDoNotHoldAStepPastItsTimeout(t *testing.T) { | |||
| 403 | + | needTools(t, "bash") | |||
| 404 | + | var matchers []string | |||
| 405 | + | var adds []string | |||
| 406 | + | for i := range 8 { | |||
| 407 | + | matchers = append(matchers, fmt.Sprintf(`{"owner":"bad%d","pattern":[{"regexp":"^((a+)+)$","message":1}]}`, i)) | |||
| 408 | + | } | |||
| 409 | + | adds = append(adds, `echo '{"problemMatcher":[`+strings.Join(matchers, ",")+`]}' > bad.json`) | |||
| 410 | + | start := time.Now() | |||
| 411 | + | rr, _ := runResults(t, wfHead+` steps: | |||
| 412 | + | - name: slow lines | |||
| 413 | + | timeout-minutes: 1 | |||
| 414 | + | run: | | |||
| 415 | + | `+adds[0]+` | |||
| 416 | + | echo "::add-matcher::bad.json" | |||
| 417 | + | for i in 1 2 3 4 5 6; do echo "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!"; done | |||
| 418 | + | sleep 30 | |||
| 419 | + | `, func(c *Config) { c.StepTimeoutSkew = -(60*time.Second - 1500*time.Millisecond) }) | |||
| 420 | + | took := time.Since(start) | |||
| 421 | + | if took > 8*time.Second { | |||
| 422 | + | t.Errorf("the step overran its timeout: %v", took) | |||
| 423 | + | } | |||
| 424 | + | log := logOf(rr.step(t, "slow lines")) | |||
| 425 | + | if !strings.Contains(log, "The action 'slow lines' has timed out after 1 minutes.") { | |||
| 426 | + | t.Errorf("no timeout message:\n%s", log) | |||
| 427 | + | } | |||
| 428 | + | // the lines that were not matched are still logged | |||
| 429 | + | if strings.Count(log, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!") < 6 { | |||
| 430 | + | t.Errorf("lines lost after the cancellation:\n%s", log) | |||
| 431 | + | } | |||
| 432 | + | } | |||