diff --git a/internal/worker/command_misc.go b/internal/worker/command_misc.go index b40d0465..b41720d4 100644 --- a/internal/worker/command_misc.go +++ b/internal/worker/command_misc.go @@ -49,7 +49,12 @@ func (ce *CommandExecutor) cmdSleep(ctx context.Context, logger zerolog.Logger, return NewParameterInvalidError("duration_in_seconds", cmd, "bad type %T, expecting int or float", sleepTime) } - log.Info().Str("duration", duration.String()).Msg("sleep") + logger = log.With().Str("duration", duration.String()).Logger() + if duration < 0 { + logger.Error().Msg("cannot sleep negative durations") + return NewParameterInvalidError("duration_in_seconds", cmd, "cannot be negative") + } + logger.Info().Msg("sleep") select { case <-ctx.Done(): diff --git a/internal/worker/command_misc_test.go b/internal/worker/command_misc_test.go index f713f888..6c3ad63e 100644 --- a/internal/worker/command_misc_test.go +++ b/internal/worker/command_misc_test.go @@ -74,3 +74,24 @@ loop: // Within the step size is precise enough. We're testing our implementation, not the precision of `time.After()`. assert.WithinDuration(t, timeBefore.Add(47*time.Second), timeAfter, timeStepSize) } + +func TestCommandSleepNegative(t *testing.T) { + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + ce, _ := testCommandExecutor(t, mockCtrl) + + ctx := context.Background() + taskID := "90e9d656-e201-4ef0-b6b0-c80684fafa27" + cmd := api.Command{ + Name: "sleep", + Parameters: map[string]interface{}{"duration_in_seconds": -47}, + } + + err := ce.Run(ctx, taskID, cmd) + var paramErr ParameterInvalidError + if assert.ErrorAs(t, err, ¶mErr) { + assert.Equal(t, "duration_in_seconds", paramErr.Parameter) + assert.Equal(t, -47, paramErr.ParamValue()) + assert.Equal(t, "cannot be negative", paramErr.Message) + } +}