| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2017 The LUCI Authors. All rights reserved. |
| 2 // Use of this source code is governed under the Apache License, Version 2.0 |
| 3 // that can be found in the LICENSE file. |
| 4 |
| 5 package python |
| 6 |
| 7 import ( |
| 8 "fmt" |
| 9 "os" |
| 10 "os/exec" |
| 11 "testing" |
| 12 |
| 13 "golang.org/x/net/context" |
| 14 |
| 15 . "github.com/luci/luci-go/common/testing/assertions" |
| 16 . "github.com/smartystreets/goconvey/convey" |
| 17 ) |
| 18 |
| 19 func TestParsePythonCommandLine(t *testing.T) { |
| 20 t.Parallel() |
| 21 |
| 22 successes := []struct { |
| 23 args []string |
| 24 cmd CommandLine |
| 25 }{ |
| 26 {nil, CommandLine{}}, |
| 27 |
| 28 {[]string{"-a", "-b", "-Q'foo.bar.baz'", "-Wbar"}, |
| 29 CommandLine{ |
| 30 Flags: []string{"-a", "-b", "-Q'foo.bar.baz'", "
-Wbar"}, |
| 31 Args: []string{}, |
| 32 }, |
| 33 }, |
| 34 |
| 35 {[]string{"path.py", "--", "foo", "bar"}, |
| 36 CommandLine{ |
| 37 Type: TargetScript, |
| 38 Value: "path.py", |
| 39 Flags: []string{}, |
| 40 Args: []string{"--", "foo", "bar"}, |
| 41 }, |
| 42 }, |
| 43 |
| 44 {[]string{"-a", "-Wfoo", "-", "--", "foo"}, |
| 45 CommandLine{ |
| 46 Type: TargetScript, |
| 47 Value: "-", |
| 48 Flags: []string{"-a", "-Wfoo"}, |
| 49 Args: []string{"--", "foo"}, |
| 50 }, |
| 51 }, |
| 52 |
| 53 {[]string{"-a", "-b", "-W", "foo", "-Wbar", "-c", "<script>", "-
-", "arg"}, |
| 54 CommandLine{ |
| 55 Type: TargetCommand, |
| 56 Value: "<script>", |
| 57 Flags: []string{"-a", "-b", "-W", "foo", "-Wbar"
}, |
| 58 Args: []string{"--", "arg"}, |
| 59 }, |
| 60 }, |
| 61 |
| 62 {[]string{"-a", "-b", "-m'foo.bar.baz'", "arg"}, |
| 63 CommandLine{ |
| 64 Type: TargetModule, |
| 65 Value: "'foo.bar.baz'", |
| 66 Flags: []string{"-a", "-b"}, |
| 67 Args: []string{"arg"}, |
| 68 }, |
| 69 }, |
| 70 } |
| 71 |
| 72 failures := []struct { |
| 73 args []string |
| 74 err string |
| 75 }{ |
| 76 {[]string{"-a", "-b", "-Q"}, "truncated two-variable argument"}, |
| 77 {[]string{"-c"}, "missing second value"}, |
| 78 {[]string{"-\x80"}, "invalid rune in flag"}, |
| 79 } |
| 80 |
| 81 Convey(`Testing Python command-line parsing`, t, func() { |
| 82 for _, tc := range successes { |
| 83 Convey(fmt.Sprintf(`Success cases: %v`, tc.args), func()
{ |
| 84 cmd, err := ParseCommandLine(tc.args) |
| 85 So(err, ShouldBeNil) |
| 86 So(cmd, ShouldResemble, tc.cmd) |
| 87 }) |
| 88 } |
| 89 |
| 90 for _, tc := range failures { |
| 91 Convey(fmt.Sprintf(`Error cases: %v`, tc.args), func() { |
| 92 _, err := ParseCommandLine(tc.args) |
| 93 So(err, ShouldErrLike, tc.err) |
| 94 }) |
| 95 } |
| 96 }) |
| 97 } |
| 98 |
| 99 func TestInterpreter(t *testing.T) { |
| 100 t.Parallel() |
| 101 |
| 102 versionSuccesses := []struct { |
| 103 output string |
| 104 vers Version |
| 105 }{ |
| 106 {"Python 2.7.1\n", Version{2, 7, 1}}, |
| 107 {"Python 3", Version{3, 0, 0}}, |
| 108 } |
| 109 |
| 110 versionFailures := []struct { |
| 111 output string |
| 112 err string |
| 113 }{ |
| 114 {"", "unknown version output"}, |
| 115 {"Python2.7.11\n", "unknown version output"}, |
| 116 {"Python", "unknown version output"}, |
| 117 {"Python 2.7.11 foo bar junk", "invalid number value"}, |
| 118 {"Python 3.1.2.3.4", "failed to parse version"}, |
| 119 } |
| 120 |
| 121 Convey(`A Python interpreter`, t, func() { |
| 122 c := context.Background() |
| 123 |
| 124 var ( |
| 125 runnerOutput string |
| 126 runnerErr error |
| 127 lastCmd *exec.Cmd |
| 128 ) |
| 129 i := Interpreter{ |
| 130 runner: func(cmd *exec.Cmd, capture bool) (string, error
) { |
| 131 // Sanitize exec.Cmd to exclude its private memb
ers for comparison. |
| 132 lastCmd = &exec.Cmd{ |
| 133 Path: cmd.Path, |
| 134 Args: cmd.Args, |
| 135 Stdin: cmd.Stdin, |
| 136 Stdout: cmd.Stdout, |
| 137 Stderr: cmd.Stderr, |
| 138 Env: cmd.Env, |
| 139 Dir: cmd.Dir, |
| 140 } |
| 141 return runnerOutput, runnerErr |
| 142 }, |
| 143 } |
| 144 |
| 145 Convey(`Will error if no Python interpreter is supplied.`, func(
) { |
| 146 So(i.Run(c, "foo", "bar"), ShouldErrLike, "a Python inte
rpreter must be supplied") |
| 147 }) |
| 148 |
| 149 Convey(`With a Python interpreter installed`, func() { |
| 150 i.Python = "/path/to/python" |
| 151 |
| 152 Convey(`Testing Run`, func() { |
| 153 Convey(`Can run a command.`, func() { |
| 154 So(i.Run(c, "foo", "bar"), ShouldBeNil) |
| 155 So(lastCmd, ShouldResemble, &exec.Cmd{ |
| 156 Path: "/path/to/python", |
| 157 Args: []string{"/path/to/pytho
n", "foo", "bar"}, |
| 158 Stdout: os.Stdout, |
| 159 Stderr: os.Stderr, |
| 160 }) |
| 161 }) |
| 162 |
| 163 Convey(`Can run an isolated environment command.
`, func() { |
| 164 i.Isolated = true |
| 165 |
| 166 So(i.Run(c, "foo", "bar"), ShouldBeNil) |
| 167 So(lastCmd, ShouldResemble, &exec.Cmd{ |
| 168 Path: "/path/to/python", |
| 169 Args: []string{"/path/to/pytho
n", "-B", "-E", "-s", "foo", "bar"}, |
| 170 Stdout: os.Stdout, |
| 171 Stderr: os.Stderr, |
| 172 }) |
| 173 }) |
| 174 |
| 175 Convey(`Can connect STDIN.`, func() { |
| 176 i.ConnectSTDIN = true |
| 177 |
| 178 So(i.Run(c, "foo", "bar"), ShouldBeNil) |
| 179 So(lastCmd, ShouldResemble, &exec.Cmd{ |
| 180 Path: "/path/to/python", |
| 181 Args: []string{"/path/to/pytho
n", "foo", "bar"}, |
| 182 Stdout: os.Stdout, |
| 183 Stderr: os.Stderr, |
| 184 Stdin: os.Stdin, |
| 185 }) |
| 186 }) |
| 187 |
| 188 Convey(`Will forward a working directory and env
iornment`, func() { |
| 189 i.WorkDir = "zugzug" |
| 190 i.Env = []string{"pants=on"} |
| 191 |
| 192 So(i.Run(c, "foo", "bar"), ShouldBeNil) |
| 193 So(lastCmd, ShouldResemble, &exec.Cmd{ |
| 194 Path: "/path/to/python", |
| 195 Args: []string{"/path/to/pytho
n", "foo", "bar"}, |
| 196 Stdout: os.Stdout, |
| 197 Stderr: os.Stderr, |
| 198 Env: []string{"pants=on"}, |
| 199 Dir: "zugzug", |
| 200 }) |
| 201 }) |
| 202 }) |
| 203 |
| 204 Convey(`Testing GetVersion`, func() { |
| 205 for _, tc := range versionSuccesses { |
| 206 Convey(fmt.Sprintf(`Can successfully par
se %q => %s`, tc.output, tc.vers), func() { |
| 207 runnerOutput = tc.output |
| 208 vers, err := i.GetVersion(c) |
| 209 So(err, ShouldBeNil) |
| 210 So(vers, ShouldResemble, tc.vers
) |
| 211 }) |
| 212 } |
| 213 |
| 214 for _, tc := range versionFailures { |
| 215 Convey(fmt.Sprintf(`Will fail to parse %
q (%s)`, tc.output, tc.err), func() { |
| 216 runnerOutput = tc.output |
| 217 _, err := i.GetVersion(c) |
| 218 So(err, ShouldErrLike, tc.err) |
| 219 }) |
| 220 } |
| 221 }) |
| 222 }) |
| 223 }) |
| 224 } |
| OLD | NEW |