فهرست منبع

Merge pull request #23969 from tkopczynski/20784-builder-dockerfile-dispatchers-2

Builder dispatchers unit tests
Vincent Demeester 9 سال پیش
والد
کامیت
0fc062d31e
3فایلهای تغییر یافته به همراه310 افزوده شده و 43 حذف شده
  1. 263 0
      builder/dockerfile/dispatchers_test.go
  2. 33 0
      builder/dockerfile/dispatchers_unix_test.go
  3. 14 43
      builder/dockerfile/internals_test.go

+ 263 - 0
builder/dockerfile/dispatchers_test.go

@@ -6,7 +6,10 @@ import (
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 
 
+	"github.com/docker/engine-api/types"
 	"github.com/docker/engine-api/types/container"
 	"github.com/docker/engine-api/types/container"
+	"github.com/docker/engine-api/types/strslice"
+	"github.com/docker/go-connections/nat"
 )
 )
 
 
 type commandWithFunction struct {
 type commandWithFunction struct {
@@ -206,3 +209,263 @@ func TestOnbuild(t *testing.T) {
 		t.Fatalf("Wrong ONBUILD command. Expected: %s, got: %s", expectedOnbuild, b.runConfig.OnBuild[0])
 		t.Fatalf("Wrong ONBUILD command. Expected: %s, got: %s", expectedOnbuild, b.runConfig.OnBuild[0])
 	}
 	}
 }
 }
+
+func TestWorkdir(t *testing.T) {
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true}
+
+	workingDir := "/app"
+
+	if runtime.GOOS == "windows" {
+		workingDir = "C:\app"
+	}
+
+	err := workdir(b, []string{workingDir}, nil, "")
+
+	if err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	if b.runConfig.WorkingDir != workingDir {
+		t.Fatalf("WorkingDir should be set to %s, got %s", workingDir, b.runConfig.WorkingDir)
+	}
+
+}
+
+func TestCmd(t *testing.T) {
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true}
+
+	command := "./executable"
+
+	err := cmd(b, []string{command}, nil, "")
+
+	if err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	var expectedCommand strslice.StrSlice
+
+	if runtime.GOOS == "windows" {
+		expectedCommand = strslice.StrSlice(append([]string{"cmd"}, "/S", "/C", command))
+	} else {
+		expectedCommand = strslice.StrSlice(append([]string{"/bin/sh"}, "-c", command))
+	}
+
+	if !compareStrSlice(b.runConfig.Cmd, expectedCommand) {
+		t.Fatalf("Command should be set to %s, got %s", command, b.runConfig.Cmd)
+	}
+
+	if !b.cmdSet {
+		t.Fatalf("Command should be marked as set")
+	}
+}
+
+func compareStrSlice(slice1, slice2 strslice.StrSlice) bool {
+	if len(slice1) != len(slice2) {
+		return false
+	}
+
+	for i := range slice1 {
+		if slice1[i] != slice2[i] {
+			return false
+		}
+	}
+
+	return true
+}
+
+func TestHealthcheckNone(t *testing.T) {
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true}
+
+	if err := healthcheck(b, []string{"NONE"}, nil, ""); err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	if b.runConfig.Healthcheck == nil {
+		t.Fatal("Healthcheck should be set, got nil")
+	}
+
+	expectedTest := strslice.StrSlice(append([]string{"NONE"}))
+
+	if !compareStrSlice(expectedTest, b.runConfig.Healthcheck.Test) {
+		t.Fatalf("Command should be set to %s, got %s", expectedTest, b.runConfig.Healthcheck.Test)
+	}
+}
+
+func TestHealthcheckCmd(t *testing.T) {
+	b := &Builder{flags: &BFlags{flags: make(map[string]*Flag)}, runConfig: &container.Config{}, disableCommit: true}
+
+	if err := healthcheck(b, []string{"CMD", "curl", "-f", "http://localhost/", "||", "exit", "1"}, nil, ""); err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	if b.runConfig.Healthcheck == nil {
+		t.Fatal("Healthcheck should be set, got nil")
+	}
+
+	expectedTest := strslice.StrSlice(append([]string{"CMD-SHELL"}, "curl -f http://localhost/ || exit 1"))
+
+	if !compareStrSlice(expectedTest, b.runConfig.Healthcheck.Test) {
+		t.Fatalf("Command should be set to %s, got %s", expectedTest, b.runConfig.Healthcheck.Test)
+	}
+}
+
+func TestEntrypoint(t *testing.T) {
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true}
+
+	entrypointCmd := "/usr/sbin/nginx"
+
+	if err := entrypoint(b, []string{entrypointCmd}, nil, ""); err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	if b.runConfig.Entrypoint == nil {
+		t.Fatalf("Entrypoint should be set")
+	}
+
+	var expectedEntrypoint strslice.StrSlice
+
+	if runtime.GOOS == "windows" {
+		expectedEntrypoint = strslice.StrSlice(append([]string{"cmd"}, "/S", "/C", entrypointCmd))
+	} else {
+		expectedEntrypoint = strslice.StrSlice(append([]string{"/bin/sh"}, "-c", entrypointCmd))
+	}
+
+	if !compareStrSlice(expectedEntrypoint, b.runConfig.Entrypoint) {
+		t.Fatalf("Entrypoint command should be set to %s, got %s", expectedEntrypoint, b.runConfig.Entrypoint)
+	}
+}
+
+func TestExpose(t *testing.T) {
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true}
+
+	exposedPort := "80"
+
+	if err := expose(b, []string{exposedPort}, nil, ""); err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	if b.runConfig.ExposedPorts == nil {
+		t.Fatalf("ExposedPorts should be set")
+	}
+
+	if len(b.runConfig.ExposedPorts) != 1 {
+		t.Fatalf("ExposedPorts should contain only 1 element. Got %s", b.runConfig.ExposedPorts)
+	}
+
+	portsMapping, err := nat.ParsePortSpec(exposedPort)
+
+	if err != nil {
+		t.Fatalf("Error when parsing port spec: %s", err.Error())
+	}
+
+	if _, ok := b.runConfig.ExposedPorts[portsMapping[0].Port]; !ok {
+		t.Fatalf("Port %s should be present. Got %s", exposedPort, b.runConfig.ExposedPorts)
+	}
+}
+
+func TestUser(t *testing.T) {
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true}
+
+	userCommand := "foo"
+
+	if err := user(b, []string{userCommand}, nil, ""); err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	if b.runConfig.User != userCommand {
+		t.Fatalf("User should be set to %s, got %s", userCommand, b.runConfig.User)
+	}
+}
+
+func TestVolume(t *testing.T) {
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true}
+
+	exposedVolume := "/foo"
+
+	if err := volume(b, []string{exposedVolume}, nil, ""); err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	if b.runConfig.Volumes == nil {
+		t.Fatalf("Volumes should be set")
+	}
+
+	if len(b.runConfig.Volumes) != 1 {
+		t.Fatalf("Volumes should contain only 1 element. Got %s", b.runConfig.Volumes)
+	}
+
+	if _, ok := b.runConfig.Volumes[exposedVolume]; !ok {
+		t.Fatalf("Volume %s should be present. Got %s", exposedVolume, b.runConfig.Volumes)
+	}
+}
+
+func TestStopSignal(t *testing.T) {
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true}
+
+	signal := "SIGKILL"
+
+	if err := stopSignal(b, []string{signal}, nil, ""); err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	if b.runConfig.StopSignal != signal {
+		t.Fatalf("StopSignal should be set to %s, got %s", signal, b.runConfig.StopSignal)
+	}
+}
+
+func TestArg(t *testing.T) {
+	buildOptions := &types.ImageBuildOptions{BuildArgs: make(map[string]string)}
+
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true, allowedBuildArgs: make(map[string]bool), options: buildOptions}
+
+	argName := "foo"
+	argVal := "bar"
+	argDef := fmt.Sprintf("%s=%s", argName, argVal)
+
+	if err := arg(b, []string{argDef}, nil, ""); err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	allowed, ok := b.allowedBuildArgs[argName]
+
+	if !ok {
+		t.Fatalf("%s argument should be allowed as a build arg", argName)
+	}
+
+	if !allowed {
+		t.Fatalf("%s argument was present in map but disallowed as a build arg", argName)
+	}
+
+	val, ok := b.options.BuildArgs[argName]
+
+	if !ok {
+		t.Fatalf("%s argument should be a build arg", argName)
+	}
+
+	if val != "bar" {
+		t.Fatalf("%s argument should have default value 'bar', got %s", argName, val)
+	}
+}
+
+func TestShell(t *testing.T) {
+	b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true}
+
+	shellCmd := "powershell"
+
+	attrs := make(map[string]bool)
+	attrs["json"] = true
+
+	if err := shell(b, []string{shellCmd}, attrs, ""); err != nil {
+		t.Fatalf("Error should be empty, got: %s", err.Error())
+	}
+
+	if b.runConfig.Shell == nil {
+		t.Fatalf("Shell should be set")
+	}
+
+	expectedShell := strslice.StrSlice([]string{shellCmd})
+
+	if !compareStrSlice(expectedShell, b.runConfig.Shell) {
+		t.Fatalf("Shell should be set to %s, got %s", expectedShell, b.runConfig.Shell)
+	}
+}

+ 33 - 0
builder/dockerfile/dispatchers_unix_test.go

@@ -0,0 +1,33 @@
+// +build !windows
+
+package dockerfile
+
+import (
+	"testing"
+)
+
+func TestNormaliseWorkdir(t *testing.T) {
+	testCases := []struct{ current, requested, expected, expectedError string }{
+		{``, ``, ``, `cannot normalise nothing`},
+		{``, `foo`, `/foo`, ``},
+		{``, `/foo`, `/foo`, ``},
+		{`/foo`, `bar`, `/foo/bar`, ``},
+		{`/foo`, `/bar`, `/bar`, ``},
+	}
+
+	for _, test := range testCases {
+		normalised, err := normaliseWorkdir(test.current, test.requested)
+
+		if test.expectedError != "" && err == nil {
+			t.Fatalf("NormaliseWorkdir should return an error %s, got nil", test.expectedError)
+		}
+
+		if test.expectedError != "" && err.Error() != test.expectedError {
+			t.Fatalf("NormaliseWorkdir returned wrong error. Expected %s, got %s", test.expectedError, err.Error())
+		}
+
+		if normalised != test.expected {
+			t.Fatalf("NormaliseWorkdir error. Expected %s for current %s and requested %s, got %s", test.expected, test.current, test.requested, normalised)
+		}
+	}
+}

+ 14 - 43
builder/dockerfile/internals_test.go

@@ -34,52 +34,25 @@ func TestSymlinkDockerfile(t *testing.T) {
 	readAndCheckDockerfile(t, "symlinkDockerfile", contextDir, builder.DefaultDockerfileName, expectedError)
 	readAndCheckDockerfile(t, "symlinkDockerfile", contextDir, builder.DefaultDockerfileName, expectedError)
 }
 }
 
 
-func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath, expectedError string) {
-	tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
-
-	if err != nil {
-		t.Fatalf("Error when creating tar stream: %s", err)
-	}
-
-	defer func() {
-		if err = tarStream.Close(); err != nil {
-			t.Fatalf("Error when closing tar stream: %s", err)
-		}
-	}()
-
-	context, err := builder.MakeTarSumContext(tarStream)
-
-	if err != nil {
-		t.Fatalf("Error when creating tar context: %s", err)
-	}
-
-	defer func() {
-		if err = context.Close(); err != nil {
-			t.Fatalf("Error when closing tar context: %s", err)
-		}
-	}()
-
-	options := &types.ImageBuildOptions{
-		Dockerfile: dockerfilePath,
-	}
-
-	b := &Builder{options: options, context: context}
-
-	err = b.readDockerfile()
+func TestDockerfileOutsideTheBuildContext(t *testing.T) {
+	contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test")
+	defer cleanup()
 
 
-	if err == nil {
-		t.Fatalf("No error when executing test: %s", testName)
-	}
+	expectedError := "Forbidden path outside the build context"
 
 
-	if !strings.Contains(err.Error(), expectedError) {
-		t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", expectedError, err.Error())
-	}
+	readAndCheckDockerfile(t, "DockerfileOutsideTheBuildContext", contextDir, "../../Dockerfile", expectedError)
 }
 }
 
 
-func TestDockerfileOutsideTheBuildContext(t *testing.T) {
+func TestNonExistingDockerfile(t *testing.T) {
 	contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test")
 	contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test")
 	defer cleanup()
 	defer cleanup()
 
 
+	expectedError := "Cannot locate specified Dockerfile: Dockerfile"
+
+	readAndCheckDockerfile(t, "NonExistingDockerfile", contextDir, "Dockerfile", expectedError)
+}
+
+func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath, expectedError string) {
 	tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
 	tarStream, err := archive.Tar(contextDir, archive.Uncompressed)
 
 
 	if err != nil {
 	if err != nil {
@@ -105,7 +78,7 @@ func TestDockerfileOutsideTheBuildContext(t *testing.T) {
 	}()
 	}()
 
 
 	options := &types.ImageBuildOptions{
 	options := &types.ImageBuildOptions{
-		Dockerfile: "../../Dockerfile",
+		Dockerfile: dockerfilePath,
 	}
 	}
 
 
 	b := &Builder{options: options, context: context}
 	b := &Builder{options: options, context: context}
@@ -113,11 +86,9 @@ func TestDockerfileOutsideTheBuildContext(t *testing.T) {
 	err = b.readDockerfile()
 	err = b.readDockerfile()
 
 
 	if err == nil {
 	if err == nil {
-		t.Fatalf("No error when executing test for Dockerfile outside the build context")
+		t.Fatalf("No error when executing test: %s", testName)
 	}
 	}
 
 
-	expectedError := "Forbidden path outside the build context"
-
 	if !strings.Contains(err.Error(), expectedError) {
 	if !strings.Contains(err.Error(), expectedError) {
 		t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", expectedError, err.Error())
 		t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", expectedError, err.Error())
 	}
 	}