github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/internal/test/fakestorage/storage.go (about)

     1  package fakestorage // import "github.com/docker/docker/internal/test/fakestorage"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"net/http/httptest"
    10  	"net/url"
    11  	"os"
    12  	"strings"
    13  
    14  	"github.com/docker/docker/api/types"
    15  	containertypes "github.com/docker/docker/api/types/container"
    16  	"github.com/docker/docker/client"
    17  	"github.com/docker/docker/integration-cli/request"
    18  	"github.com/docker/docker/internal/test/environment"
    19  	"github.com/docker/docker/internal/test/fakecontext"
    20  	"github.com/docker/docker/internal/testutil"
    21  	"github.com/docker/go-connections/nat"
    22  	"github.com/gotestyourself/gotestyourself/assert"
    23  )
    24  
    25  var testEnv *environment.Execution
    26  
    27  type testingT interface {
    28  	assert.TestingT
    29  	logT
    30  	skipT
    31  	Fatal(args ...interface{})
    32  	Fatalf(string, ...interface{})
    33  }
    34  
    35  type logT interface {
    36  	Logf(string, ...interface{})
    37  }
    38  
    39  type skipT interface {
    40  	Skip(reason string)
    41  }
    42  
    43  // Fake is a static file server. It might be running locally or remotely
    44  // on test host.
    45  type Fake interface {
    46  	Close() error
    47  	URL() string
    48  	CtxDir() string
    49  }
    50  
    51  // SetTestEnvironment sets a static test environment
    52  // TODO: decouple this package from environment
    53  func SetTestEnvironment(env *environment.Execution) {
    54  	testEnv = env
    55  }
    56  
    57  // New returns a static file server that will be use as build context.
    58  func New(t testingT, dir string, modifiers ...func(*fakecontext.Fake) error) Fake {
    59  	if testEnv == nil {
    60  		t.Fatal("fakstorage package requires SetTestEnvironment() to be called before use.")
    61  	}
    62  	ctx := fakecontext.New(t, dir, modifiers...)
    63  	switch {
    64  	case testEnv.IsRemoteDaemon() && strings.HasPrefix(request.DaemonHost(), "unix:///"):
    65  		t.Skip(fmt.Sprintf("e2e run : daemon is remote but docker host points to a unix socket"))
    66  	case testEnv.IsLocalDaemon():
    67  		return newLocalFakeStorage(ctx)
    68  	default:
    69  		return newRemoteFileServer(t, ctx, testEnv.APIClient())
    70  	}
    71  	return nil
    72  }
    73  
    74  // localFileStorage is a file storage on the running machine
    75  type localFileStorage struct {
    76  	*fakecontext.Fake
    77  	*httptest.Server
    78  }
    79  
    80  func (s *localFileStorage) URL() string {
    81  	return s.Server.URL
    82  }
    83  
    84  func (s *localFileStorage) CtxDir() string {
    85  	return s.Fake.Dir
    86  }
    87  
    88  func (s *localFileStorage) Close() error {
    89  	defer s.Server.Close()
    90  	return s.Fake.Close()
    91  }
    92  
    93  func newLocalFakeStorage(ctx *fakecontext.Fake) *localFileStorage {
    94  	handler := http.FileServer(http.Dir(ctx.Dir))
    95  	server := httptest.NewServer(handler)
    96  	return &localFileStorage{
    97  		Fake:   ctx,
    98  		Server: server,
    99  	}
   100  }
   101  
   102  // remoteFileServer is a containerized static file server started on the remote
   103  // testing machine to be used in URL-accepting docker build functionality.
   104  type remoteFileServer struct {
   105  	host      string // hostname/port web server is listening to on docker host e.g. 0.0.0.0:43712
   106  	container string
   107  	image     string
   108  	client    client.APIClient
   109  	ctx       *fakecontext.Fake
   110  }
   111  
   112  func (f *remoteFileServer) URL() string {
   113  	u := url.URL{
   114  		Scheme: "http",
   115  		Host:   f.host}
   116  	return u.String()
   117  }
   118  
   119  func (f *remoteFileServer) CtxDir() string {
   120  	return f.ctx.Dir
   121  }
   122  
   123  func (f *remoteFileServer) Close() error {
   124  	defer func() {
   125  		if f.ctx != nil {
   126  			f.ctx.Close()
   127  		}
   128  		if f.image != "" {
   129  			if _, err := f.client.ImageRemove(context.Background(), f.image, types.ImageRemoveOptions{
   130  				Force: true,
   131  			}); err != nil {
   132  				fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err)
   133  			}
   134  		}
   135  		if err := f.client.Close(); err != nil {
   136  			fmt.Fprintf(os.Stderr, "Error closing remote file server : %v\n", err)
   137  		}
   138  	}()
   139  	if f.container == "" {
   140  		return nil
   141  	}
   142  	return f.client.ContainerRemove(context.Background(), f.container, types.ContainerRemoveOptions{
   143  		Force:         true,
   144  		RemoveVolumes: true,
   145  	})
   146  }
   147  
   148  func newRemoteFileServer(t testingT, ctx *fakecontext.Fake, c client.APIClient) *remoteFileServer {
   149  	var (
   150  		image     = fmt.Sprintf("fileserver-img-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10)))
   151  		container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(testutil.GenerateRandomAlphaOnlyString(10)))
   152  	)
   153  
   154  	ensureHTTPServerImage(t)
   155  
   156  	// Build the image
   157  	if err := ctx.Add("Dockerfile", `FROM httpserver
   158  COPY . /static`); err != nil {
   159  		t.Fatal(err)
   160  	}
   161  	resp, err := c.ImageBuild(context.Background(), ctx.AsTarReader(t), types.ImageBuildOptions{
   162  		NoCache: true,
   163  		Tags:    []string{image},
   164  	})
   165  	assert.NilError(t, err)
   166  	_, err = io.Copy(ioutil.Discard, resp.Body)
   167  	assert.NilError(t, err)
   168  
   169  	// Start the container
   170  	b, err := c.ContainerCreate(context.Background(), &containertypes.Config{
   171  		Image: image,
   172  	}, &containertypes.HostConfig{}, nil, container)
   173  	assert.NilError(t, err)
   174  	err = c.ContainerStart(context.Background(), b.ID, types.ContainerStartOptions{})
   175  	assert.NilError(t, err)
   176  
   177  	// Find out the system assigned port
   178  	i, err := c.ContainerInspect(context.Background(), b.ID)
   179  	assert.NilError(t, err)
   180  	newP, err := nat.NewPort("tcp", "80")
   181  	assert.NilError(t, err)
   182  	ports, exists := i.NetworkSettings.Ports[newP]
   183  	if !exists || len(ports) != 1 {
   184  		t.Fatalf("unable to find port 80/tcp for %s", container)
   185  	}
   186  	host := ports[0].HostIP
   187  	port := ports[0].HostPort
   188  
   189  	return &remoteFileServer{
   190  		container: container,
   191  		image:     image,
   192  		host:      fmt.Sprintf("%s:%s", host, port),
   193  		ctx:       ctx,
   194  		client:    c,
   195  	}
   196  }