mirror of
https://github.com/go-task/task.git
synced 2026-05-18 13:15:41 +02:00
Compare commits
1 Commits
nightly
...
fix/failfa
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0431e4bf27 |
@@ -7,6 +7,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/sebdah/goldie/v2"
|
"github.com/sebdah/goldie/v2"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@@ -30,13 +31,15 @@ type (
|
|||||||
// gen:fixtures`.
|
// gen:fixtures`.
|
||||||
ExecutorTest struct {
|
ExecutorTest struct {
|
||||||
TaskTest
|
TaskTest
|
||||||
task string
|
task string
|
||||||
vars map[string]any
|
vars map[string]any
|
||||||
input string
|
input string
|
||||||
executorOpts []task.ExecutorOption
|
executorOpts []task.ExecutorOption
|
||||||
wantSetupError bool
|
wantSetupError bool
|
||||||
wantRunError bool
|
wantRunError bool
|
||||||
wantStatusError bool
|
wantStatusError bool
|
||||||
|
skipOutputFixture bool
|
||||||
|
maxDuration time.Duration
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -113,6 +116,32 @@ func (opt *statusErrorTestOption) applyToExecutorTest(t *ExecutorTest) {
|
|||||||
t.wantStatusError = true
|
t.wantStatusError = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithoutOutputFixture disables the stdout/stderr golden fixture comparison.
|
||||||
|
// Use for tasks with non-deterministic output by design (e.g. parallel deps
|
||||||
|
// cancelled mid-execution) where only the run error or timing matters.
|
||||||
|
func WithoutOutputFixture() ExecutorTestOption {
|
||||||
|
return &withoutOutputFixtureTestOption{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type withoutOutputFixtureTestOption struct{}
|
||||||
|
|
||||||
|
func (opt *withoutOutputFixtureTestOption) applyToExecutorTest(t *ExecutorTest) {
|
||||||
|
t.skipOutputFixture = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithMaxDuration asserts the run phase completes within d. Use to verify
|
||||||
|
// that failfast/cancellation kicks in promptly instead of waiting for deps
|
||||||
|
// to finish naturally.
|
||||||
|
func WithMaxDuration(d time.Duration) ExecutorTestOption {
|
||||||
|
return &maxDurationTestOption{d: d}
|
||||||
|
}
|
||||||
|
|
||||||
|
type maxDurationTestOption struct{ d time.Duration }
|
||||||
|
|
||||||
|
func (opt *maxDurationTestOption) applyToExecutorTest(t *ExecutorTest) {
|
||||||
|
t.maxDuration = opt.d
|
||||||
|
}
|
||||||
|
|
||||||
// Helpers
|
// Helpers
|
||||||
|
|
||||||
// writeFixtureErrRun is a wrapper for writing the output of an error during the
|
// writeFixtureErrRun is a wrapper for writing the output of an error during the
|
||||||
@@ -172,7 +201,9 @@ func (tt *ExecutorTest) run(t *testing.T) {
|
|||||||
if err := e.Setup(); tt.wantSetupError {
|
if err := e.Setup(); tt.wantSetupError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
tt.writeFixtureErrSetup(t, g, err)
|
tt.writeFixtureErrSetup(t, g, err)
|
||||||
tt.writeFixtureBuffer(t, g, buffer.buf)
|
if !tt.skipOutputFixture {
|
||||||
|
tt.writeFixtureBuffer(t, g, buffer.buf)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -190,10 +221,18 @@ func (tt *ExecutorTest) run(t *testing.T) {
|
|||||||
|
|
||||||
// Run the task and check for errors
|
// Run the task and check for errors
|
||||||
ctx := t.Context()
|
ctx := t.Context()
|
||||||
if err := e.Run(ctx, call); tt.wantRunError {
|
start := time.Now()
|
||||||
|
err := e.Run(ctx, call)
|
||||||
|
if tt.maxDuration > 0 {
|
||||||
|
require.Less(t, time.Since(start), tt.maxDuration,
|
||||||
|
"task took too long — failfast/cancellation likely did not trigger")
|
||||||
|
}
|
||||||
|
if tt.wantRunError {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
tt.writeFixtureErrRun(t, g, err)
|
tt.writeFixtureErrRun(t, g, err)
|
||||||
tt.writeFixtureBuffer(t, g, buffer.buf)
|
if !tt.skipOutputFixture {
|
||||||
|
tt.writeFixtureBuffer(t, g, buffer.buf)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -206,7 +245,9 @@ func (tt *ExecutorTest) run(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tt.writeFixtureBuffer(t, g, buffer.buf)
|
if !tt.skipOutputFixture {
|
||||||
|
tt.writeFixtureBuffer(t, g, buffer.buf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the test (with a name if it has one)
|
// Run the test (with a name if it has one)
|
||||||
@@ -1130,12 +1171,14 @@ func TestFailfast(t *testing.T) {
|
|||||||
|
|
||||||
NewExecutorTest(t,
|
NewExecutorTest(t,
|
||||||
WithName("default"),
|
WithName("default"),
|
||||||
|
WithVar("SLEEP", "sleep 5 && "),
|
||||||
WithExecutorOptions(
|
WithExecutorOptions(
|
||||||
task.WithDir("testdata/failfast/default"),
|
task.WithDir("testdata/failfast/default"),
|
||||||
task.WithSilent(true),
|
task.WithSilent(true),
|
||||||
task.WithFailfast(true),
|
task.WithFailfast(true),
|
||||||
),
|
),
|
||||||
WithPostProcessFn(PPSortedLines),
|
WithoutOutputFixture(),
|
||||||
|
WithMaxDuration(4*time.Second),
|
||||||
WithRunError(),
|
WithRunError(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -1149,7 +1192,8 @@ func TestFailfast(t *testing.T) {
|
|||||||
task.WithDir("testdata/failfast/task"),
|
task.WithDir("testdata/failfast/task"),
|
||||||
task.WithSilent(true),
|
task.WithSilent(true),
|
||||||
),
|
),
|
||||||
WithPostProcessFn(PPSortedLines),
|
WithoutOutputFixture(),
|
||||||
|
WithMaxDuration(4*time.Second),
|
||||||
WithRunError(),
|
WithRunError(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
18
testdata/failfast/default/Taskfile.yaml
vendored
18
testdata/failfast/default/Taskfile.yaml
vendored
@@ -1,14 +1,20 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
SLEEP: ''
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
default:
|
default:
|
||||||
deps:
|
deps:
|
||||||
- dep1
|
- task: dep1
|
||||||
- dep2
|
vars: { SLEEP: '{{.SLEEP}}' }
|
||||||
- dep3
|
- task: dep2
|
||||||
|
vars: { SLEEP: '{{.SLEEP}}' }
|
||||||
|
- task: dep3
|
||||||
|
vars: { SLEEP: '{{.SLEEP}}' }
|
||||||
- dep4
|
- dep4
|
||||||
|
|
||||||
dep1: sleep 0.1 && echo 'dep1'
|
dep1: '{{.SLEEP}}echo ''dep1'''
|
||||||
dep2: sleep 0.2 && echo 'dep2'
|
dep2: '{{.SLEEP}}echo ''dep2'''
|
||||||
dep3: sleep 0.3 && echo 'dep3'
|
dep3: '{{.SLEEP}}echo ''dep3'''
|
||||||
dep4: exit 1
|
dep4: exit 1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
task: Failed to run task "default": task: Failed to run task "dep4": exit status 1
|
task: Failed to run task "default": task: Failed to run task "dep4": exit status 1
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
6
testdata/failfast/task/Taskfile.yaml
vendored
6
testdata/failfast/task/Taskfile.yaml
vendored
@@ -9,7 +9,7 @@ tasks:
|
|||||||
- dep4
|
- dep4
|
||||||
failfast: true
|
failfast: true
|
||||||
|
|
||||||
dep1: sleep 0.1 && echo 'dep1'
|
dep1: sleep 5 && echo 'dep1'
|
||||||
dep2: sleep 0.2 && echo 'dep2'
|
dep2: sleep 6 && echo 'dep2'
|
||||||
dep3: sleep 0.3 && echo 'dep3'
|
dep3: sleep 7 && echo 'dep3'
|
||||||
dep4: exit 1
|
dep4: exit 1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
task: Failed to run task "default": task: Failed to run task "dep4": exit status 1
|
task: Failed to run task "default": task: Failed to run task "dep4": exit status 1
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
Reference in New Issue
Block a user