Commit b7e640d9 authored by Tomasz Maczukin's avatar Tomasz Maczukin 🌴

Merge branch 'add-failure-reason-for-execution-timeout' into 'master'

Add  failure reason for execution timeout

See merge request gitlab-org/gitlab-runner!1051
parents 7092cd26 c53e4fe7
......@@ -268,7 +268,10 @@ func (b *Build) handleError(err error) error {
case context.DeadlineExceeded:
b.CurrentState = BuildRunRuntimeTimedout
return &BuildError{Inner: fmt.Errorf("execution took longer than %v seconds", b.GetBuildTimeout())}
return &BuildError{
Inner: fmt.Errorf("execution took longer than %v seconds", b.GetBuildTimeout()),
FailureReason: JobExecutionTimeout,
}
default:
b.CurrentState = BuildRunRuntimeFinished
......@@ -379,6 +382,35 @@ func (b *Build) waitForTerminal(timeout time.Duration) {
}
}
func (b *Build) setTraceStatus(trace JobTrace, err error) {
logger := b.logger.WithFields(logrus.Fields{
"duration": b.Duration(),
})
if err == nil {
logger.Infoln("Job succeeded")
trace.Success()
return
}
if buildError, ok := err.(*BuildError); ok {
logger.SoftErrorln("Job failed:", err)
failureReason := buildError.FailureReason
if failureReason == "" {
failureReason = ScriptFailure
}
trace.Fail(err, failureReason)
return
}
logger.Errorln("Job failed (system failure):", err)
trace.Fail(err, RunnerSystemFailure)
}
func (b *Build) CurrentExecutorStage() ExecutorStage {
if b.executorStageResolver == nil {
b.executorStageResolver = func() ExecutorStage {
......@@ -401,20 +433,7 @@ func (b *Build) Run(globalConfig *Config, trace JobTrace) (err error) {
b.CurrentState = BuildRunStatePending
defer func() {
logger := b.logger.WithFields(logrus.Fields{
"duration": b.Duration(),
})
if _, ok := err.(*BuildError); ok {
logger.SoftErrorln("Job failed:", err)
trace.Fail(err, ScriptFailure)
} else if err != nil {
logger.Errorln("Job failed (system failure):", err)
trace.Fail(err, RunnerSystemFailure)
} else {
logger.Infoln("Job succeeded")
trace.Success()
}
b.setTraceStatus(trace, err)
if executor != nil {
executor.Cleanup()
......
......@@ -5,6 +5,7 @@ import (
"fmt"
"os"
"testing"
"time"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
......@@ -181,6 +182,111 @@ func TestPrepareFailureOnBuildError(t *testing.T) {
assert.IsType(t, err, &BuildError{})
}
func TestJobFailure(t *testing.T) {
e := new(MockExecutor)
defer e.AssertExpectations(t)
p := new(MockExecutorProvider)
defer p.AssertExpectations(t)
// Create executor
p.On("CanCreate").Return(true).Once()
p.On("GetDefaultShell").Return("bash").Once()
p.On("GetFeatures", mock.Anything).Return(nil).Twice()
p.On("Create").Return(e).Times(1)
// Prepare plan
e.On("Prepare", mock.Anything, mock.Anything, mock.Anything).
Return(nil).Times(1)
e.On("Cleanup").Return().Times(1)
// Succeed a build script
thrownErr := &BuildError{Inner: errors.New("test error")}
e.On("Shell").Return(&ShellScriptInfo{Shell: "script-shell"})
e.On("Run", mock.Anything).Return(thrownErr)
e.On("Finish", thrownErr).Return().Once()
RegisterExecutor("build-run-job-failure", p)
failedBuild, err := GetFailedBuild()
assert.NoError(t, err)
build := &Build{
JobResponse: failedBuild,
Runner: &RunnerConfig{
RunnerSettings: RunnerSettings{
Executor: "build-run-job-failure",
},
},
}
trace := new(MockJobTrace)
defer trace.AssertExpectations(t)
trace.On("Write", mock.Anything).Return(0, nil)
trace.On("IsStdout").Return(true)
trace.On("SetCancelFunc", mock.Anything).Once()
trace.On("Fail", thrownErr, ScriptFailure).Once()
err = build.Run(&Config{}, trace)
require.IsType(t, &BuildError{}, err)
}
func TestJobFailureOnExecutionTimeout(t *testing.T) {
e := new(MockExecutor)
defer e.AssertExpectations(t)
p := new(MockExecutorProvider)
defer p.AssertExpectations(t)
// Create executor
p.On("CanCreate").Return(true).Once()
p.On("GetDefaultShell").Return("bash").Once()
p.On("GetFeatures", mock.Anything).Return(nil).Twice()
p.On("Create").Return(e).Times(1)
// Prepare plan
e.On("Prepare", mock.Anything, mock.Anything, mock.Anything).
Return(nil).Times(1)
e.On("Cleanup").Return().Times(1)
// Succeed a build script
e.On("Shell").Return(&ShellScriptInfo{Shell: "script-shell"})
e.On("Run", matchBuildStage(BuildStageUserScript)).Run(func(arguments mock.Arguments) {
time.Sleep(2 * time.Second)
}).Return(nil)
e.On("Run", mock.Anything).Return(nil)
e.On("Finish", mock.Anything).Return().Once()
RegisterExecutor("build-run-job-failure-on-execution-timeout", p)
successfulBuild, err := GetSuccessfulBuild()
assert.NoError(t, err)
successfulBuild.RunnerInfo.Timeout = 1
build := &Build{
JobResponse: successfulBuild,
Runner: &RunnerConfig{
RunnerSettings: RunnerSettings{
Executor: "build-run-job-failure-on-execution-timeout",
},
},
}
trace := new(MockJobTrace)
defer trace.AssertExpectations(t)
trace.On("Write", mock.Anything).Return(0, nil)
trace.On("IsStdout").Return(true)
trace.On("SetCancelFunc", mock.Anything).Once()
trace.On("Fail", mock.Anything, JobExecutionTimeout).Run(func(arguments mock.Arguments) {
assert.Error(t, arguments.Get(0).(error))
}).Once()
err = build.Run(&Config{}, trace)
require.IsType(t, &BuildError{}, err)
}
func matchBuildStage(buildStage BuildStage) interface{} {
return mock.MatchedBy(func(cmd ExecutorCommand) bool {
return cmd.Stage == buildStage
......
......@@ -54,7 +54,8 @@ type ExecutorProvider interface {
}
type BuildError struct {
Inner error
Inner error
FailureReason JobFailureReason
}
func (b *BuildError) Error() string {
......
......@@ -25,6 +25,7 @@ const (
NoneFailure JobFailureReason = ""
ScriptFailure JobFailureReason = "script_failure"
RunnerSystemFailure JobFailureReason = "runner_system_failure"
JobExecutionTimeout JobFailureReason = "job_execution_timeout"
)
const (
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment