github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/e2e/integration_test.go (about)

     1  // Copyright 2018 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package integration provides end-to-end integration tests for runsc.
    16  //
    17  // Each test calls docker commands to start up a container, and tests that it is
    18  // behaving properly, with various runsc commands. The container is killed and
    19  // deleted at the end.
    20  //
    21  // Setup instruction in test/README.md.
    22  package integration
    23  
    24  import (
    25  	"context"
    26  	"flag"
    27  	"fmt"
    28  	"io/ioutil"
    29  	"net"
    30  	"net/http"
    31  	"os"
    32  	"path/filepath"
    33  	"strconv"
    34  	"strings"
    35  	"testing"
    36  	"time"
    37  
    38  	"github.com/docker/docker/api/types/mount"
    39  	"github.com/SagerNet/gvisor/pkg/test/dockerutil"
    40  	"github.com/SagerNet/gvisor/pkg/test/testutil"
    41  )
    42  
    43  // defaultWait is the default wait time used for tests.
    44  const defaultWait = time.Minute
    45  
    46  // httpRequestSucceeds sends a request to a given url and checks that the status is OK.
    47  func httpRequestSucceeds(client http.Client, server string, port int) error {
    48  	url := fmt.Sprintf("http://%s:%d", server, port)
    49  	// Ensure that content is being served.
    50  	resp, err := client.Get(url)
    51  	if err != nil {
    52  		return fmt.Errorf("error reaching http server: %v", err)
    53  	}
    54  	if want := http.StatusOK; resp.StatusCode != want {
    55  		return fmt.Errorf("wrong response code, got: %d, want: %d", resp.StatusCode, want)
    56  	}
    57  	return nil
    58  }
    59  
    60  // TestLifeCycle tests a basic Create/Start/Stop docker container life cycle.
    61  func TestLifeCycle(t *testing.T) {
    62  	ctx := context.Background()
    63  	d := dockerutil.MakeContainer(ctx, t)
    64  	defer d.CleanUp(ctx)
    65  
    66  	// Start the container.
    67  	port := 80
    68  	if err := d.Create(ctx, dockerutil.RunOpts{
    69  		Image: "basic/nginx",
    70  		Ports: []int{port},
    71  	}); err != nil {
    72  		t.Fatalf("docker create failed: %v", err)
    73  	}
    74  	if err := d.Start(ctx); err != nil {
    75  		t.Fatalf("docker start failed: %v", err)
    76  	}
    77  
    78  	ip, err := d.FindIP(ctx, false)
    79  	if err != nil {
    80  		t.Fatalf("docker.FindIP failed: %v", err)
    81  	}
    82  	if err := testutil.WaitForHTTP(ip.String(), port, defaultWait); err != nil {
    83  		t.Fatalf("WaitForHTTP() timeout: %v", err)
    84  	}
    85  	client := http.Client{Timeout: defaultWait}
    86  	if err := httpRequestSucceeds(client, ip.String(), port); err != nil {
    87  		t.Errorf("http request failed: %v", err)
    88  	}
    89  
    90  	if err := d.Stop(ctx); err != nil {
    91  		t.Fatalf("docker stop failed: %v", err)
    92  	}
    93  	if err := d.Remove(ctx); err != nil {
    94  		t.Fatalf("docker rm failed: %v", err)
    95  	}
    96  }
    97  
    98  func TestPauseResume(t *testing.T) {
    99  	if !testutil.IsCheckpointSupported() {
   100  		t.Skip("Checkpoint is not supported.")
   101  	}
   102  
   103  	ctx := context.Background()
   104  	d := dockerutil.MakeContainer(ctx, t)
   105  	defer d.CleanUp(ctx)
   106  
   107  	// Start the container.
   108  	port := 8080
   109  	if err := d.Spawn(ctx, dockerutil.RunOpts{
   110  		Image: "basic/python",
   111  		Ports: []int{port}, // See Dockerfile.
   112  	}); err != nil {
   113  		t.Fatalf("docker run failed: %v", err)
   114  	}
   115  
   116  	// Find container IP address.
   117  	ip, err := d.FindIP(ctx, false)
   118  	if err != nil {
   119  		t.Fatalf("docker.FindIP failed: %v", err)
   120  	}
   121  
   122  	// Wait until it's up and running.
   123  	if err := testutil.WaitForHTTP(ip.String(), port, defaultWait); err != nil {
   124  		t.Fatalf("WaitForHTTP() timeout: %v", err)
   125  	}
   126  
   127  	// Check that container is working.
   128  	client := http.Client{Timeout: defaultWait}
   129  	if err := httpRequestSucceeds(client, ip.String(), port); err != nil {
   130  		t.Error("http request failed:", err)
   131  	}
   132  
   133  	if err := d.Pause(ctx); err != nil {
   134  		t.Fatalf("docker pause failed: %v", err)
   135  	}
   136  
   137  	// Check if container is paused.
   138  	client = http.Client{Timeout: 10 * time.Millisecond} // Don't wait a minute.
   139  	switch _, err := client.Get(fmt.Sprintf("http://%s:%d", ip.String(), port)); v := err.(type) {
   140  	case nil:
   141  		t.Errorf("http req expected to fail but it succeeded")
   142  	case net.Error:
   143  		if !v.Timeout() {
   144  			t.Errorf("http req got error %v, wanted timeout", v)
   145  		}
   146  	default:
   147  		t.Errorf("http req got unexpected error %v", v)
   148  	}
   149  
   150  	if err := d.Unpause(ctx); err != nil {
   151  		t.Fatalf("docker unpause failed: %v", err)
   152  	}
   153  
   154  	// Wait until it's up and running.
   155  	if err := testutil.WaitForHTTP(ip.String(), port, defaultWait); err != nil {
   156  		t.Fatalf("WaitForHTTP() timeout: %v", err)
   157  	}
   158  
   159  	// Check if container is working again.
   160  	client = http.Client{Timeout: defaultWait}
   161  	if err := httpRequestSucceeds(client, ip.String(), port); err != nil {
   162  		t.Error("http request failed:", err)
   163  	}
   164  }
   165  
   166  func TestCheckpointRestore(t *testing.T) {
   167  	if !testutil.IsCheckpointSupported() {
   168  		t.Skip("Pause/resume is not supported.")
   169  	}
   170  
   171  	ctx := context.Background()
   172  	d := dockerutil.MakeContainer(ctx, t)
   173  	defer d.CleanUp(ctx)
   174  
   175  	// Start the container.
   176  	port := 8080
   177  	if err := d.Spawn(ctx, dockerutil.RunOpts{
   178  		Image: "basic/python",
   179  		Ports: []int{port}, // See Dockerfile.
   180  	}); err != nil {
   181  		t.Fatalf("docker run failed: %v", err)
   182  	}
   183  
   184  	// Create a snapshot.
   185  	if err := d.Checkpoint(ctx, "test"); err != nil {
   186  		t.Fatalf("docker checkpoint failed: %v", err)
   187  	}
   188  	if err := d.WaitTimeout(ctx, defaultWait); err != nil {
   189  		t.Fatalf("wait failed: %v", err)
   190  	}
   191  
   192  	// TODO(b/143498576): Remove Poll after github.com/moby/moby/issues/38963 is fixed.
   193  	if err := testutil.Poll(func() error { return d.Restore(ctx, "test") }, defaultWait); err != nil {
   194  		t.Fatalf("docker restore failed: %v", err)
   195  	}
   196  
   197  	// Find container IP address.
   198  	ip, err := d.FindIP(ctx, false)
   199  	if err != nil {
   200  		t.Fatalf("docker.FindIP failed: %v", err)
   201  	}
   202  
   203  	// Wait until it's up and running.
   204  	if err := testutil.WaitForHTTP(ip.String(), port, defaultWait); err != nil {
   205  		t.Fatalf("WaitForHTTP() timeout: %v", err)
   206  	}
   207  
   208  	// Check if container is working again.
   209  	client := http.Client{Timeout: defaultWait}
   210  	if err := httpRequestSucceeds(client, ip.String(), port); err != nil {
   211  		t.Error("http request failed:", err)
   212  	}
   213  }
   214  
   215  // Create client and server that talk to each other using the local IP.
   216  func TestConnectToSelf(t *testing.T) {
   217  	ctx := context.Background()
   218  	d := dockerutil.MakeContainer(ctx, t)
   219  	defer d.CleanUp(ctx)
   220  
   221  	// Creates server that replies "server" and exists. Sleeps at the end because
   222  	// 'docker exec' gets killed if the init process exists before it can finish.
   223  	if err := d.Spawn(ctx, dockerutil.RunOpts{
   224  		Image: "basic/ubuntu",
   225  	}, "/bin/sh", "-c", "echo server | nc -l -p 8080 && sleep 1"); err != nil {
   226  		t.Fatalf("docker run failed: %v", err)
   227  	}
   228  
   229  	// Finds IP address for host.
   230  	ip, err := d.Exec(ctx, dockerutil.ExecOpts{}, "/bin/sh", "-c", "cat /etc/hosts | grep ${HOSTNAME} | awk '{print $1}'")
   231  	if err != nil {
   232  		t.Fatalf("docker exec failed: %v", err)
   233  	}
   234  	ip = strings.TrimRight(ip, "\n")
   235  
   236  	// Runs client that sends "client" to the server and exits.
   237  	reply, err := d.Exec(ctx, dockerutil.ExecOpts{}, "/bin/sh", "-c", fmt.Sprintf("echo client | nc %s 8080", ip))
   238  	if err != nil {
   239  		t.Fatalf("docker exec failed: %v", err)
   240  	}
   241  
   242  	// Ensure both client and server got the message from each other.
   243  	if want := "server\n"; reply != want {
   244  		t.Errorf("Error on server, want: %q, got: %q", want, reply)
   245  	}
   246  	if _, err := d.WaitForOutput(ctx, "^client\n$", defaultWait); err != nil {
   247  		t.Fatalf("docker.WaitForOutput(client) timeout: %v", err)
   248  	}
   249  }
   250  
   251  func TestMemLimit(t *testing.T) {
   252  	ctx := context.Background()
   253  	d := dockerutil.MakeContainer(ctx, t)
   254  	defer d.CleanUp(ctx)
   255  
   256  	allocMemoryKb := 50 * 1024
   257  	out, err := d.Run(ctx, dockerutil.RunOpts{
   258  		Image:  "basic/alpine",
   259  		Memory: allocMemoryKb * 1024, // In bytes.
   260  	}, "sh", "-c", "cat /proc/meminfo | grep MemTotal: | awk '{print $2}'")
   261  	if err != nil {
   262  		t.Fatalf("docker run failed: %v", err)
   263  	}
   264  
   265  	// Remove warning message that swap isn't present.
   266  	if strings.HasPrefix(out, "WARNING") {
   267  		lines := strings.Split(out, "\n")
   268  		if len(lines) != 3 {
   269  			t.Fatalf("invalid output: %s", out)
   270  		}
   271  		out = lines[1]
   272  	}
   273  
   274  	// Ensure the memory matches what we want.
   275  	got, err := strconv.ParseUint(strings.TrimSpace(out), 10, 64)
   276  	if err != nil {
   277  		t.Fatalf("failed to parse %q: %v", out, err)
   278  	}
   279  	if want := uint64(allocMemoryKb); got != want {
   280  		t.Errorf("MemTotal got: %d, want: %d", got, want)
   281  	}
   282  }
   283  
   284  func TestNumCPU(t *testing.T) {
   285  	ctx := context.Background()
   286  	d := dockerutil.MakeContainer(ctx, t)
   287  	defer d.CleanUp(ctx)
   288  
   289  	// Read how many cores are in the container.
   290  	out, err := d.Run(ctx, dockerutil.RunOpts{
   291  		Image:      "basic/alpine",
   292  		CpusetCpus: "0",
   293  	}, "sh", "-c", "cat /proc/cpuinfo | grep 'processor.*:' | wc -l")
   294  	if err != nil {
   295  		t.Fatalf("docker run failed: %v", err)
   296  	}
   297  
   298  	// Ensure it matches what we want.
   299  	got, err := strconv.Atoi(strings.TrimSpace(out))
   300  	if err != nil {
   301  		t.Fatalf("failed to parse %q: %v", out, err)
   302  	}
   303  	if want := 1; got != want {
   304  		t.Errorf("MemTotal got: %d, want: %d", got, want)
   305  	}
   306  }
   307  
   308  // TestJobControl tests that job control characters are handled properly.
   309  func TestJobControl(t *testing.T) {
   310  	ctx := context.Background()
   311  	d := dockerutil.MakeContainer(ctx, t)
   312  	defer d.CleanUp(ctx)
   313  
   314  	// Start the container with an attached PTY.
   315  	p, err := d.SpawnProcess(ctx, dockerutil.RunOpts{
   316  		Image: "basic/alpine",
   317  	}, "sh", "-c", "sleep 100 | cat")
   318  	if err != nil {
   319  		t.Fatalf("docker run failed: %v", err)
   320  	}
   321  	// Give shell a few seconds to start executing the sleep.
   322  	time.Sleep(2 * time.Second)
   323  
   324  	if _, err := p.Write(time.Second, []byte{0x03}); err != nil {
   325  		t.Fatalf("error exit: %v", err)
   326  	}
   327  
   328  	if err := d.WaitTimeout(ctx, 3*time.Second); err != nil {
   329  		t.Fatalf("WaitTimeout failed: %v", err)
   330  	}
   331  
   332  	want := 130
   333  	got, err := p.WaitExitStatus(ctx)
   334  	if err != nil {
   335  		t.Fatalf("wait for exit failed with: %v", err)
   336  	} else if got != want {
   337  		t.Fatalf("got: %d want: %d", got, want)
   338  	}
   339  }
   340  
   341  // TestWorkingDirCreation checks that working dir is created if it doesn't exit.
   342  func TestWorkingDirCreation(t *testing.T) {
   343  	for _, tc := range []struct {
   344  		name       string
   345  		workingDir string
   346  	}{
   347  		{name: "root", workingDir: "/foo"},
   348  		{name: "tmp", workingDir: "/tmp/foo"},
   349  	} {
   350  		for _, readonly := range []bool{true, false} {
   351  			name := tc.name
   352  			if readonly {
   353  				name += "-readonly"
   354  			}
   355  			t.Run(name, func(t *testing.T) {
   356  				ctx := context.Background()
   357  				d := dockerutil.MakeContainer(ctx, t)
   358  				defer d.CleanUp(ctx)
   359  
   360  				opts := dockerutil.RunOpts{
   361  					Image:    "basic/alpine",
   362  					WorkDir:  tc.workingDir,
   363  					ReadOnly: readonly,
   364  				}
   365  				got, err := d.Run(ctx, opts, "sh", "-c", "echo ${PWD}")
   366  				if err != nil {
   367  					t.Fatalf("docker run failed: %v", err)
   368  				}
   369  				if want := tc.workingDir + "\n"; want != got {
   370  					t.Errorf("invalid working dir, want: %q, got: %q", want, got)
   371  				}
   372  			})
   373  		}
   374  	}
   375  }
   376  
   377  // TestTmpFile checks that files inside '/tmp' are not overridden.
   378  func TestTmpFile(t *testing.T) {
   379  	ctx := context.Background()
   380  	d := dockerutil.MakeContainer(ctx, t)
   381  	defer d.CleanUp(ctx)
   382  
   383  	opts := dockerutil.RunOpts{Image: "basic/tmpfile"}
   384  	got, err := d.Run(ctx, opts, "cat", "/tmp/foo/file.txt")
   385  	if err != nil {
   386  		t.Fatalf("docker run failed: %v", err)
   387  	}
   388  	if want := "123\n"; want != got {
   389  		t.Errorf("invalid file content, want: %q, got: %q", want, got)
   390  	}
   391  }
   392  
   393  // TestTmpMount checks that mounts inside '/tmp' are not overridden.
   394  func TestTmpMount(t *testing.T) {
   395  	dir, err := ioutil.TempDir(testutil.TmpDir(), "tmp-mount")
   396  	if err != nil {
   397  		t.Fatalf("TempDir(): %v", err)
   398  	}
   399  	const want = "123"
   400  	if err := ioutil.WriteFile(filepath.Join(dir, "file.txt"), []byte("123"), 0666); err != nil {
   401  		t.Fatalf("WriteFile(): %v", err)
   402  	}
   403  	ctx := context.Background()
   404  	d := dockerutil.MakeContainer(ctx, t)
   405  	defer d.CleanUp(ctx)
   406  
   407  	opts := dockerutil.RunOpts{
   408  		Image: "basic/alpine",
   409  		Mounts: []mount.Mount{
   410  			{
   411  				Type:   mount.TypeBind,
   412  				Source: dir,
   413  				Target: "/tmp/foo",
   414  			},
   415  		},
   416  	}
   417  	got, err := d.Run(ctx, opts, "cat", "/tmp/foo/file.txt")
   418  	if err != nil {
   419  		t.Fatalf("docker run failed: %v", err)
   420  	}
   421  	if want != got {
   422  		t.Errorf("invalid file content, want: %q, got: %q", want, got)
   423  	}
   424  }
   425  
   426  // Test that it is allowed to mount a file on top of /dev files, e.g.
   427  // /dev/random.
   428  func TestMountOverDev(t *testing.T) {
   429  	if usingVFS2, err := dockerutil.UsingVFS2(); !usingVFS2 {
   430  		t.Skip("VFS1 doesn't allow /dev/random to be mounted.")
   431  	} else if err != nil {
   432  		t.Fatalf("Failed to read config for runtime %s: %v", dockerutil.Runtime(), err)
   433  	}
   434  
   435  	random, err := ioutil.TempFile(testutil.TmpDir(), "random")
   436  	if err != nil {
   437  		t.Fatal("ioutil.TempFile() failed:", err)
   438  	}
   439  	const want = "123"
   440  	if _, err := random.WriteString(want); err != nil {
   441  		t.Fatalf("WriteString() to %q: %v", random.Name(), err)
   442  	}
   443  
   444  	ctx := context.Background()
   445  	d := dockerutil.MakeContainer(ctx, t)
   446  	defer d.CleanUp(ctx)
   447  
   448  	opts := dockerutil.RunOpts{
   449  		Image: "basic/alpine",
   450  		Mounts: []mount.Mount{
   451  			{
   452  				Type:   mount.TypeBind,
   453  				Source: random.Name(),
   454  				Target: "/dev/random",
   455  			},
   456  		},
   457  	}
   458  	cmd := "dd count=1 bs=5 if=/dev/random 2> /dev/null"
   459  	got, err := d.Run(ctx, opts, "sh", "-c", cmd)
   460  	if err != nil {
   461  		t.Fatalf("docker run failed: %v", err)
   462  	}
   463  	if want != got {
   464  		t.Errorf("invalid file content, want: %q, got: %q", want, got)
   465  	}
   466  }
   467  
   468  // TestSyntheticDirs checks that submounts can be created inside a readonly
   469  // mount even if the target path does not exist.
   470  func TestSyntheticDirs(t *testing.T) {
   471  	ctx := context.Background()
   472  	d := dockerutil.MakeContainer(ctx, t)
   473  	defer d.CleanUp(ctx)
   474  
   475  	opts := dockerutil.RunOpts{
   476  		Image: "basic/alpine",
   477  		// Make the root read-only to force use of synthetic dirs
   478  		// inside the root gofer mount.
   479  		ReadOnly: true,
   480  		Mounts: []mount.Mount{
   481  			// Mount inside read-only gofer-backed root.
   482  			{
   483  				Type:   mount.TypeTmpfs,
   484  				Target: "/foo/bar/baz",
   485  			},
   486  			// Mount inside sysfs, which always uses synthetic dirs
   487  			// for submounts.
   488  			{
   489  				Type:   mount.TypeTmpfs,
   490  				Target: "/sys/foo/bar/baz",
   491  			},
   492  		},
   493  	}
   494  	// Make sure the directories exist.
   495  	if _, err := d.Run(ctx, opts, "ls", "/foo/bar/baz", "/sys/foo/bar/baz"); err != nil {
   496  		t.Fatalf("docker run failed: %v", err)
   497  	}
   498  
   499  }
   500  
   501  // TestHostOverlayfsCopyUp tests that the --overlayfs-stale-read option causes
   502  // runsc to hide the incoherence of FDs opened before and after overlayfs
   503  // copy-up on the host.
   504  func TestHostOverlayfsCopyUp(t *testing.T) {
   505  	runIntegrationTest(t, nil, "./test_copy_up")
   506  }
   507  
   508  // TestHostOverlayfsRewindDir tests that rewinddir() "causes the directory
   509  // stream to refer to the current state of the corresponding directory, as a
   510  // call to opendir() would have done" as required by POSIX, when the directory
   511  // in question is host overlayfs.
   512  //
   513  // This test specifically targets host overlayfs because, per POSIX, "if a file
   514  // is removed from or added to the directory after the most recent call to
   515  // opendir() or rewinddir(), whether a subsequent call to readdir() returns an
   516  // entry for that file is unspecified"; the host filesystems used by other
   517  // automated tests yield newly-added files from readdir() even if the fsgofer
   518  // does not explicitly rewinddir(), but overlayfs does not.
   519  func TestHostOverlayfsRewindDir(t *testing.T) {
   520  	runIntegrationTest(t, nil, "./test_rewinddir")
   521  }
   522  
   523  // Basic test for linkat(2). Syscall tests requires CAP_DAC_READ_SEARCH and it
   524  // cannot use tricks like userns as root. For this reason, run a basic link test
   525  // to ensure some coverage.
   526  func TestLink(t *testing.T) {
   527  	runIntegrationTest(t, nil, "./link_test")
   528  }
   529  
   530  // This test ensures we can run ping without errors.
   531  func TestPing4Loopback(t *testing.T) {
   532  	if testutil.IsRunningWithHostNet() {
   533  		// TODO(github.com/SagerNet/issue/5011): support ICMP sockets in hostnet and enable
   534  		// this test.
   535  		t.Skip("hostnet only supports TCP/UDP sockets, so ping is not supported.")
   536  	}
   537  
   538  	runIntegrationTest(t, nil, "./ping4.sh")
   539  }
   540  
   541  // This test ensures we can enable ipv6 on loopback and run ping6 without
   542  // errors.
   543  func TestPing6Loopback(t *testing.T) {
   544  	if testutil.IsRunningWithHostNet() {
   545  		// TODO(github.com/SagerNet/issue/5011): support ICMP sockets in hostnet and enable
   546  		// this test.
   547  		t.Skip("hostnet only supports TCP/UDP sockets, so ping6 is not supported.")
   548  	}
   549  
   550  	// The CAP_NET_ADMIN capability is required to use the `ip` utility, which
   551  	// we use to enable ipv6 on loopback.
   552  	//
   553  	// By default, ipv6 loopback is not enabled by runsc, because docker does
   554  	// not assign an ipv6 address to the test container.
   555  	runIntegrationTest(t, []string{"NET_ADMIN"}, "./ping6.sh")
   556  }
   557  
   558  // This test checks that the owner of the sticky directory can delete files
   559  // inside it belonging to other users. It also checks that the owner of a file
   560  // can always delete its file when the file is inside a sticky directory owned
   561  // by another user.
   562  func TestStickyDir(t *testing.T) {
   563  	if vfs2Used, err := dockerutil.UsingVFS2(); err != nil {
   564  		t.Fatalf("failed to read config for runtime %s: %v", dockerutil.Runtime(), err)
   565  	} else if !vfs2Used {
   566  		t.Skip("sticky bit test fails on VFS1.")
   567  	}
   568  
   569  	runIntegrationTest(t, nil, "./test_sticky")
   570  }
   571  
   572  func runIntegrationTest(t *testing.T, capAdd []string, args ...string) {
   573  	ctx := context.Background()
   574  	d := dockerutil.MakeContainer(ctx, t)
   575  	defer d.CleanUp(ctx)
   576  
   577  	if got, err := d.Run(ctx, dockerutil.RunOpts{
   578  		Image:   "basic/integrationtest",
   579  		WorkDir: "/root",
   580  		CapAdd:  capAdd,
   581  	}, args...); err != nil {
   582  		t.Fatalf("docker run failed: %v", err)
   583  	} else if got != "" {
   584  		t.Errorf("test failed:\n%s", got)
   585  	}
   586  }
   587  
   588  // Test that UDS can be created using overlay when parent directory is in lower
   589  // layer only (b/134090485).
   590  //
   591  // Prerequisite: the directory where the socket file is created must not have
   592  // been open for write before bind(2) is called.
   593  func TestBindOverlay(t *testing.T) {
   594  	ctx := context.Background()
   595  	d := dockerutil.MakeContainer(ctx, t)
   596  	defer d.CleanUp(ctx)
   597  
   598  	// Run the container.
   599  	got, err := d.Run(ctx, dockerutil.RunOpts{
   600  		Image: "basic/ubuntu",
   601  	}, "bash", "-c", "nc -q -1 -l -U /var/run/sock & p=$! && sleep 1 && echo foobar-asdf | nc -q 0 -U /var/run/sock && wait $p")
   602  	if err != nil {
   603  		t.Fatalf("docker run failed: %v", err)
   604  	}
   605  
   606  	// Check the output contains what we want.
   607  	if want := "foobar-asdf"; !strings.Contains(got, want) {
   608  		t.Fatalf("docker run output is missing %q: %s", want, got)
   609  	}
   610  }
   611  
   612  func TestMain(m *testing.M) {
   613  	dockerutil.EnsureSupportedDockerVersion()
   614  	flag.Parse()
   615  	os.Exit(m.Run())
   616  }