Browse code

Move fakecontext, fakegit and fakestorage to internal/test

Signed-off-by: Vincent Demeester <vincent@sbr.pm>

Vincent Demeester authored on 2018/04/16 21:39:13
Showing 18 changed files
... ...
@@ -15,11 +15,11 @@ import (
15 15
 
16 16
 	"github.com/docker/docker/integration-cli/checker"
17 17
 	"github.com/docker/docker/integration-cli/cli"
18
-	"github.com/docker/docker/integration-cli/cli/build/fakestorage"
19 18
 	"github.com/docker/docker/integration-cli/daemon"
20 19
 	"github.com/docker/docker/integration-cli/environment"
21 20
 	testdaemon "github.com/docker/docker/internal/test/daemon"
22 21
 	ienv "github.com/docker/docker/internal/test/environment"
22
+	"github.com/docker/docker/internal/test/fakestorage"
23 23
 	"github.com/docker/docker/internal/test/fixtures/plugin"
24 24
 	"github.com/docker/docker/internal/test/registry"
25 25
 	"github.com/docker/docker/pkg/reexec"
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"io"
5 5
 	"strings"
6 6
 
7
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
7
+	"github.com/docker/docker/internal/test/fakecontext"
8 8
 	"github.com/gotestyourself/gotestyourself/icmd"
9 9
 )
10 10
 
11 11
deleted file mode 100644
... ...
@@ -1,124 +0,0 @@
1
-package fakecontext // import "github.com/docker/docker/integration-cli/cli/build/fakecontext"
2
-
3
-import (
4
-	"bytes"
5
-	"io"
6
-	"io/ioutil"
7
-	"os"
8
-	"path/filepath"
9
-
10
-	"github.com/docker/docker/pkg/archive"
11
-)
12
-
13
-type testingT interface {
14
-	Fatal(args ...interface{})
15
-	Fatalf(string, ...interface{})
16
-}
17
-
18
-// New creates a fake build context
19
-func New(t testingT, dir string, modifiers ...func(*Fake) error) *Fake {
20
-	fakeContext := &Fake{Dir: dir}
21
-	if dir == "" {
22
-		if err := newDir(fakeContext); err != nil {
23
-			t.Fatal(err)
24
-		}
25
-	}
26
-
27
-	for _, modifier := range modifiers {
28
-		if err := modifier(fakeContext); err != nil {
29
-			t.Fatal(err)
30
-		}
31
-	}
32
-
33
-	return fakeContext
34
-}
35
-
36
-func newDir(fake *Fake) error {
37
-	tmp, err := ioutil.TempDir("", "fake-context")
38
-	if err != nil {
39
-		return err
40
-	}
41
-	if err := os.Chmod(tmp, 0755); err != nil {
42
-		return err
43
-	}
44
-	fake.Dir = tmp
45
-	return nil
46
-}
47
-
48
-// WithFile adds the specified file (with content) in the build context
49
-func WithFile(name, content string) func(*Fake) error {
50
-	return func(ctx *Fake) error {
51
-		return ctx.Add(name, content)
52
-	}
53
-}
54
-
55
-// WithDockerfile adds the specified content as Dockerfile in the build context
56
-func WithDockerfile(content string) func(*Fake) error {
57
-	return WithFile("Dockerfile", content)
58
-}
59
-
60
-// WithFiles adds the specified files in the build context, content is a string
61
-func WithFiles(files map[string]string) func(*Fake) error {
62
-	return func(fakeContext *Fake) error {
63
-		for file, content := range files {
64
-			if err := fakeContext.Add(file, content); err != nil {
65
-				return err
66
-			}
67
-		}
68
-		return nil
69
-	}
70
-}
71
-
72
-// WithBinaryFiles adds the specified files in the build context, content is binary
73
-func WithBinaryFiles(files map[string]*bytes.Buffer) func(*Fake) error {
74
-	return func(fakeContext *Fake) error {
75
-		for file, content := range files {
76
-			if err := fakeContext.Add(file, string(content.Bytes())); err != nil {
77
-				return err
78
-			}
79
-		}
80
-		return nil
81
-	}
82
-}
83
-
84
-// Fake creates directories that can be used as a build context
85
-type Fake struct {
86
-	Dir string
87
-}
88
-
89
-// Add a file at a path, creating directories where necessary
90
-func (f *Fake) Add(file, content string) error {
91
-	return f.addFile(file, []byte(content))
92
-}
93
-
94
-func (f *Fake) addFile(file string, content []byte) error {
95
-	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
96
-	dirpath := filepath.Dir(fp)
97
-	if dirpath != "." {
98
-		if err := os.MkdirAll(dirpath, 0755); err != nil {
99
-			return err
100
-		}
101
-	}
102
-	return ioutil.WriteFile(fp, content, 0644)
103
-
104
-}
105
-
106
-// Delete a file at a path
107
-func (f *Fake) Delete(file string) error {
108
-	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
109
-	return os.RemoveAll(fp)
110
-}
111
-
112
-// Close deletes the context
113
-func (f *Fake) Close() error {
114
-	return os.RemoveAll(f.Dir)
115
-}
116
-
117
-// AsTarReader returns a ReadCloser with the contents of Dir as a tar archive.
118
-func (f *Fake) AsTarReader(t testingT) io.ReadCloser {
119
-	reader, err := archive.TarWithOptions(f.Dir, &archive.TarOptions{})
120
-	if err != nil {
121
-		t.Fatalf("Failed to create tar from %s: %s", f.Dir, err)
122
-	}
123
-	return reader
124
-}
125 1
deleted file mode 100644
... ...
@@ -1,132 +0,0 @@
1
-package fakegit // import "github.com/docker/docker/integration-cli/cli/build/fakegit"
2
-
3
-import (
4
-	"fmt"
5
-	"io/ioutil"
6
-	"net/http"
7
-	"net/http/httptest"
8
-	"os"
9
-	"os/exec"
10
-	"path/filepath"
11
-
12
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
13
-	"github.com/docker/docker/integration-cli/cli/build/fakestorage"
14
-	"github.com/gotestyourself/gotestyourself/assert"
15
-)
16
-
17
-type testingT interface {
18
-	assert.TestingT
19
-	logT
20
-	skipT
21
-	Fatal(args ...interface{})
22
-	Fatalf(string, ...interface{})
23
-}
24
-
25
-type logT interface {
26
-	Logf(string, ...interface{})
27
-}
28
-
29
-type skipT interface {
30
-	Skip(reason string)
31
-}
32
-
33
-type gitServer interface {
34
-	URL() string
35
-	Close() error
36
-}
37
-
38
-type localGitServer struct {
39
-	*httptest.Server
40
-}
41
-
42
-func (r *localGitServer) Close() error {
43
-	r.Server.Close()
44
-	return nil
45
-}
46
-
47
-func (r *localGitServer) URL() string {
48
-	return r.Server.URL
49
-}
50
-
51
-// FakeGit is a fake git server
52
-type FakeGit struct {
53
-	root    string
54
-	server  gitServer
55
-	RepoURL string
56
-}
57
-
58
-// Close closes the server, implements Closer interface
59
-func (g *FakeGit) Close() {
60
-	g.server.Close()
61
-	os.RemoveAll(g.root)
62
-}
63
-
64
-// New create a fake git server that can be used for git related tests
65
-func New(c testingT, name string, files map[string]string, enforceLocalServer bool) *FakeGit {
66
-	ctx := fakecontext.New(c, "", fakecontext.WithFiles(files))
67
-	defer ctx.Close()
68
-	curdir, err := os.Getwd()
69
-	if err != nil {
70
-		c.Fatal(err)
71
-	}
72
-	defer os.Chdir(curdir)
73
-
74
-	if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
75
-		c.Fatalf("error trying to init repo: %s (%s)", err, output)
76
-	}
77
-	err = os.Chdir(ctx.Dir)
78
-	if err != nil {
79
-		c.Fatal(err)
80
-	}
81
-	if output, err := exec.Command("git", "config", "user.name", "Fake User").CombinedOutput(); err != nil {
82
-		c.Fatalf("error trying to set 'user.name': %s (%s)", err, output)
83
-	}
84
-	if output, err := exec.Command("git", "config", "user.email", "fake.user@example.com").CombinedOutput(); err != nil {
85
-		c.Fatalf("error trying to set 'user.email': %s (%s)", err, output)
86
-	}
87
-	if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
88
-		c.Fatalf("error trying to add files to repo: %s (%s)", err, output)
89
-	}
90
-	if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
91
-		c.Fatalf("error trying to commit to repo: %s (%s)", err, output)
92
-	}
93
-
94
-	root, err := ioutil.TempDir("", "docker-test-git-repo")
95
-	if err != nil {
96
-		c.Fatal(err)
97
-	}
98
-	repoPath := filepath.Join(root, name+".git")
99
-	if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
100
-		os.RemoveAll(root)
101
-		c.Fatalf("error trying to clone --bare: %s (%s)", err, output)
102
-	}
103
-	err = os.Chdir(repoPath)
104
-	if err != nil {
105
-		os.RemoveAll(root)
106
-		c.Fatal(err)
107
-	}
108
-	if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
109
-		os.RemoveAll(root)
110
-		c.Fatalf("error trying to git update-server-info: %s (%s)", err, output)
111
-	}
112
-	err = os.Chdir(curdir)
113
-	if err != nil {
114
-		os.RemoveAll(root)
115
-		c.Fatal(err)
116
-	}
117
-
118
-	var server gitServer
119
-	if !enforceLocalServer {
120
-		// use fakeStorage server, which might be local or remote (at test daemon)
121
-		server = fakestorage.New(c, root)
122
-	} else {
123
-		// always start a local http server on CLI test machine
124
-		httpServer := httptest.NewServer(http.FileServer(http.Dir(root)))
125
-		server = &localGitServer{httpServer}
126
-	}
127
-	return &FakeGit{
128
-		root:    root,
129
-		server:  server,
130
-		RepoURL: fmt.Sprintf("%s/%s.git", server.URL(), name),
131
-	}
132
-}
133 1
deleted file mode 100644
... ...
@@ -1,74 +0,0 @@
1
-package fakestorage // import "github.com/docker/docker/integration-cli/cli/build/fakestorage"
2
-
3
-import (
4
-	"io/ioutil"
5
-	"os"
6
-	"os/exec"
7
-	"path/filepath"
8
-	"sync"
9
-
10
-	"github.com/docker/docker/integration-cli/cli"
11
-)
12
-
13
-var ensureHTTPServerOnce sync.Once
14
-
15
-func ensureHTTPServerImage(t testingT) {
16
-	var doIt bool
17
-	ensureHTTPServerOnce.Do(func() {
18
-		doIt = true
19
-	})
20
-
21
-	if !doIt {
22
-		return
23
-	}
24
-
25
-	defer testEnv.ProtectImage(t, "httpserver:latest")
26
-
27
-	tmp, err := ioutil.TempDir("", "docker-http-server-test")
28
-	if err != nil {
29
-		t.Fatalf("could not build http server: %v", err)
30
-	}
31
-	defer os.RemoveAll(tmp)
32
-
33
-	goos := testEnv.OSType
34
-	if goos == "" {
35
-		goos = "linux"
36
-	}
37
-	goarch := os.Getenv("DOCKER_ENGINE_GOARCH")
38
-	if goarch == "" {
39
-		goarch = "amd64"
40
-	}
41
-
42
-	cpCmd, lookErr := exec.LookPath("cp")
43
-	if lookErr != nil {
44
-		t.Fatalf("could not build http server: %v", lookErr)
45
-	}
46
-
47
-	if _, err = os.Stat("../contrib/httpserver/httpserver"); os.IsNotExist(err) {
48
-		goCmd, lookErr := exec.LookPath("go")
49
-		if lookErr != nil {
50
-			t.Fatalf("could not build http server: %v", lookErr)
51
-		}
52
-
53
-		cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver")
54
-		cmd.Env = append(os.Environ(), []string{
55
-			"CGO_ENABLED=0",
56
-			"GOOS=" + goos,
57
-			"GOARCH=" + goarch,
58
-		}...)
59
-		var out []byte
60
-		if out, err = cmd.CombinedOutput(); err != nil {
61
-			t.Fatalf("could not build http server: %s", string(out))
62
-		}
63
-	} else {
64
-		if out, err := exec.Command(cpCmd, "../contrib/httpserver/httpserver", filepath.Join(tmp, "httpserver")).CombinedOutput(); err != nil {
65
-			t.Fatalf("could not copy http server: %v", string(out))
66
-		}
67
-	}
68
-
69
-	if out, err := exec.Command(cpCmd, "../contrib/httpserver/Dockerfile", filepath.Join(tmp, "Dockerfile")).CombinedOutput(); err != nil {
70
-		t.Fatalf("could not build http server: %v", string(out))
71
-	}
72
-
73
-	cli.DockerCmd(t, "build", "-q", "-t", "httpserver", tmp)
74
-}
75 1
deleted file mode 100644
... ...
@@ -1,175 +0,0 @@
1
-package fakestorage // import "github.com/docker/docker/integration-cli/cli/build/fakestorage"
2
-
3
-import (
4
-	"fmt"
5
-	"net"
6
-	"net/http"
7
-	"net/http/httptest"
8
-	"net/url"
9
-	"os"
10
-	"strings"
11
-
12
-	"github.com/docker/docker/integration-cli/cli"
13
-	"github.com/docker/docker/integration-cli/cli/build"
14
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
15
-	"github.com/docker/docker/integration-cli/request"
16
-	"github.com/docker/docker/internal/test/environment"
17
-	"github.com/docker/docker/internal/testutil"
18
-	"github.com/gotestyourself/gotestyourself/assert"
19
-)
20
-
21
-var testEnv *environment.Execution
22
-
23
-type testingT interface {
24
-	assert.TestingT
25
-	logT
26
-	skipT
27
-	Fatal(args ...interface{})
28
-	Fatalf(string, ...interface{})
29
-}
30
-
31
-type logT interface {
32
-	Logf(string, ...interface{})
33
-}
34
-
35
-type skipT interface {
36
-	Skip(reason string)
37
-}
38
-
39
-// Fake is a static file server. It might be running locally or remotely
40
-// on test host.
41
-type Fake interface {
42
-	Close() error
43
-	URL() string
44
-	CtxDir() string
45
-}
46
-
47
-// SetTestEnvironment sets a static test environment
48
-// TODO: decouple this package from environment
49
-func SetTestEnvironment(env *environment.Execution) {
50
-	testEnv = env
51
-}
52
-
53
-// New returns a static file server that will be use as build context.
54
-func New(t testingT, dir string, modifiers ...func(*fakecontext.Fake) error) Fake {
55
-	if testEnv == nil {
56
-		t.Fatal("fakstorage package requires SetTestEnvironment() to be called before use.")
57
-	}
58
-	ctx := fakecontext.New(t, dir, modifiers...)
59
-	switch {
60
-	case testEnv.IsRemoteDaemon() && strings.HasPrefix(request.DaemonHost(), "unix:///"):
61
-		t.Skip(fmt.Sprintf("e2e run : daemon is remote but docker host points to a unix socket"))
62
-	case testEnv.IsLocalDaemon():
63
-		return newLocalFakeStorage(ctx)
64
-	default:
65
-		return newRemoteFileServer(t, ctx)
66
-	}
67
-	return nil
68
-}
69
-
70
-// localFileStorage is a file storage on the running machine
71
-type localFileStorage struct {
72
-	*fakecontext.Fake
73
-	*httptest.Server
74
-}
75
-
76
-func (s *localFileStorage) URL() string {
77
-	return s.Server.URL
78
-}
79
-
80
-func (s *localFileStorage) CtxDir() string {
81
-	return s.Fake.Dir
82
-}
83
-
84
-func (s *localFileStorage) Close() error {
85
-	defer s.Server.Close()
86
-	return s.Fake.Close()
87
-}
88
-
89
-func newLocalFakeStorage(ctx *fakecontext.Fake) *localFileStorage {
90
-	handler := http.FileServer(http.Dir(ctx.Dir))
91
-	server := httptest.NewServer(handler)
92
-	return &localFileStorage{
93
-		Fake:   ctx,
94
-		Server: server,
95
-	}
96
-}
97
-
98
-// remoteFileServer is a containerized static file server started on the remote
99
-// testing machine to be used in URL-accepting docker build functionality.
100
-type remoteFileServer struct {
101
-	host      string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712
102
-	container string
103
-	image     string
104
-	ctx       *fakecontext.Fake
105
-}
106
-
107
-func (f *remoteFileServer) URL() string {
108
-	u := url.URL{
109
-		Scheme: "http",
110
-		Host:   f.host}
111
-	return u.String()
112
-}
113
-
114
-func (f *remoteFileServer) CtxDir() string {
115
-	return f.ctx.Dir
116
-}
117
-
118
-func (f *remoteFileServer) Close() error {
119
-	defer func() {
120
-		if f.ctx != nil {
121
-			f.ctx.Close()
122
-		}
123
-		if f.image != "" {
124
-			if err := cli.Docker(cli.Args("rmi", "-f", f.image)).Error; err != nil {
125
-				fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err)
126
-			}
127
-		}
128
-	}()
129
-	if f.container == "" {
130
-		return nil
131
-	}
132
-	return cli.Docker(cli.Args("rm", "-fv", f.container)).Error
133
-}
134
-
135
-func newRemoteFileServer(t testingT, ctx *fakecontext.Fake) *remoteFileServer {
136
-	var (
137
-		image     = fmt.Sprintf("fileserver-img-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10)))
138
-		container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10)))
139
-	)
140
-
141
-	ensureHTTPServerImage(t)
142
-
143
-	// Build the image
144
-	if err := ctx.Add("Dockerfile", `FROM httpserver
145
-COPY . /static`); err != nil {
146
-		t.Fatal(err)
147
-	}
148
-	cli.BuildCmd(t, image, build.WithoutCache, build.WithExternalBuildContext(ctx))
149
-
150
-	// Start the container
151
-	cli.DockerCmd(t, "run", "-d", "-P", "--name", container, image)
152
-
153
-	// Find out the system assigned port
154
-	out := cli.DockerCmd(t, "port", container, "80/tcp").Combined()
155
-	fileserverHostPort := strings.Trim(out, "\n")
156
-	_, port, err := net.SplitHostPort(fileserverHostPort)
157
-	if err != nil {
158
-		t.Fatalf("unable to parse file server host:port: %v", err)
159
-	}
160
-
161
-	dockerHostURL, err := url.Parse(request.DaemonHost())
162
-	if err != nil {
163
-		t.Fatalf("unable to parse daemon host URL: %v", err)
164
-	}
165
-	host, _, err := net.SplitHostPort(dockerHostURL.Host)
166
-	if err != nil {
167
-		t.Fatalf("unable to parse docker daemon host:port: %v", err)
168
-	}
169
-
170
-	return &remoteFileServer{
171
-		container: container,
172
-		image:     image,
173
-		host:      fmt.Sprintf("%s:%s", host, port),
174
-		ctx:       ctx}
175
-}
... ...
@@ -13,10 +13,10 @@ import (
13 13
 
14 14
 	"github.com/docker/docker/api/types"
15 15
 	"github.com/docker/docker/integration-cli/checker"
16
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
17
-	"github.com/docker/docker/integration-cli/cli/build/fakegit"
18
-	"github.com/docker/docker/integration-cli/cli/build/fakestorage"
19 16
 	"github.com/docker/docker/integration-cli/request"
17
+	"github.com/docker/docker/internal/test/fakecontext"
18
+	"github.com/docker/docker/internal/test/fakegit"
19
+	"github.com/docker/docker/internal/test/fakestorage"
20 20
 	"github.com/go-check/check"
21 21
 	"github.com/gotestyourself/gotestyourself/assert"
22 22
 	is "github.com/gotestyourself/gotestyourself/assert/cmp"
... ...
@@ -20,9 +20,9 @@ import (
20 20
 	"github.com/docker/docker/integration-cli/checker"
21 21
 	"github.com/docker/docker/integration-cli/cli"
22 22
 	"github.com/docker/docker/integration-cli/cli/build"
23
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
24
-	"github.com/docker/docker/integration-cli/cli/build/fakegit"
25
-	"github.com/docker/docker/integration-cli/cli/build/fakestorage"
23
+	"github.com/docker/docker/internal/test/fakecontext"
24
+	"github.com/docker/docker/internal/test/fakegit"
25
+	"github.com/docker/docker/internal/test/fakestorage"
26 26
 	"github.com/docker/docker/internal/testutil"
27 27
 	"github.com/docker/docker/pkg/archive"
28 28
 	"github.com/go-check/check"
... ...
@@ -18,7 +18,7 @@ import (
18 18
 	"github.com/docker/docker/integration-cli/checker"
19 19
 	"github.com/docker/docker/integration-cli/cli"
20 20
 	"github.com/docker/docker/integration-cli/cli/build"
21
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
21
+	"github.com/docker/docker/internal/test/fakecontext"
22 22
 	units "github.com/docker/go-units"
23 23
 	"github.com/go-check/check"
24 24
 	"github.com/gotestyourself/gotestyourself/icmd"
... ...
@@ -11,7 +11,7 @@ import (
11 11
 	"github.com/docker/docker/integration-cli/checker"
12 12
 	"github.com/docker/docker/integration-cli/cli"
13 13
 	"github.com/docker/docker/integration-cli/cli/build"
14
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
14
+	"github.com/docker/docker/internal/test/fakecontext"
15 15
 	"github.com/docker/docker/pkg/stringid"
16 16
 	"github.com/docker/go-connections/nat"
17 17
 	"github.com/go-check/check"
... ...
@@ -25,7 +25,7 @@ import (
25 25
 	"github.com/docker/docker/integration-cli/checker"
26 26
 	"github.com/docker/docker/integration-cli/cli"
27 27
 	"github.com/docker/docker/integration-cli/cli/build"
28
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
28
+	"github.com/docker/docker/internal/test/fakecontext"
29 29
 	"github.com/docker/docker/internal/testutil"
30 30
 	"github.com/docker/docker/pkg/mount"
31 31
 	"github.com/docker/docker/pkg/parsers/kernel"
... ...
@@ -8,9 +8,9 @@ import (
8 8
 	"testing"
9 9
 
10 10
 	dclient "github.com/docker/docker/client"
11
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
12 11
 	"github.com/docker/docker/integration-cli/request"
13 12
 	"github.com/docker/docker/internal/test/daemon"
13
+	"github.com/docker/docker/internal/test/fakecontext"
14 14
 	"github.com/gotestyourself/gotestyourself/assert"
15 15
 	is "github.com/gotestyourself/gotestyourself/assert/cmp"
16 16
 	"github.com/moby/buildkit/session"
... ...
@@ -9,9 +9,9 @@ import (
9 9
 	"testing"
10 10
 
11 11
 	"github.com/docker/docker/api/types"
12
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
13 12
 	"github.com/docker/docker/integration/internal/container"
14 13
 	"github.com/docker/docker/internal/test/daemon"
14
+	"github.com/docker/docker/internal/test/fakecontext"
15 15
 	"github.com/docker/docker/pkg/stdcopy"
16 16
 	"github.com/gotestyourself/gotestyourself/assert"
17 17
 	is "github.com/gotestyourself/gotestyourself/assert/cmp"
... ...
@@ -13,8 +13,8 @@ import (
13 13
 	"github.com/docker/docker/api/types"
14 14
 	"github.com/docker/docker/api/types/filters"
15 15
 	"github.com/docker/docker/api/types/versions"
16
-	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
17 16
 	"github.com/docker/docker/integration/internal/request"
17
+	"github.com/docker/docker/internal/test/fakecontext"
18 18
 	"github.com/docker/docker/pkg/jsonmessage"
19 19
 	"github.com/gotestyourself/gotestyourself/assert"
20 20
 	is "github.com/gotestyourself/gotestyourself/assert/cmp"
21 21
new file mode 100644
... ...
@@ -0,0 +1,124 @@
0
+package fakecontext // import "github.com/docker/docker/internal/test/fakecontext"
1
+
2
+import (
3
+	"bytes"
4
+	"io"
5
+	"io/ioutil"
6
+	"os"
7
+	"path/filepath"
8
+
9
+	"github.com/docker/docker/pkg/archive"
10
+)
11
+
12
+type testingT interface {
13
+	Fatal(args ...interface{})
14
+	Fatalf(string, ...interface{})
15
+}
16
+
17
+// New creates a fake build context
18
+func New(t testingT, dir string, modifiers ...func(*Fake) error) *Fake {
19
+	fakeContext := &Fake{Dir: dir}
20
+	if dir == "" {
21
+		if err := newDir(fakeContext); err != nil {
22
+			t.Fatal(err)
23
+		}
24
+	}
25
+
26
+	for _, modifier := range modifiers {
27
+		if err := modifier(fakeContext); err != nil {
28
+			t.Fatal(err)
29
+		}
30
+	}
31
+
32
+	return fakeContext
33
+}
34
+
35
+func newDir(fake *Fake) error {
36
+	tmp, err := ioutil.TempDir("", "fake-context")
37
+	if err != nil {
38
+		return err
39
+	}
40
+	if err := os.Chmod(tmp, 0755); err != nil {
41
+		return err
42
+	}
43
+	fake.Dir = tmp
44
+	return nil
45
+}
46
+
47
+// WithFile adds the specified file (with content) in the build context
48
+func WithFile(name, content string) func(*Fake) error {
49
+	return func(ctx *Fake) error {
50
+		return ctx.Add(name, content)
51
+	}
52
+}
53
+
54
+// WithDockerfile adds the specified content as Dockerfile in the build context
55
+func WithDockerfile(content string) func(*Fake) error {
56
+	return WithFile("Dockerfile", content)
57
+}
58
+
59
+// WithFiles adds the specified files in the build context, content is a string
60
+func WithFiles(files map[string]string) func(*Fake) error {
61
+	return func(fakeContext *Fake) error {
62
+		for file, content := range files {
63
+			if err := fakeContext.Add(file, content); err != nil {
64
+				return err
65
+			}
66
+		}
67
+		return nil
68
+	}
69
+}
70
+
71
+// WithBinaryFiles adds the specified files in the build context, content is binary
72
+func WithBinaryFiles(files map[string]*bytes.Buffer) func(*Fake) error {
73
+	return func(fakeContext *Fake) error {
74
+		for file, content := range files {
75
+			if err := fakeContext.Add(file, content.String()); err != nil {
76
+				return err
77
+			}
78
+		}
79
+		return nil
80
+	}
81
+}
82
+
83
+// Fake creates directories that can be used as a build context
84
+type Fake struct {
85
+	Dir string
86
+}
87
+
88
+// Add a file at a path, creating directories where necessary
89
+func (f *Fake) Add(file, content string) error {
90
+	return f.addFile(file, []byte(content))
91
+}
92
+
93
+func (f *Fake) addFile(file string, content []byte) error {
94
+	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
95
+	dirpath := filepath.Dir(fp)
96
+	if dirpath != "." {
97
+		if err := os.MkdirAll(dirpath, 0755); err != nil {
98
+			return err
99
+		}
100
+	}
101
+	return ioutil.WriteFile(fp, content, 0644)
102
+
103
+}
104
+
105
+// Delete a file at a path
106
+func (f *Fake) Delete(file string) error {
107
+	fp := filepath.Join(f.Dir, filepath.FromSlash(file))
108
+	return os.RemoveAll(fp)
109
+}
110
+
111
+// Close deletes the context
112
+func (f *Fake) Close() error {
113
+	return os.RemoveAll(f.Dir)
114
+}
115
+
116
+// AsTarReader returns a ReadCloser with the contents of Dir as a tar archive.
117
+func (f *Fake) AsTarReader(t testingT) io.ReadCloser {
118
+	reader, err := archive.TarWithOptions(f.Dir, &archive.TarOptions{})
119
+	if err != nil {
120
+		t.Fatalf("Failed to create tar from %s: %s", f.Dir, err)
121
+	}
122
+	return reader
123
+}
0 124
new file mode 100644
... ...
@@ -0,0 +1,132 @@
0
+package fakegit // import "github.com/docker/docker/internal/test/fakegit"
1
+
2
+import (
3
+	"fmt"
4
+	"io/ioutil"
5
+	"net/http"
6
+	"net/http/httptest"
7
+	"os"
8
+	"os/exec"
9
+	"path/filepath"
10
+
11
+	"github.com/docker/docker/internal/test/fakecontext"
12
+	"github.com/docker/docker/internal/test/fakestorage"
13
+	"github.com/gotestyourself/gotestyourself/assert"
14
+)
15
+
16
+type testingT interface {
17
+	assert.TestingT
18
+	logT
19
+	skipT
20
+	Fatal(args ...interface{})
21
+	Fatalf(string, ...interface{})
22
+}
23
+
24
+type logT interface {
25
+	Logf(string, ...interface{})
26
+}
27
+
28
+type skipT interface {
29
+	Skip(reason string)
30
+}
31
+
32
+type gitServer interface {
33
+	URL() string
34
+	Close() error
35
+}
36
+
37
+type localGitServer struct {
38
+	*httptest.Server
39
+}
40
+
41
+func (r *localGitServer) Close() error {
42
+	r.Server.Close()
43
+	return nil
44
+}
45
+
46
+func (r *localGitServer) URL() string {
47
+	return r.Server.URL
48
+}
49
+
50
+// FakeGit is a fake git server
51
+type FakeGit struct {
52
+	root    string
53
+	server  gitServer
54
+	RepoURL string
55
+}
56
+
57
+// Close closes the server, implements Closer interface
58
+func (g *FakeGit) Close() {
59
+	g.server.Close()
60
+	os.RemoveAll(g.root)
61
+}
62
+
63
+// New create a fake git server that can be used for git related tests
64
+func New(c testingT, name string, files map[string]string, enforceLocalServer bool) *FakeGit {
65
+	ctx := fakecontext.New(c, "", fakecontext.WithFiles(files))
66
+	defer ctx.Close()
67
+	curdir, err := os.Getwd()
68
+	if err != nil {
69
+		c.Fatal(err)
70
+	}
71
+	defer os.Chdir(curdir)
72
+
73
+	if output, err := exec.Command("git", "init", ctx.Dir).CombinedOutput(); err != nil {
74
+		c.Fatalf("error trying to init repo: %s (%s)", err, output)
75
+	}
76
+	err = os.Chdir(ctx.Dir)
77
+	if err != nil {
78
+		c.Fatal(err)
79
+	}
80
+	if output, err := exec.Command("git", "config", "user.name", "Fake User").CombinedOutput(); err != nil {
81
+		c.Fatalf("error trying to set 'user.name': %s (%s)", err, output)
82
+	}
83
+	if output, err := exec.Command("git", "config", "user.email", "fake.user@example.com").CombinedOutput(); err != nil {
84
+		c.Fatalf("error trying to set 'user.email': %s (%s)", err, output)
85
+	}
86
+	if output, err := exec.Command("git", "add", "*").CombinedOutput(); err != nil {
87
+		c.Fatalf("error trying to add files to repo: %s (%s)", err, output)
88
+	}
89
+	if output, err := exec.Command("git", "commit", "-a", "-m", "Initial commit").CombinedOutput(); err != nil {
90
+		c.Fatalf("error trying to commit to repo: %s (%s)", err, output)
91
+	}
92
+
93
+	root, err := ioutil.TempDir("", "docker-test-git-repo")
94
+	if err != nil {
95
+		c.Fatal(err)
96
+	}
97
+	repoPath := filepath.Join(root, name+".git")
98
+	if output, err := exec.Command("git", "clone", "--bare", ctx.Dir, repoPath).CombinedOutput(); err != nil {
99
+		os.RemoveAll(root)
100
+		c.Fatalf("error trying to clone --bare: %s (%s)", err, output)
101
+	}
102
+	err = os.Chdir(repoPath)
103
+	if err != nil {
104
+		os.RemoveAll(root)
105
+		c.Fatal(err)
106
+	}
107
+	if output, err := exec.Command("git", "update-server-info").CombinedOutput(); err != nil {
108
+		os.RemoveAll(root)
109
+		c.Fatalf("error trying to git update-server-info: %s (%s)", err, output)
110
+	}
111
+	err = os.Chdir(curdir)
112
+	if err != nil {
113
+		os.RemoveAll(root)
114
+		c.Fatal(err)
115
+	}
116
+
117
+	var server gitServer
118
+	if !enforceLocalServer {
119
+		// use fakeStorage server, which might be local or remote (at test daemon)
120
+		server = fakestorage.New(c, root)
121
+	} else {
122
+		// always start a local http server on CLI test machine
123
+		httpServer := httptest.NewServer(http.FileServer(http.Dir(root)))
124
+		server = &localGitServer{httpServer}
125
+	}
126
+	return &FakeGit{
127
+		root:    root,
128
+		server:  server,
129
+		RepoURL: fmt.Sprintf("%s/%s.git", server.URL(), name),
130
+	}
131
+}
0 132
new file mode 100644
... ...
@@ -0,0 +1,88 @@
0
+package fakestorage // import "github.com/docker/docker/internal/test/fakestorage"
1
+
2
+import (
3
+	"context"
4
+	"io"
5
+	"io/ioutil"
6
+	"os"
7
+	"os/exec"
8
+	"path/filepath"
9
+	"sync"
10
+
11
+	"github.com/docker/docker/api/types"
12
+	"github.com/docker/docker/pkg/archive"
13
+	"github.com/gotestyourself/gotestyourself/assert"
14
+)
15
+
16
+var ensureHTTPServerOnce sync.Once
17
+
18
+func ensureHTTPServerImage(t testingT) {
19
+	var doIt bool
20
+	ensureHTTPServerOnce.Do(func() {
21
+		doIt = true
22
+	})
23
+
24
+	if !doIt {
25
+		return
26
+	}
27
+
28
+	defer testEnv.ProtectImage(t, "httpserver:latest")
29
+
30
+	tmp, err := ioutil.TempDir("", "docker-http-server-test")
31
+	if err != nil {
32
+		t.Fatalf("could not build http server: %v", err)
33
+	}
34
+	defer os.RemoveAll(tmp)
35
+
36
+	goos := testEnv.OSType
37
+	if goos == "" {
38
+		goos = "linux"
39
+	}
40
+	goarch := os.Getenv("DOCKER_ENGINE_GOARCH")
41
+	if goarch == "" {
42
+		goarch = "amd64"
43
+	}
44
+
45
+	cpCmd, lookErr := exec.LookPath("cp")
46
+	if lookErr != nil {
47
+		t.Fatalf("could not build http server: %v", lookErr)
48
+	}
49
+
50
+	if _, err = os.Stat("../contrib/httpserver/httpserver"); os.IsNotExist(err) {
51
+		goCmd, lookErr := exec.LookPath("go")
52
+		if lookErr != nil {
53
+			t.Fatalf("could not build http server: %v", lookErr)
54
+		}
55
+
56
+		cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver")
57
+		cmd.Env = append(os.Environ(), []string{
58
+			"CGO_ENABLED=0",
59
+			"GOOS=" + goos,
60
+			"GOARCH=" + goarch,
61
+		}...)
62
+		var out []byte
63
+		if out, err = cmd.CombinedOutput(); err != nil {
64
+			t.Fatalf("could not build http server: %s", string(out))
65
+		}
66
+	} else {
67
+		if out, err := exec.Command(cpCmd, "../contrib/httpserver/httpserver", filepath.Join(tmp, "httpserver")).CombinedOutput(); err != nil {
68
+			t.Fatalf("could not copy http server: %v", string(out))
69
+		}
70
+	}
71
+
72
+	if out, err := exec.Command(cpCmd, "../contrib/httpserver/Dockerfile", filepath.Join(tmp, "Dockerfile")).CombinedOutput(); err != nil {
73
+		t.Fatalf("could not build http server: %v", string(out))
74
+	}
75
+
76
+	c := testEnv.APIClient()
77
+	reader, err := archive.TarWithOptions(tmp, &archive.TarOptions{})
78
+	assert.NilError(t, err)
79
+	resp, err := c.ImageBuild(context.Background(), reader, types.ImageBuildOptions{
80
+		Remove:      true,
81
+		ForceRemove: true,
82
+		Tags:        []string{"httpserver"},
83
+	})
84
+	assert.NilError(t, err)
85
+	_, err = io.Copy(ioutil.Discard, resp.Body)
86
+	assert.NilError(t, err)
87
+}
0 88
new file mode 100644
... ...
@@ -0,0 +1,196 @@
0
+package fakestorage // import "github.com/docker/docker/internal/test/fakestorage"
1
+
2
+import (
3
+	"context"
4
+	"fmt"
5
+	"io"
6
+	"io/ioutil"
7
+	"net/http"
8
+	"net/http/httptest"
9
+	"net/url"
10
+	"os"
11
+	"strings"
12
+
13
+	"github.com/docker/docker/api/types"
14
+	containertypes "github.com/docker/docker/api/types/container"
15
+	"github.com/docker/docker/client"
16
+	"github.com/docker/docker/integration-cli/request"
17
+	"github.com/docker/docker/internal/test/environment"
18
+	"github.com/docker/docker/internal/test/fakecontext"
19
+	"github.com/docker/docker/internal/testutil"
20
+	"github.com/docker/go-connections/nat"
21
+	"github.com/gotestyourself/gotestyourself/assert"
22
+)
23
+
24
+var testEnv *environment.Execution
25
+
26
+type testingT interface {
27
+	assert.TestingT
28
+	logT
29
+	skipT
30
+	Fatal(args ...interface{})
31
+	Fatalf(string, ...interface{})
32
+}
33
+
34
+type logT interface {
35
+	Logf(string, ...interface{})
36
+}
37
+
38
+type skipT interface {
39
+	Skip(reason string)
40
+}
41
+
42
+// Fake is a static file server. It might be running locally or remotely
43
+// on test host.
44
+type Fake interface {
45
+	Close() error
46
+	URL() string
47
+	CtxDir() string
48
+}
49
+
50
+// SetTestEnvironment sets a static test environment
51
+// TODO: decouple this package from environment
52
+func SetTestEnvironment(env *environment.Execution) {
53
+	testEnv = env
54
+}
55
+
56
+// New returns a static file server that will be use as build context.
57
+func New(t testingT, dir string, modifiers ...func(*fakecontext.Fake) error) Fake {
58
+	if testEnv == nil {
59
+		t.Fatal("fakstorage package requires SetTestEnvironment() to be called before use.")
60
+	}
61
+	ctx := fakecontext.New(t, dir, modifiers...)
62
+	switch {
63
+	case testEnv.IsRemoteDaemon() && strings.HasPrefix(request.DaemonHost(), "unix:///"):
64
+		t.Skip(fmt.Sprintf("e2e run : daemon is remote but docker host points to a unix socket"))
65
+	case testEnv.IsLocalDaemon():
66
+		return newLocalFakeStorage(ctx)
67
+	default:
68
+		return newRemoteFileServer(t, ctx, testEnv.APIClient())
69
+	}
70
+	return nil
71
+}
72
+
73
+// localFileStorage is a file storage on the running machine
74
+type localFileStorage struct {
75
+	*fakecontext.Fake
76
+	*httptest.Server
77
+}
78
+
79
+func (s *localFileStorage) URL() string {
80
+	return s.Server.URL
81
+}
82
+
83
+func (s *localFileStorage) CtxDir() string {
84
+	return s.Fake.Dir
85
+}
86
+
87
+func (s *localFileStorage) Close() error {
88
+	defer s.Server.Close()
89
+	return s.Fake.Close()
90
+}
91
+
92
+func newLocalFakeStorage(ctx *fakecontext.Fake) *localFileStorage {
93
+	handler := http.FileServer(http.Dir(ctx.Dir))
94
+	server := httptest.NewServer(handler)
95
+	return &localFileStorage{
96
+		Fake:   ctx,
97
+		Server: server,
98
+	}
99
+}
100
+
101
+// remoteFileServer is a containerized static file server started on the remote
102
+// testing machine to be used in URL-accepting docker build functionality.
103
+type remoteFileServer struct {
104
+	host      string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712
105
+	container string
106
+	image     string
107
+	client    client.APIClient
108
+	ctx       *fakecontext.Fake
109
+}
110
+
111
+func (f *remoteFileServer) URL() string {
112
+	u := url.URL{
113
+		Scheme: "http",
114
+		Host:   f.host}
115
+	return u.String()
116
+}
117
+
118
+func (f *remoteFileServer) CtxDir() string {
119
+	return f.ctx.Dir
120
+}
121
+
122
+func (f *remoteFileServer) Close() error {
123
+	defer func() {
124
+		if f.ctx != nil {
125
+			f.ctx.Close()
126
+		}
127
+		if f.image != "" {
128
+			if _, err := f.client.ImageRemove(context.Background(), f.image, types.ImageRemoveOptions{
129
+				Force: true,
130
+			}); err != nil {
131
+				fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err)
132
+			}
133
+		}
134
+		if err := f.client.Close(); err != nil {
135
+			fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err)
136
+		}
137
+	}()
138
+	if f.container == "" {
139
+		return nil
140
+	}
141
+	return f.client.ContainerRemove(context.Background(), f.container, types.ContainerRemoveOptions{
142
+		Force:         true,
143
+		RemoveVolumes: true,
144
+	})
145
+}
146
+
147
+func newRemoteFileServer(t testingT, ctx *fakecontext.Fake, c client.APIClient) *remoteFileServer {
148
+	var (
149
+		image     = fmt.Sprintf("fileserver-img-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10)))
150
+		container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10)))
151
+	)
152
+
153
+	ensureHTTPServerImage(t)
154
+
155
+	// Build the image
156
+	if err := ctx.Add("Dockerfile", `FROM httpserver
157
+COPY . /static`); err != nil {
158
+		t.Fatal(err)
159
+	}
160
+	resp, err := c.ImageBuild(context.Background(), ctx.AsTarReader(t), types.ImageBuildOptions{
161
+		NoCache: true,
162
+		Tags:    []string{image},
163
+	})
164
+	assert.NilError(t, err)
165
+	_, err = io.Copy(ioutil.Discard, resp.Body)
166
+	assert.NilError(t, err)
167
+
168
+	// Start the container
169
+	b, err := c.ContainerCreate(context.Background(), &containertypes.Config{
170
+		Image: image,
171
+	}, &containertypes.HostConfig{}, nil, container)
172
+	assert.NilError(t, err)
173
+	err = c.ContainerStart(context.Background(), b.ID, types.ContainerStartOptions{})
174
+	assert.NilError(t, err)
175
+
176
+	// Find out the system assigned port
177
+	i, err := c.ContainerInspect(context.Background(), b.ID)
178
+	assert.NilError(t, err)
179
+	newP, err := nat.NewPort("tcp", "80")
180
+	assert.NilError(t, err)
181
+	ports, exists := i.NetworkSettings.Ports[newP]
182
+	if !exists || len(ports) != 1 {
183
+		t.Fatalf("unable to find port 80/tcp for %s", container)
184
+	}
185
+	host := ports[0].HostIP
186
+	port := ports[0].HostPort
187
+
188
+	return &remoteFileServer{
189
+		container: container,
190
+		image:     image,
191
+		host:      fmt.Sprintf("%s:%s", host, port),
192
+		ctx:       ctx,
193
+		client:    c,
194
+	}
195
+}