Skip to content

Instantly share code, notes, and snippets.

@hichihara
Created May 31, 2018 06:10
Show Gist options
  • Save hichihara/46f6b278f3b6a1a9901666f27bcaa61b to your computer and use it in GitHub Desktop.
Save hichihara/46f6b278f3b6a1a9901666f27bcaa61b to your computer and use it in GitHub Desktop.
Golang exec command unit test
package main
import (
"fmt"
"os/exec"
"strconv"
"strings"
)
var execCommand = exec.Command
func ls() (string, error) {
cmd := execCommand("ls")
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf(string(out))
return string(out), err
}
return string(out), nil
}
func ssh(p int, in string) (string, error) {
cmd := execCommand("ssh", "root@localhost", "-p", strconv.Itoa(p))
cmd.Stdin = strings.NewReader(in)
out, err := cmd.CombinedOutput()
if err != nil {
fmt.Printf(string(out))
return string(out), err
}
return string(out), nil
}
func main() {
r, _ := ls()
fmt.Print(r)
p := 32768
in := "touch hoge\ntouch piyo\n"
ssh(p, in)
}
package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"strings"
"testing"
)
const stub = "test_file\ntest_file2\n"
var testCase string
func fakeExecCommand(command string, args ...string) *exec.Cmd {
cs := []string{"-test.run=TestHelperProcess", "--", command}
cs = append(cs, args...)
cmd := exec.Command(os.Args[0], cs...)
tc := "TEST_CASE=" + testCase
cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1", tc}
return cmd
}
func TestHelperProcess(t *testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
defer os.Exit(0)
args := os.Args
for len(args) > 0 {
if args[0] == "--" {
args = args[1:]
break
}
args = args[1:]
}
if len(args) == 0 {
fmt.Fprintf(os.Stderr, "No command\n")
os.Exit(2)
}
switch os.Getenv("TEST_CASE") {
case "case1":
fmt.Fprint(os.Stdout, stub)
case "case2":
e := "ssh root@localhost -p 22"
if s := strings.Join(args, " "); s != e {
fmt.Fprintf(os.Stderr, "Error: want %q, got %q", e, s)
os.Exit(1)
}
b, err := ioutil.ReadAll(os.Stdin)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
e = "touch aaa\ntouch bbb\n"
if s := string(b); s != e {
fmt.Fprintf(os.Stderr, "Error: Read %q, want %q", s, e)
os.Exit(1)
}
}
}
func TestLs(t *testing.T) {
testCase = "case1"
execCommand = fakeExecCommand
defer func() { execCommand = exec.Command }()
out, err := ls()
if err != nil {
t.Fatal(out)
}
if out != stub {
t.Fatalf("Error: want %q, got %q", stub, out)
}
}
func TestSsh(t *testing.T) {
testCase = "case2"
execCommand = fakeExecCommand
defer func() { execCommand = exec.Command }()
out, err := ssh(22, "touch aaa\ntouch bbb\n")
if err != nil {
t.Fatal(out)
}
}
@BogdanIrimie
Copy link

BogdanIrimie commented Nov 5, 2021

Since the tests run in parallel (https://stackoverflow.com/questions/24375966/does-go-test-run-unit-tests-concurrently , https://github.com/golang/go/blob/182bdbb1e1d62fe53f8386e7b02c7738898d373b/src/testing/testing.go#L555), isn't there concurrent access to var testCase string leading to unexpected behaviors?

@hichihara
Copy link
Author

You're right. This test code cannot consider parallel run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment