Signed-off-by: Vincent Demeester <vincent@sbr.pm>
| ... | ... |
@@ -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" |
| 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 |
+} |