Skip to content

Commit

Permalink
Merge pull request #65 from telekom-mms/feature/capture-execs-command…
Browse files Browse the repository at this point in the history
…-output

Capture stdout and stderr output of execs commands
  • Loading branch information
hwipl authored Apr 10, 2024
2 parents 9f75b17 + 73e318c commit ea48a9a
Show file tree
Hide file tree
Showing 12 changed files with 329 additions and 260 deletions.
46 changes: 19 additions & 27 deletions internal/execs/execs.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,85 +15,77 @@ var (
resolvectl = Resolvectl
)

// RunCmd runs the cmd with args and sets stdin to s.
var RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
// RunCmd runs the cmd with args and sets stdin to s, returns stdout and stderr.
var RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) (stdout, stderr []byte, err error) {
c := exec.CommandContext(ctx, cmd, arg...)
if s != "" {
c.Stdin = bytes.NewBufferString(s)
}
return c.Run()
}

// RunCmdOutput runs the cmd with args and sets stdin to s, returns output.
var RunCmdOutput = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, error) {
c := exec.CommandContext(ctx, cmd, arg...)
if s != "" {
c.Stdin = bytes.NewBufferString(s)
}
return c.Output()
var outbuf, errbuf bytes.Buffer
c.Stdout = &outbuf
c.Stderr = &errbuf
err = c.Run()
stdout = outbuf.Bytes()
stderr = errbuf.Bytes()
return
}

// RunIP runs the "ip" command with args.
func RunIP(ctx context.Context, arg ...string) error {
func RunIP(ctx context.Context, arg ...string) (stdout, stderr []byte, err error) {
return RunCmd(ctx, ip, "", arg...)
}

// RunIPLink runs the "ip link" command with args.
func RunIPLink(ctx context.Context, arg ...string) error {
func RunIPLink(ctx context.Context, arg ...string) (stdout, stderr []byte, err error) {
a := append([]string{"link"}, arg...)
return RunIP(ctx, a...)
}

// RunIPAddress runs the "ip address" command with args.
func RunIPAddress(ctx context.Context, arg ...string) error {
func RunIPAddress(ctx context.Context, arg ...string) (stdout, stderr []byte, err error) {
a := append([]string{"address"}, arg...)
return RunIP(ctx, a...)
}

// RunIP4Route runs the "ip -4 route" command with args.
func RunIP4Route(ctx context.Context, arg ...string) error {
func RunIP4Route(ctx context.Context, arg ...string) (stdout, stderr []byte, err error) {
a := append([]string{"-4", "route"}, arg...)
return RunIP(ctx, a...)
}

// RunIP6Route runs the "ip -6 route" command with args.
func RunIP6Route(ctx context.Context, arg ...string) error {
func RunIP6Route(ctx context.Context, arg ...string) (stdout, stderr []byte, err error) {
a := append([]string{"-6", "route"}, arg...)
return RunIP(ctx, a...)
}

// RunIP4Rule runs the "ip -4 rule" command with args.
func RunIP4Rule(ctx context.Context, arg ...string) error {
func RunIP4Rule(ctx context.Context, arg ...string) (stdout, stderr []byte, err error) {
a := append([]string{"-4", "rule"}, arg...)
return RunIP(ctx, a...)
}

// RunIP6Rule runs the "ip -6 rule" command with args.
func RunIP6Rule(ctx context.Context, arg ...string) error {
func RunIP6Rule(ctx context.Context, arg ...string) (stdout, stderr []byte, err error) {
a := append([]string{"-6", "rule"}, arg...)
return RunIP(ctx, a...)
}

// RunSysctl runs the "sysctl" command with args.
func RunSysctl(ctx context.Context, arg ...string) error {
func RunSysctl(ctx context.Context, arg ...string) (stdout, stderr []byte, err error) {
return RunCmd(ctx, sysctl, "", arg...)
}

// RunNft runs the "nft -f -" command and sets stdin to s.
func RunNft(ctx context.Context, s string) error {
func RunNft(ctx context.Context, s string) (stdout, stderr []byte, err error) {
return RunCmd(ctx, nft, s, "-f", "-")
}

// RunResolvectl runs the "resolvectl" command with args.
func RunResolvectl(ctx context.Context, arg ...string) error {
func RunResolvectl(ctx context.Context, arg ...string) (stdout, stderr []byte, err error) {
return RunCmd(ctx, resolvectl, "", arg...)
}

// RunResolvectlOutput runs the "resolvectl" command with args, returns output.
func RunResolvectlOutput(ctx context.Context, arg ...string) ([]byte, error) {
return RunCmdOutput(ctx, resolvectl, "", arg...)
}

// SetExecutables configures all executables from config.
func SetExecutables(config *Config) {
ip = config.IP
Expand Down
111 changes: 42 additions & 69 deletions internal/execs/execs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,39 +14,30 @@ func TestRunCmd(t *testing.T) {

// test not existing
dir := t.TempDir()
if err := RunCmd(ctx, filepath.Join(dir, "does/not/exist"), ""); err == nil {
if _, _, err := RunCmd(ctx, filepath.Join(dir, "does/not/exist"), ""); err == nil {
t.Errorf("running not existing command should fail: %v", err)
}

// test existing
if err := RunCmd(ctx, "echo", "", "this", "is", "a", "test"); err != nil {
if _, _, err := RunCmd(ctx, "echo", "", "this", "is", "a", "test"); err != nil {
t.Errorf("running echo failed: %v", err)
}

// test with stdin
if err := RunCmd(ctx, "echo", "this is a test"); err != nil {
if _, _, err := RunCmd(ctx, "echo", "this is a test"); err != nil {
t.Errorf("running echo failed: %v", err)
}
}

// TestRunCmdOutput tests RunCmdOutput.
func TestRunCmdOutput(t *testing.T) {
ctx := context.Background()
dir := t.TempDir()

// test with error
if _, err := RunCmdOutput(ctx, filepath.Join(dir, "does/not/exist"), ""); err == nil {
t.Errorf("running should fail: %v", err)
// test stdout
stdout, stderr, err := RunCmd(ctx, "cat", "this is a test")
if err != nil || string(stdout) != "this is a test" {
t.Errorf("running echo failed: %s, %s, %v", stdout, stderr, err)
}

// test without error
if b, err := RunCmdOutput(ctx, "ls", "", "-d", dir); err != nil || len(b) == 0 {
t.Errorf("running should not fail: %v, %v", b, err)
}

// test with stdin
if b, err := RunCmdOutput(ctx, "echo", "this is a test"); err != nil || len(b) == 0 {
t.Errorf("running should not fail: %v, %v", b, err)
// test stderr and error
stdout, stderr, err = RunCmd(ctx, "cat", "", "does/not/exist")
if err == nil || string(stderr) != "cat: does/not/exist: No such file or directory\n" {
t.Errorf("running echo failed: %s, %s, %v", stdout, stderr, err)
}
}

Expand All @@ -56,13 +47,13 @@ func TestRunIP(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return nil
return nil, nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunIP(context.Background(), "address", "show")
_, _, _ = RunIP(context.Background(), "address", "show")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
Expand All @@ -74,13 +65,13 @@ func TestRunIPLink(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return nil
return nil, nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunIPLink(context.Background(), "show")
_, _, _ = RunIPLink(context.Background(), "show")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
Expand All @@ -92,13 +83,13 @@ func TestRunIPAddress(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return nil
return nil, nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunIPAddress(context.Background(), "show")
_, _, _ = RunIPAddress(context.Background(), "show")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
Expand All @@ -110,13 +101,13 @@ func TestRunIP4Route(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return nil
return nil, nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunIP4Route(context.Background(), "show")
_, _, _ = RunIP4Route(context.Background(), "show")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
Expand All @@ -128,13 +119,13 @@ func TestRunIP6Route(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return nil
return nil, nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunIP6Route(context.Background(), "show")
_, _, _ = RunIP6Route(context.Background(), "show")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
Expand All @@ -146,13 +137,13 @@ func TestRunIP4Rule(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return nil
return nil, nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunIP4Rule(context.Background(), "show")
_, _, _ = RunIP4Rule(context.Background(), "show")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
Expand All @@ -164,13 +155,13 @@ func TestRunIP6Rule(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return nil
return nil, nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunIP6Rule(context.Background(), "show")
_, _, _ = RunIP6Rule(context.Background(), "show")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
Expand All @@ -182,13 +173,13 @@ func TestRunSysctl(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return nil
return nil, nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunSysctl(context.Background(), "-q", "net.ipv4.conf.all.src_valid_mark=1")
_, _, _ = RunSysctl(context.Background(), "-q", "net.ipv4.conf.all.src_valid_mark=1")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
Expand All @@ -200,13 +191,13 @@ func TestRunNft(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " ")+" "+s)
return nil
return nil, nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunNft(context.Background(), "list tables")
_, _, _ = RunNft(context.Background(), "list tables")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
Expand All @@ -218,32 +209,14 @@ func TestRunResolvectl(t *testing.T) {
got := []string{}

oldRunCmd := RunCmd
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) error {
RunCmd = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, []byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return nil
return []byte("OK"), nil, nil
}
defer func() { RunCmd = oldRunCmd }()

_ = RunResolvectl(context.Background(), "dns")
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
}
}

// TestRunResolvectlOutput tests RunResolvectlOutput.
func TestRunResolvectlOutput(t *testing.T) {
want := []string{"resolvectl dns"}
got := []string{}

oldRunCmdOutput := RunCmdOutput
RunCmdOutput = func(ctx context.Context, cmd string, s string, arg ...string) ([]byte, error) {
got = append(got, cmd+" "+strings.Join(arg, " "))
return []byte("OK"), nil
}
defer func() { RunCmdOutput = oldRunCmdOutput }()

if b, err := RunResolvectlOutput(context.Background(), "dns"); err != nil || string(b) != "OK" {
t.Errorf("invalid return values %v, %v", b, err)
if b, _, err := RunResolvectl(context.Background(), "dns"); err != nil || string(b) != "OK" {
t.Errorf("invalid return values %s, %v", b, err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, want %v", got, want)
Expand Down
Loading

0 comments on commit ea48a9a

Please sign in to comment.