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  }