瀏覽代碼

* Builder: reorganized unit tests for better code reuse, and to test non-empty contexts

Solomon Hykes 12 年之前
父節點
當前提交
061f8d12e0
共有 2 個文件被更改,包括 88 次插入66 次删除
  1. 73 55
      buildfile_test.go
  2. 15 11
      commands.go

+ 73 - 55
buildfile_test.go

@@ -1,40 +1,75 @@
 package docker
 
 import (
-	"github.com/dotcloud/docker/utils"
+	"io/ioutil"
 	"testing"
 )
 
-const Dockerfile = `
+// mkTestContext generates a build context from the contents of the provided dockerfile.
+// This context is suitable for use as an argument to BuildFile.Build()
+func mkTestContext(dockerfile string, files [][2]string, t *testing.T) Archive {
+	context, err := mkBuildContext(dockerfile, files)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return context
+}
+
+// A testContextTemplate describes a build context and how to test it
+type testContextTemplate struct {
+	// Contents of the Dockerfile
+	dockerfile string
+	// Additional files in the context, eg [][2]string{"./passwd", "gordon"}
+	files [][2]string
+	// Test commands to run in the resulting image
+	tests []testCommand
+}
+
+// A testCommand describes a command to run in a container, and the exact output required to pass the test
+type testCommand struct {
+	// The command to run, eg. []string{"echo", "hello", "world"}
+	cmd []string
+	// The exact output expected, eg. "hello world\n"
+	output string
+}
+
+// A table of all the contexts to build and test.
+// A new docker runtime will be created and torn down for each context.
+var testContexts []testContextTemplate = []testContextTemplate{
+	{
+		`
 # VERSION		0.1
 # DOCKER-VERSION	0.2
 
-from   ` + unitTestImageName + `
+from   docker-ut
 run    sh -c 'echo root:testpass > /tmp/passwd'
 run    mkdir -p /var/run/sshd
-`
+`,
+		nil,
+		[]testCommand{
+			{[]string{"cat", "/tmp/passwd"}, "root:testpass\n"},
+			{[]string{"ls", "-d", "/var/run/sshd"}, "/var/run/sshd\n"},
+		},
+	},
 
-const DockerfileNoNewLine = `
+	{
+		`
 # VERSION		0.1
 # DOCKER-VERSION	0.2
 
-from   ` + unitTestImageName + `
+from   docker-ut
 run    sh -c 'echo root:testpass > /tmp/passwd'
-run    mkdir -p /var/run/sshd`
-
-// mkTestContext generates a build context from the contents of the provided dockerfile.
-// This context is suitable for use as an argument to BuildFile.Build()
-func mkTestContext(dockerfile string, t *testing.T) Archive {
-	context, err := mkBuildContext(dockerfile)
-	if err != nil {
-		t.Fatal(err)
-	}
-	return context
+run    mkdir -p /var/run/sshd`,
+		nil,
+		[]testCommand{
+			{[]string{"cat", "/tmp/passwd"}, "root:testpass\n"},
+			{[]string{"ls", "-d", "/var/run/sshd"}, "/var/run/sshd\n"},
+		},
+	},
 }
 
 func TestBuild(t *testing.T) {
-	dockerfiles := []string{Dockerfile, DockerfileNoNewLine}
-	for _, Dockerfile := range dockerfiles {
+	for _, ctx := range testContexts {
 		runtime, err := newTestRuntime()
 		if err != nil {
 			t.Fatal(err)
@@ -43,50 +78,33 @@ func TestBuild(t *testing.T) {
 
 		srv := &Server{runtime: runtime}
 
-		buildfile := NewBuildFile(srv, &utils.NopWriter{})
+		buildfile := NewBuildFile(srv, ioutil.Discard)
 
-		imgID, err := buildfile.Build(mkTestContext(Dockerfile, t))
+		imgID, err := buildfile.Build(mkTestContext(ctx.dockerfile, ctx.files, t))
 		if err != nil {
 			t.Fatal(err)
 		}
 
 		builder := NewBuilder(runtime)
-		container, err := builder.Create(
-			&Config{
-				Image: imgID,
-				Cmd:   []string{"cat", "/tmp/passwd"},
-			},
-		)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer runtime.Destroy(container)
+		for _, testCmd := range ctx.tests {
+			container, err := builder.Create(
+				&Config{
+					Image: imgID,
+					Cmd:   testCmd.cmd,
+				},
+			)
+			if err != nil {
+				t.Fatal(err)
+			}
+			defer runtime.Destroy(container)
 
-		output, err := container.Output()
-		if err != nil {
-			t.Fatal(err)
-		}
-		if string(output) != "root:testpass\n" {
-			t.Fatalf("Unexpected output. Read '%s', expected '%s'", output, "root:testpass\n")
-		}
-
-		container2, err := builder.Create(
-			&Config{
-				Image: imgID,
-				Cmd:   []string{"ls", "-d", "/var/run/sshd"},
-			},
-		)
-		if err != nil {
-			t.Fatal(err)
-		}
-		defer runtime.Destroy(container2)
-
-		output, err = container2.Output()
-		if err != nil {
-			t.Fatal(err)
-		}
-		if string(output) != "/var/run/sshd\n" {
-			t.Fatal("/var/run/sshd has not been created")
+			output, err := container.Output()
+			if err != nil {
+				t.Fatal(err)
+			}
+			if string(output) != testCmd.output {
+				t.Fatalf("Unexpected output. Read '%s', expected '%s'", output, testCmd.output)
+			}
 		}
 	}
 }

+ 15 - 11
commands.go

@@ -132,18 +132,22 @@ func (cli *DockerCli) CmdInsert(args ...string) error {
 
 // mkBuildContext returns an archive of an empty context with the contents
 // of `dockerfile` at the path ./Dockerfile
-func mkBuildContext(content string) (Archive, error) {
+func mkBuildContext(dockerfile string, files [][2]string) (Archive, error) {
 	buf := new(bytes.Buffer)
 	tw := tar.NewWriter(buf)
-	hdr := &tar.Header{
-		Name: "Dockerfile",
-		Size: int64(len(content)),
-	}
-	if err := tw.WriteHeader(hdr); err != nil {
-		return nil, err
-	}
-	if _, err := tw.Write([]byte(content)); err != nil {
-		return nil, err
+	files = append(files, [2]string{"Dockerfile", dockerfile})
+	for _, file := range files {
+		name, content := file[0], file[1]
+		hdr := &tar.Header{
+			Name: name,
+			Size: int64(len(content)),
+		}
+		if err := tw.WriteHeader(hdr); err != nil {
+			return nil, err
+		}
+		if _, err := tw.Write([]byte(content)); err != nil {
+			return nil, err
+		}
 	}
 	if err := tw.Close(); err != nil {
 		return nil, err
@@ -174,7 +178,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
 		if err != nil {
 			return err
 		}
-		context, err = mkBuildContext(string(dockerfile))
+		context, err = mkBuildContext(string(dockerfile), nil)
 	} else {
 		context, err = Tar(cmd.Arg(0), Uncompressed)
 	}