github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/pkg/integration/dockerCmd_utils_test.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "testing" 8 9 "io/ioutil" 10 "strings" 11 "time" 12 13 "github.com/go-check/check" 14 ) 15 16 const dockerBinary = "docker" 17 18 // Setup go-check for this test 19 func Test(t *testing.T) { 20 check.TestingT(t) 21 } 22 23 func init() { 24 check.Suite(&DockerCmdSuite{}) 25 } 26 27 type DockerCmdSuite struct{} 28 29 // Fake the exec.Command to use our mock. 30 func (s *DockerCmdSuite) SetUpTest(c *check.C) { 31 execCommand = fakeExecCommand 32 } 33 34 // And bring it back to normal after the test. 35 func (s *DockerCmdSuite) TearDownTest(c *check.C) { 36 execCommand = exec.Command 37 } 38 39 // DockerCmdWithError tests 40 41 func (s *DockerCmdSuite) TestDockerCmdWithError(c *check.C) { 42 cmds := []struct { 43 binary string 44 args []string 45 expectedOut string 46 expectedExitCode int 47 expectedError error 48 }{ 49 { 50 "doesnotexists", 51 []string{}, 52 "Command doesnotexists not found.", 53 1, 54 fmt.Errorf("exit status 1"), 55 }, 56 { 57 dockerBinary, 58 []string{"an", "error"}, 59 "an error has occurred", 60 1, 61 fmt.Errorf("exit status 1"), 62 }, 63 { 64 dockerBinary, 65 []string{"an", "exitCode", "127"}, 66 "an error has occurred with exitCode 127", 67 127, 68 fmt.Errorf("exit status 127"), 69 }, 70 { 71 dockerBinary, 72 []string{"run", "-ti", "ubuntu", "echo", "hello"}, 73 "hello", 74 0, 75 nil, 76 }, 77 } 78 for _, cmd := range cmds { 79 out, exitCode, error := DockerCmdWithError(cmd.binary, cmd.args...) 80 c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out)) 81 c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode)) 82 if cmd.expectedError != nil { 83 c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError)) 84 c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error())) 85 } else { 86 c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error)) 87 } 88 } 89 } 90 91 // DockerCmdWithStdoutStderr tests 92 93 type dockerCmdWithStdoutStderrErrorSuite struct{} 94 95 func (s *dockerCmdWithStdoutStderrErrorSuite) Test(c *check.C) { 96 // Should fail, the test too 97 DockerCmdWithStdoutStderr(dockerBinary, c, "an", "error") 98 } 99 100 type dockerCmdWithStdoutStderrSuccessSuite struct{} 101 102 func (s *dockerCmdWithStdoutStderrSuccessSuite) Test(c *check.C) { 103 stdout, stderr, exitCode := DockerCmdWithStdoutStderr(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello") 104 c.Assert(stdout, check.Equals, "hello") 105 c.Assert(stderr, check.Equals, "") 106 c.Assert(exitCode, check.Equals, 0) 107 108 } 109 110 func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrError(c *check.C) { 111 // Run error suite, should fail. 112 output := String{} 113 result := check.Run(&dockerCmdWithStdoutStderrErrorSuite{}, &check.RunConf{Output: &output}) 114 c.Check(result.Succeeded, check.Equals, 0) 115 c.Check(result.Failed, check.Equals, 1) 116 } 117 118 func (s *DockerCmdSuite) TestDockerCmdWithStdoutStderrSuccess(c *check.C) { 119 // Run error suite, should fail. 120 output := String{} 121 result := check.Run(&dockerCmdWithStdoutStderrSuccessSuite{}, &check.RunConf{Output: &output}) 122 c.Check(result.Succeeded, check.Equals, 1) 123 c.Check(result.Failed, check.Equals, 0) 124 } 125 126 // DockerCmd tests 127 128 type dockerCmdErrorSuite struct{} 129 130 func (s *dockerCmdErrorSuite) Test(c *check.C) { 131 // Should fail, the test too 132 DockerCmd(dockerBinary, c, "an", "error") 133 } 134 135 type dockerCmdSuccessSuite struct{} 136 137 func (s *dockerCmdSuccessSuite) Test(c *check.C) { 138 stdout, exitCode := DockerCmd(dockerBinary, c, "run", "-ti", "ubuntu", "echo", "hello") 139 c.Assert(stdout, check.Equals, "hello") 140 c.Assert(exitCode, check.Equals, 0) 141 142 } 143 144 func (s *DockerCmdSuite) TestDockerCmdError(c *check.C) { 145 // Run error suite, should fail. 146 output := String{} 147 result := check.Run(&dockerCmdErrorSuite{}, &check.RunConf{Output: &output}) 148 c.Check(result.Succeeded, check.Equals, 0) 149 c.Check(result.Failed, check.Equals, 1) 150 } 151 152 func (s *DockerCmdSuite) TestDockerCmdSuccess(c *check.C) { 153 // Run error suite, should fail. 154 output := String{} 155 result := check.Run(&dockerCmdSuccessSuite{}, &check.RunConf{Output: &output}) 156 c.Check(result.Succeeded, check.Equals, 1) 157 c.Check(result.Failed, check.Equals, 0) 158 } 159 160 // DockerCmdWithTimeout tests 161 162 func (s *DockerCmdSuite) TestDockerCmdWithTimeout(c *check.C) { 163 cmds := []struct { 164 binary string 165 args []string 166 timeout time.Duration 167 expectedOut string 168 expectedExitCode int 169 expectedError error 170 }{ 171 { 172 "doesnotexists", 173 []string{}, 174 200 * time.Millisecond, 175 `Command doesnotexists not found.`, 176 1, 177 fmt.Errorf(`"" failed with errors: exit status 1 : "Command doesnotexists not found."`), 178 }, 179 { 180 dockerBinary, 181 []string{"an", "error"}, 182 200 * time.Millisecond, 183 `an error has occurred`, 184 1, 185 fmt.Errorf(`"an error" failed with errors: exit status 1 : "an error has occurred"`), 186 }, 187 { 188 dockerBinary, 189 []string{"a", "command", "that", "times", "out"}, 190 5 * time.Millisecond, 191 "", 192 0, 193 fmt.Errorf(`"a command that times out" failed with errors: command timed out : ""`), 194 }, 195 { 196 dockerBinary, 197 []string{"run", "-ti", "ubuntu", "echo", "hello"}, 198 200 * time.Millisecond, 199 "hello", 200 0, 201 nil, 202 }, 203 } 204 for _, cmd := range cmds { 205 out, exitCode, error := DockerCmdWithTimeout(cmd.binary, cmd.timeout, cmd.args...) 206 c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out)) 207 c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode)) 208 if cmd.expectedError != nil { 209 c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError)) 210 c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error())) 211 } else { 212 c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error)) 213 } 214 } 215 } 216 217 // DockerCmdInDir tests 218 219 func (s *DockerCmdSuite) TestDockerCmdInDir(c *check.C) { 220 tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir") 221 c.Assert(err, check.IsNil) 222 223 cmds := []struct { 224 binary string 225 args []string 226 expectedOut string 227 expectedExitCode int 228 expectedError error 229 }{ 230 { 231 "doesnotexists", 232 []string{}, 233 `Command doesnotexists not found.`, 234 1, 235 fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder), 236 }, 237 { 238 dockerBinary, 239 []string{"an", "error"}, 240 `an error has occurred`, 241 1, 242 fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder), 243 }, 244 { 245 dockerBinary, 246 []string{"run", "-ti", "ubuntu", "echo", "hello"}, 247 "hello", 248 0, 249 nil, 250 }, 251 } 252 for _, cmd := range cmds { 253 // We prepend the arguments with dir:thefolder.. the fake command will check 254 // that the current workdir is the same as the one we are passing. 255 args := append([]string{"dir:" + tempFolder}, cmd.args...) 256 out, exitCode, error := DockerCmdInDir(cmd.binary, tempFolder, args...) 257 c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out)) 258 c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode)) 259 if cmd.expectedError != nil { 260 c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError)) 261 c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error())) 262 } else { 263 c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error)) 264 } 265 } 266 } 267 268 // DockerCmdInDirWithTimeout tests 269 270 func (s *DockerCmdSuite) TestDockerCmdInDirWithTimeout(c *check.C) { 271 tempFolder, err := ioutil.TempDir("", "test-docker-cmd-in-dir") 272 c.Assert(err, check.IsNil) 273 274 cmds := []struct { 275 binary string 276 args []string 277 timeout time.Duration 278 expectedOut string 279 expectedExitCode int 280 expectedError error 281 }{ 282 { 283 "doesnotexists", 284 []string{}, 285 200 * time.Millisecond, 286 `Command doesnotexists not found.`, 287 1, 288 fmt.Errorf(`"dir:%s" failed with errors: exit status 1 : "Command doesnotexists not found."`, tempFolder), 289 }, 290 { 291 dockerBinary, 292 []string{"an", "error"}, 293 200 * time.Millisecond, 294 `an error has occurred`, 295 1, 296 fmt.Errorf(`"dir:%s an error" failed with errors: exit status 1 : "an error has occurred"`, tempFolder), 297 }, 298 { 299 dockerBinary, 300 []string{"a", "command", "that", "times", "out"}, 301 5 * time.Millisecond, 302 "", 303 0, 304 fmt.Errorf(`"dir:%s a command that times out" failed with errors: command timed out : ""`, tempFolder), 305 }, 306 { 307 dockerBinary, 308 []string{"run", "-ti", "ubuntu", "echo", "hello"}, 309 200 * time.Millisecond, 310 "hello", 311 0, 312 nil, 313 }, 314 } 315 for _, cmd := range cmds { 316 // We prepend the arguments with dir:thefolder.. the fake command will check 317 // that the current workdir is the same as the one we are passing. 318 args := append([]string{"dir:" + tempFolder}, cmd.args...) 319 out, exitCode, error := DockerCmdInDirWithTimeout(cmd.binary, cmd.timeout, tempFolder, args...) 320 c.Assert(out, check.Equals, cmd.expectedOut, check.Commentf("Expected output %q for arguments %v, got %q", cmd.expectedOut, cmd.args, out)) 321 c.Assert(exitCode, check.Equals, cmd.expectedExitCode, check.Commentf("Expected exitCode %q for arguments %v, got %q", cmd.expectedExitCode, cmd.args, exitCode)) 322 if cmd.expectedError != nil { 323 c.Assert(error, check.NotNil, check.Commentf("Expected an error %q, got nothing", cmd.expectedError)) 324 c.Assert(error.Error(), check.Equals, cmd.expectedError.Error(), check.Commentf("Expected error %q for arguments %v, got %q", cmd.expectedError.Error(), cmd.args, error.Error())) 325 } else { 326 c.Assert(error, check.IsNil, check.Commentf("Expected no error, got %v", error)) 327 } 328 } 329 } 330 331 // Helpers :) 332 333 // Type implementing the io.Writer interface for analyzing output. 334 type String struct { 335 value string 336 } 337 338 // The only function required by the io.Writer interface. Will append 339 // written data to the String.value string. 340 func (s *String) Write(p []byte) (n int, err error) { 341 s.value += string(p) 342 return len(p), nil 343 } 344 345 // Helper function that mock the exec.Command call (and call the test binary) 346 func fakeExecCommand(command string, args ...string) *exec.Cmd { 347 cs := []string{"-test.run=TestHelperProcess", "--", command} 348 cs = append(cs, args...) 349 cmd := exec.Command(os.Args[0], cs...) 350 cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} 351 return cmd 352 } 353 354 func TestHelperProcess(t *testing.T) { 355 if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { 356 return 357 } 358 args := os.Args 359 360 // Previous arguments are tests stuff, that looks like : 361 // /tmp/go-build970079519/…/_test/integration.test -test.run=TestHelperProcess -- 362 cmd, args := args[3], args[4:] 363 // Handle the case where args[0] is dir:... 364 if len(args) > 0 && strings.HasPrefix(args[0], "dir:") { 365 expectedCwd := args[0][4:] 366 if len(args) > 1 { 367 args = args[1:] 368 } 369 cwd, err := os.Getwd() 370 if err != nil { 371 fmt.Fprintf(os.Stderr, "Failed to get workingdir: %v", err) 372 os.Exit(1) 373 } 374 // This checks that the given path is the same as the currend working dire 375 if expectedCwd != cwd { 376 fmt.Fprintf(os.Stderr, "Current workdir should be %q, but is %q", expectedCwd, cwd) 377 } 378 } 379 switch cmd { 380 case dockerBinary: 381 argsStr := strings.Join(args, " ") 382 switch argsStr { 383 case "an exitCode 127": 384 fmt.Fprintf(os.Stderr, "an error has occurred with exitCode 127") 385 os.Exit(127) 386 case "an error": 387 fmt.Fprintf(os.Stderr, "an error has occurred") 388 os.Exit(1) 389 case "a command that times out": 390 time.Sleep(10 * time.Second) 391 fmt.Fprintf(os.Stdout, "too long, should be killed") 392 // A random exit code (that should never happened in tests) 393 os.Exit(7) 394 case "run -ti ubuntu echo hello": 395 fmt.Fprintf(os.Stdout, "hello") 396 default: 397 fmt.Fprintf(os.Stdout, "no arguments") 398 } 399 default: 400 fmt.Fprintf(os.Stderr, "Command %s not found.", cmd) 401 os.Exit(1) 402 } 403 // some code here to check arguments perhaps? 404 os.Exit(0) 405 }