github.com/brahmaroutu/docker@v1.2.1-0.20160809185609-eb28dde01f16/builder/dockerfile/dispatchers_test.go (about) 1 package dockerfile 2 3 import ( 4 "fmt" 5 "runtime" 6 "strings" 7 "testing" 8 9 "github.com/docker/engine-api/types" 10 "github.com/docker/engine-api/types/container" 11 "github.com/docker/engine-api/types/strslice" 12 "github.com/docker/go-connections/nat" 13 ) 14 15 type commandWithFunction struct { 16 name string 17 function func(args []string) error 18 } 19 20 func TestCommandsExactlyOneArgument(t *testing.T) { 21 commands := []commandWithFunction{ 22 {"MAINTAINER", func(args []string) error { return maintainer(nil, args, nil, "") }}, 23 {"FROM", func(args []string) error { return from(nil, args, nil, "") }}, 24 {"WORKDIR", func(args []string) error { return workdir(nil, args, nil, "") }}, 25 {"USER", func(args []string) error { return user(nil, args, nil, "") }}} 26 27 for _, command := range commands { 28 err := command.function([]string{}) 29 30 if err == nil { 31 t.Fatalf("Error should be present for %s command", command.name) 32 } 33 34 expectedError := fmt.Sprintf("%s requires exactly one argument", command.name) 35 36 if err.Error() != expectedError { 37 t.Fatalf("Wrong error message for %s. Got: %s. Should be: %s", command.name, err.Error(), expectedError) 38 } 39 } 40 } 41 42 func TestCommandsAtLeastOneArgument(t *testing.T) { 43 commands := []commandWithFunction{ 44 {"ENV", func(args []string) error { return env(nil, args, nil, "") }}, 45 {"LABEL", func(args []string) error { return label(nil, args, nil, "") }}, 46 {"ONBUILD", func(args []string) error { return onbuild(nil, args, nil, "") }}, 47 {"EXPOSE", func(args []string) error { return expose(nil, args, nil, "") }}, 48 {"VOLUME", func(args []string) error { return volume(nil, args, nil, "") }}} 49 50 for _, command := range commands { 51 err := command.function([]string{}) 52 53 if err == nil { 54 t.Fatalf("Error should be present for %s command", command.name) 55 } 56 57 expectedError := fmt.Sprintf("%s requires at least one argument", command.name) 58 59 if err.Error() != expectedError { 60 t.Fatalf("Wrong error message for %s. Got: %s. Should be: %s", command.name, err.Error(), expectedError) 61 } 62 } 63 } 64 65 func TestCommandsAtLeastTwoArguments(t *testing.T) { 66 commands := []commandWithFunction{ 67 {"ADD", func(args []string) error { return add(nil, args, nil, "") }}, 68 {"COPY", func(args []string) error { return dispatchCopy(nil, args, nil, "") }}} 69 70 for _, command := range commands { 71 err := command.function([]string{"arg1"}) 72 73 if err == nil { 74 t.Fatalf("Error should be present for %s command", command.name) 75 } 76 77 expectedError := fmt.Sprintf("%s requires at least two arguments", command.name) 78 79 if err.Error() != expectedError { 80 t.Fatalf("Wrong error message for %s. Got: %s. Should be: %s", command.name, err.Error(), expectedError) 81 } 82 } 83 } 84 85 func TestCommandsTooManyArguments(t *testing.T) { 86 commands := []commandWithFunction{ 87 {"ENV", func(args []string) error { return env(nil, args, nil, "") }}, 88 {"LABEL", func(args []string) error { return label(nil, args, nil, "") }}} 89 90 for _, command := range commands { 91 err := command.function([]string{"arg1", "arg2", "arg3"}) 92 93 if err == nil { 94 t.Fatalf("Error should be present for %s command", command.name) 95 } 96 97 expectedError := fmt.Sprintf("Bad input to %s, too many arguments", command.name) 98 99 if err.Error() != expectedError { 100 t.Fatalf("Wrong error message for %s. Got: %s. Should be: %s", command.name, err.Error(), expectedError) 101 } 102 } 103 } 104 105 func TestEnv2Variables(t *testing.T) { 106 variables := []string{"var1", "val1", "var2", "val2"} 107 108 bflags := &BFlags{} 109 config := &container.Config{} 110 111 b := &Builder{flags: bflags, runConfig: config, disableCommit: true} 112 113 if err := env(b, variables, nil, ""); err != nil { 114 t.Fatalf("Error when executing env: %s", err.Error()) 115 } 116 117 expectedVar1 := fmt.Sprintf("%s=%s", variables[0], variables[1]) 118 expectedVar2 := fmt.Sprintf("%s=%s", variables[2], variables[3]) 119 120 if b.runConfig.Env[0] != expectedVar1 { 121 t.Fatalf("Wrong env output for first variable. Got: %s. Should be: %s", b.runConfig.Env[0], expectedVar1) 122 } 123 124 if b.runConfig.Env[1] != expectedVar2 { 125 t.Fatalf("Wrong env output for second variable. Got: %s, Should be: %s", b.runConfig.Env[1], expectedVar2) 126 } 127 } 128 129 func TestMaintainer(t *testing.T) { 130 maintainerEntry := "Some Maintainer <maintainer@example.com>" 131 132 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 133 134 if err := maintainer(b, []string{maintainerEntry}, nil, ""); err != nil { 135 t.Fatalf("Error when executing maintainer: %s", err.Error()) 136 } 137 138 if b.maintainer != maintainerEntry { 139 t.Fatalf("Maintainer in builder should be set to %s. Got: %s", maintainerEntry, b.maintainer) 140 } 141 } 142 143 func TestLabel(t *testing.T) { 144 labelName := "label" 145 labelValue := "value" 146 147 labelEntry := []string{labelName, labelValue} 148 149 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 150 151 if err := label(b, labelEntry, nil, ""); err != nil { 152 t.Fatalf("Error when executing label: %s", err.Error()) 153 } 154 155 if val, ok := b.runConfig.Labels[labelName]; ok { 156 if val != labelValue { 157 t.Fatalf("Label %s should have value %s, had %s instead", labelName, labelValue, val) 158 } 159 } else { 160 t.Fatalf("Label %s should be present but it is not", labelName) 161 } 162 } 163 164 func TestFrom(t *testing.T) { 165 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 166 167 err := from(b, []string{"scratch"}, nil, "") 168 169 if runtime.GOOS == "windows" { 170 if err == nil { 171 t.Fatalf("Error not set on Windows") 172 } 173 174 expectedError := "Windows does not support FROM scratch" 175 176 if !strings.Contains(err.Error(), expectedError) { 177 t.Fatalf("Error message not correct on Windows. Should be: %s, got: %s", expectedError, err.Error()) 178 } 179 } else { 180 if err != nil { 181 t.Fatalf("Error when executing from: %s", err.Error()) 182 } 183 184 if b.image != "" { 185 t.Fatalf("Image shoule be empty, got: %s", b.image) 186 } 187 188 if b.noBaseImage != true { 189 t.Fatalf("Image should not have any base image, got: %s", b.noBaseImage) 190 } 191 } 192 } 193 194 func TestOnbuildIllegalTriggers(t *testing.T) { 195 triggers := []struct{ command, expectedError string }{ 196 {"ONBUILD", "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed"}, 197 {"MAINTAINER", "MAINTAINER isn't allowed as an ONBUILD trigger"}, 198 {"FROM", "FROM isn't allowed as an ONBUILD trigger"}} 199 200 for _, trigger := range triggers { 201 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 202 203 err := onbuild(b, []string{trigger.command}, nil, "") 204 205 if err == nil { 206 t.Fatalf("Error should not be nil") 207 } 208 209 if !strings.Contains(err.Error(), trigger.expectedError) { 210 t.Fatalf("Error message not correct. Should be: %s, got: %s", trigger.expectedError, err.Error()) 211 } 212 } 213 } 214 215 func TestOnbuild(t *testing.T) { 216 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 217 218 err := onbuild(b, []string{"ADD", ".", "/app/src"}, nil, "ONBUILD ADD . /app/src") 219 220 if err != nil { 221 t.Fatalf("Error should be empty, got: %s", err.Error()) 222 } 223 224 expectedOnbuild := "ADD . /app/src" 225 226 if b.runConfig.OnBuild[0] != expectedOnbuild { 227 t.Fatalf("Wrong ONBUILD command. Expected: %s, got: %s", expectedOnbuild, b.runConfig.OnBuild[0]) 228 } 229 } 230 231 func TestWorkdir(t *testing.T) { 232 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 233 234 workingDir := "/app" 235 236 if runtime.GOOS == "windows" { 237 workingDir = "C:\app" 238 } 239 240 err := workdir(b, []string{workingDir}, nil, "") 241 242 if err != nil { 243 t.Fatalf("Error should be empty, got: %s", err.Error()) 244 } 245 246 if b.runConfig.WorkingDir != workingDir { 247 t.Fatalf("WorkingDir should be set to %s, got %s", workingDir, b.runConfig.WorkingDir) 248 } 249 250 } 251 252 func TestCmd(t *testing.T) { 253 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 254 255 command := "./executable" 256 257 err := cmd(b, []string{command}, nil, "") 258 259 if err != nil { 260 t.Fatalf("Error should be empty, got: %s", err.Error()) 261 } 262 263 var expectedCommand strslice.StrSlice 264 265 if runtime.GOOS == "windows" { 266 expectedCommand = strslice.StrSlice(append([]string{"cmd"}, "/S", "/C", command)) 267 } else { 268 expectedCommand = strslice.StrSlice(append([]string{"/bin/sh"}, "-c", command)) 269 } 270 271 if !compareStrSlice(b.runConfig.Cmd, expectedCommand) { 272 t.Fatalf("Command should be set to %s, got %s", command, b.runConfig.Cmd) 273 } 274 275 if !b.cmdSet { 276 t.Fatalf("Command should be marked as set") 277 } 278 } 279 280 func compareStrSlice(slice1, slice2 strslice.StrSlice) bool { 281 if len(slice1) != len(slice2) { 282 return false 283 } 284 285 for i := range slice1 { 286 if slice1[i] != slice2[i] { 287 return false 288 } 289 } 290 291 return true 292 } 293 294 func TestHealthcheckNone(t *testing.T) { 295 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 296 297 if err := healthcheck(b, []string{"NONE"}, nil, ""); err != nil { 298 t.Fatalf("Error should be empty, got: %s", err.Error()) 299 } 300 301 if b.runConfig.Healthcheck == nil { 302 t.Fatal("Healthcheck should be set, got nil") 303 } 304 305 expectedTest := strslice.StrSlice(append([]string{"NONE"})) 306 307 if !compareStrSlice(expectedTest, b.runConfig.Healthcheck.Test) { 308 t.Fatalf("Command should be set to %s, got %s", expectedTest, b.runConfig.Healthcheck.Test) 309 } 310 } 311 312 func TestHealthcheckCmd(t *testing.T) { 313 b := &Builder{flags: &BFlags{flags: make(map[string]*Flag)}, runConfig: &container.Config{}, disableCommit: true} 314 315 if err := healthcheck(b, []string{"CMD", "curl", "-f", "http://localhost/", "||", "exit", "1"}, nil, ""); err != nil { 316 t.Fatalf("Error should be empty, got: %s", err.Error()) 317 } 318 319 if b.runConfig.Healthcheck == nil { 320 t.Fatal("Healthcheck should be set, got nil") 321 } 322 323 expectedTest := strslice.StrSlice(append([]string{"CMD-SHELL"}, "curl -f http://localhost/ || exit 1")) 324 325 if !compareStrSlice(expectedTest, b.runConfig.Healthcheck.Test) { 326 t.Fatalf("Command should be set to %s, got %s", expectedTest, b.runConfig.Healthcheck.Test) 327 } 328 } 329 330 func TestEntrypoint(t *testing.T) { 331 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 332 333 entrypointCmd := "/usr/sbin/nginx" 334 335 if err := entrypoint(b, []string{entrypointCmd}, nil, ""); err != nil { 336 t.Fatalf("Error should be empty, got: %s", err.Error()) 337 } 338 339 if b.runConfig.Entrypoint == nil { 340 t.Fatalf("Entrypoint should be set") 341 } 342 343 var expectedEntrypoint strslice.StrSlice 344 345 if runtime.GOOS == "windows" { 346 expectedEntrypoint = strslice.StrSlice(append([]string{"cmd"}, "/S", "/C", entrypointCmd)) 347 } else { 348 expectedEntrypoint = strslice.StrSlice(append([]string{"/bin/sh"}, "-c", entrypointCmd)) 349 } 350 351 if !compareStrSlice(expectedEntrypoint, b.runConfig.Entrypoint) { 352 t.Fatalf("Entrypoint command should be set to %s, got %s", expectedEntrypoint, b.runConfig.Entrypoint) 353 } 354 } 355 356 func TestExpose(t *testing.T) { 357 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 358 359 exposedPort := "80" 360 361 if err := expose(b, []string{exposedPort}, nil, ""); err != nil { 362 t.Fatalf("Error should be empty, got: %s", err.Error()) 363 } 364 365 if b.runConfig.ExposedPorts == nil { 366 t.Fatalf("ExposedPorts should be set") 367 } 368 369 if len(b.runConfig.ExposedPorts) != 1 { 370 t.Fatalf("ExposedPorts should contain only 1 element. Got %s", b.runConfig.ExposedPorts) 371 } 372 373 portsMapping, err := nat.ParsePortSpec(exposedPort) 374 375 if err != nil { 376 t.Fatalf("Error when parsing port spec: %s", err.Error()) 377 } 378 379 if _, ok := b.runConfig.ExposedPorts[portsMapping[0].Port]; !ok { 380 t.Fatalf("Port %s should be present. Got %s", exposedPort, b.runConfig.ExposedPorts) 381 } 382 } 383 384 func TestUser(t *testing.T) { 385 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 386 387 userCommand := "foo" 388 389 if err := user(b, []string{userCommand}, nil, ""); err != nil { 390 t.Fatalf("Error should be empty, got: %s", err.Error()) 391 } 392 393 if b.runConfig.User != userCommand { 394 t.Fatalf("User should be set to %s, got %s", userCommand, b.runConfig.User) 395 } 396 } 397 398 func TestVolume(t *testing.T) { 399 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 400 401 exposedVolume := "/foo" 402 403 if err := volume(b, []string{exposedVolume}, nil, ""); err != nil { 404 t.Fatalf("Error should be empty, got: %s", err.Error()) 405 } 406 407 if b.runConfig.Volumes == nil { 408 t.Fatalf("Volumes should be set") 409 } 410 411 if len(b.runConfig.Volumes) != 1 { 412 t.Fatalf("Volumes should contain only 1 element. Got %s", b.runConfig.Volumes) 413 } 414 415 if _, ok := b.runConfig.Volumes[exposedVolume]; !ok { 416 t.Fatalf("Volume %s should be present. Got %s", exposedVolume, b.runConfig.Volumes) 417 } 418 } 419 420 func TestStopSignal(t *testing.T) { 421 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 422 423 signal := "SIGKILL" 424 425 if err := stopSignal(b, []string{signal}, nil, ""); err != nil { 426 t.Fatalf("Error should be empty, got: %s", err.Error()) 427 } 428 429 if b.runConfig.StopSignal != signal { 430 t.Fatalf("StopSignal should be set to %s, got %s", signal, b.runConfig.StopSignal) 431 } 432 } 433 434 func TestArg(t *testing.T) { 435 buildOptions := &types.ImageBuildOptions{BuildArgs: make(map[string]string)} 436 437 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true, allowedBuildArgs: make(map[string]bool), options: buildOptions} 438 439 argName := "foo" 440 argVal := "bar" 441 argDef := fmt.Sprintf("%s=%s", argName, argVal) 442 443 if err := arg(b, []string{argDef}, nil, ""); err != nil { 444 t.Fatalf("Error should be empty, got: %s", err.Error()) 445 } 446 447 allowed, ok := b.allowedBuildArgs[argName] 448 449 if !ok { 450 t.Fatalf("%s argument should be allowed as a build arg", argName) 451 } 452 453 if !allowed { 454 t.Fatalf("%s argument was present in map but disallowed as a build arg", argName) 455 } 456 457 val, ok := b.options.BuildArgs[argName] 458 459 if !ok { 460 t.Fatalf("%s argument should be a build arg", argName) 461 } 462 463 if val != "bar" { 464 t.Fatalf("%s argument should have default value 'bar', got %s", argName, val) 465 } 466 } 467 468 func TestShell(t *testing.T) { 469 b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} 470 471 shellCmd := "powershell" 472 473 attrs := make(map[string]bool) 474 attrs["json"] = true 475 476 if err := shell(b, []string{shellCmd}, attrs, ""); err != nil { 477 t.Fatalf("Error should be empty, got: %s", err.Error()) 478 } 479 480 if b.runConfig.Shell == nil { 481 t.Fatalf("Shell should be set") 482 } 483 484 expectedShell := strslice.StrSlice([]string{shellCmd}) 485 486 if !compareStrSlice(expectedShell, b.runConfig.Shell) { 487 t.Fatalf("Shell should be set to %s, got %s", expectedShell, b.runConfig.Shell) 488 } 489 }