Skip to content

Commit edb13af

Browse files
authored
[*] run PROGRAM task for all parameters, fixes #741 (#742)
Previously program task returned on the first fail. This is not how other kind of tasks behave. Make program task compatible with SQL and built-in tasks. All errors will be joined and returned
1 parent ad9c3bc commit edb13af

File tree

3 files changed

+26
-26
lines changed

3 files changed

+26
-26
lines changed

internal/scheduler/shell.go

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ var Cmd commander = realCommander{}
2828

2929
// ExecuteProgramCommand executes program command and returns status code, output and error if any
3030
func (sch *Scheduler) ExecuteProgramCommand(ctx context.Context, task *pgengine.ChainTask, paramValues []string) error {
31-
31+
var err error
32+
var exitCode int
3233
command := strings.TrimSpace(task.Command)
3334
if command == "" {
3435
return errors.New("program command cannot be empty")
@@ -37,24 +38,22 @@ func (sch *Scheduler) ExecuteProgramCommand(ctx context.Context, task *pgengine.
3738
paramValues = []string{""}
3839
}
3940
for _, val := range paramValues {
41+
exitCode = 0
4042
params := []string{}
4143
if val > "" {
4244
if err := json.Unmarshal([]byte(val), &params); err != nil {
4345
return err
4446
}
4547
}
46-
out, err := Cmd.CombinedOutput(ctx, command, params...) // #nosec
47-
if err != nil {
48-
//check if we're dealing with an ExitError - i.e. return code other than 0
48+
out, e := Cmd.CombinedOutput(ctx, command, params...) // #nosec
49+
if e != nil {
50+
exitCode = -1
51+
err = errors.Join(err, e) // accumulate errors for all param sets
4952
if exitError, ok := err.(*exec.ExitError); ok {
50-
exitCode := exitError.ExitCode()
51-
sch.pgengine.LogTaskExecution(context.Background(), task, exitCode, string(out), val)
52-
return exitError
53+
exitCode = exitError.ExitCode()
5354
}
54-
sch.pgengine.LogTaskExecution(context.Background(), task, -1, string(out), val)
55-
return err
5655
}
57-
sch.pgengine.LogTaskExecution(context.Background(), task, 0, string(out), val)
56+
sch.pgengine.LogTaskExecution(context.Background(), task, exitCode, string(out), val)
5857
}
59-
return nil
58+
return err
6059
}

internal/scheduler/shell_test.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package scheduler_test
33
import (
44
"context"
55
"encoding/json"
6+
"errors"
67
"fmt"
78
"os/exec"
89
"strings"
@@ -32,37 +33,37 @@ func TestShellCommand(t *testing.T) {
3233

3334
mock, err := pgxmock.NewPool() //
3435
assert.NoError(t, err)
35-
pge := pgengine.NewDB(mock, "scheduler_unit_test")
36-
scheduler := scheduler.New(pge, log.Init(config.LoggingOpts{LogLevel: "panic", LogDBLevel: "none"}))
36+
pge := pgengine.NewDB(mock, "--log-database-level=none")
37+
sch := scheduler.New(pge, log.Init(config.LoggingOpts{LogLevel: "panic", LogDBLevel: "none"}))
3738
ctx := context.Background()
3839

39-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{}, []string{""})
40+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{}, []string{""})
4041
assert.EqualError(t, err, "program command cannot be empty", "Empty command should out, fail")
4142

42-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping0"}, nil)
43+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping0"}, nil)
4344
assert.NoError(t, err, "Command with nil param is out, OK")
4445

45-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping1"}, []string{})
46+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping1"}, []string{})
4647
assert.NoError(t, err, "Command with empty array param is OK")
4748

48-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping2"}, []string{""})
49+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping2"}, []string{""})
4950
assert.NoError(t, err, "Command with empty string param is OK")
5051

51-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping3"}, []string{"[]"})
52+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping3"}, []string{"[]"})
5253
assert.NoError(t, err, "Command with empty json array param is OK")
5354

54-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping3"}, []string{"[null]"})
55+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping3"}, []string{"[null]"})
5556
assert.NoError(t, err, "Command with nil array param is OK")
5657

57-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping4"}, []string{`["localhost"]`})
58+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping4"}, []string{`["localhost"]`})
5859
assert.NoError(t, err, "Command with one param is OK")
5960

60-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping5"}, []string{`["localhost", "-4"]`})
61+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping5"}, []string{`["localhost", "-4"]`})
6162
assert.NoError(t, err, "Command with many params is OK")
6263

63-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "pong"}, nil)
64-
assert.IsType(t, (*exec.Error)(nil), err, "Uknown command should produce error")
64+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "pong"}, nil)
65+
assert.True(t, errors.Is(err, exec.ErrNotFound), "Unknown command should produce exec.Error")
6566

66-
err = scheduler.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping5"}, []string{`{"param1": "localhost"}`})
67-
assert.IsType(t, (*json.UnmarshalTypeError)(nil), err, "Command should fail with mailformed json parameter")
67+
err = sch.ExecuteProgramCommand(ctx, &pgengine.ChainTask{Command: "ping5"}, []string{`{"param1": "localhost"}`})
68+
assert.IsType(t, (*json.UnmarshalTypeError)(nil), err, "Command should fail with malformed json parameter")
6869
}

internal/scheduler/tasks_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import (
1414
func TestExecuteTask(t *testing.T) {
1515
mock, err := pgxmock.NewPool() //
1616
assert.NoError(t, err)
17-
pge := pgengine.NewDB(mock, "scheduler_unit_test")
17+
pge := pgengine.NewDB(mock, "--log-database-level=none")
1818
mocksch := New(pge, log.Init(config.LoggingOpts{LogLevel: "panic", LogDBLevel: "none"}))
1919

2020
et := func(task string, params []string) (err error) {

0 commit comments

Comments
 (0)