From b88a98bcade4efbbd4eaa5ca493a7fcab0bc4111 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Thu, 28 Dec 2017 15:03:49 -0800 Subject: [PATCH] client: add integration tests for prune Signed-off-by: Tonis Tiigi --- cache/refs.go | 2 +- client/client_test.go | 87 ++++++++++++++++++++++++++++++- cmd/buildctl/buildctl_test.go | 1 + cmd/buildctl/prune_test.go | 15 ++++++ exporter/containerimage/writer.go | 6 ++- 5 files changed, 108 insertions(+), 3 deletions(-) create mode 100644 cmd/buildctl/prune_test.go diff --git a/cache/refs.go b/cache/refs.go index 0cf429fd..37b04302 100644 --- a/cache/refs.go +++ b/cache/refs.go @@ -116,7 +116,7 @@ func (cr *cacheRecord) Parent() ImmutableRef { } p := cr.parent.(*immutableRef) p.mu.Lock() - p.mu.Unlock() + defer p.mu.Unlock() return p.ref() } diff --git a/client/client_test.go b/client/client_test.go index ad5ba779..bf1fad16 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -18,7 +18,9 @@ import ( "github.com/containerd/containerd" "github.com/containerd/containerd/content" + "github.com/containerd/containerd/images" "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/snapshots" "github.com/docker/distribution/manifest/schema2" "github.com/moby/buildkit/client/llb" "github.com/moby/buildkit/identity" @@ -68,6 +70,8 @@ func testBuildMultiMount(t *testing.T, sb integration.Sandbox) { err = c.Solve(context.TODO(), def, SolveOpt{}, nil) require.NoError(t, err) + + checkAllReleasable(t, c, sb, true) } func testBuildHTTPSource(t *testing.T, sb integration.Sandbox) { @@ -157,6 +161,8 @@ func testBuildHTTPSource(t *testing.T, sb integration.Sandbox) { require.Equal(t, fi.ModTime().Format(http.TimeFormat), modTime.Format(http.TimeFormat)) require.Equal(t, int(fi.Mode()&0777), 0741) + checkAllReleasable(t, c, sb, true) + // TODO: check that second request was marked as cached } @@ -253,6 +259,8 @@ func testUser(t *testing.T, sb integration.Sandbox) { dt, err = ioutil.ReadFile(filepath.Join(destDir, "userone")) require.NoError(t, err) require.Contains(t, string(dt), "1") + + checkAllReleasable(t, c, sb, true) } func testOCIExporter(t *testing.T, sb integration.Sandbox) { @@ -347,8 +355,9 @@ func testOCIExporter(t *testing.T, sb integration.Sandbox) { _, ok := m[l] require.True(t, ok) } - } + + checkAllReleasable(t, c, sb, true) } func testBuildPushAndValidate(t *testing.T, sb integration.Sandbox) { @@ -419,6 +428,8 @@ func testBuildPushAndValidate(t *testing.T, sb integration.Sandbox) { require.NoError(t, err) require.Equal(t, 0741, int(fi.Mode()&0777)) + checkAllReleasable(t, c, sb, false) + // examine contents of exported tars (requires containerd) var cdAddress string if cd, ok := sb.(interface { @@ -437,6 +448,16 @@ func testBuildPushAndValidate(t *testing.T, sb integration.Sandbox) { ctx := namespaces.WithNamespace(context.Background(), "buildkit") + // check image in containerd + _, err = client.ImageService().Get(ctx, target) + require.NoError(t, err) + + // deleting image should release all content + err = client.ImageService().Delete(ctx, target, images.SynchronousDelete()) + require.NoError(t, err) + + checkAllReleasable(t, c, sb, true) + img, err := client.Pull(ctx, target) require.NoError(t, err) @@ -563,3 +584,67 @@ func readTarToMap(dt []byte, compressed bool) (map[string]*tarItem, error) { m[h.Name] = &tarItem{header: h, data: dt} } } + +func checkAllReleasable(t *testing.T, c *Client, sb integration.Sandbox, checkContent bool) { + err := c.Prune(context.TODO(), nil) + require.NoError(t, err) + + du, err := c.DiskUsage(context.TODO()) + require.NoError(t, err) + require.Equal(t, 0, len(du)) + + // examine contents of exported tars (requires containerd) + var cdAddress string + if cd, ok := sb.(interface { + ContainerdAddress() string + }); !ok { + return + } else { + cdAddress = cd.ContainerdAddress() + } + + // TODO: make public pull helper function so this can be checked for standalone as well + + client, err := containerd.New(cdAddress) + require.NoError(t, err) + defer client.Close() + + ctx := namespaces.WithNamespace(context.Background(), "buildkit") + snapshotService := client.SnapshotService("overlayfs") + + retries := 0 + for { + count := 0 + err = snapshotService.Walk(ctx, func(context.Context, snapshots.Info) error { + count++ + return nil + }) + require.NoError(t, err) + if count == 0 { + break + } + require.True(t, 20 > retries) + retries++ + time.Sleep(500 * time.Millisecond) + } + + if !checkContent { + return + } + + retries = 0 + for { + count := 0 + err = client.ContentStore().Walk(ctx, func(content.Info) error { + count++ + return nil + }) + require.NoError(t, err) + if count == 0 { + break + } + require.True(t, 20 > retries) + retries++ + time.Sleep(500 * time.Millisecond) + } +} diff --git a/cmd/buildctl/buildctl_test.go b/cmd/buildctl/buildctl_test.go index c166ec88..f7073fec 100644 --- a/cmd/buildctl/buildctl_test.go +++ b/cmd/buildctl/buildctl_test.go @@ -12,5 +12,6 @@ func TestCLIIntegration(t *testing.T) { testBuildWithLocalFiles, testBuildLocalExporter, testBuildContainerdExporter, + testPrune, }) } diff --git a/cmd/buildctl/prune_test.go b/cmd/buildctl/prune_test.go new file mode 100644 index 00000000..9924f3c7 --- /dev/null +++ b/cmd/buildctl/prune_test.go @@ -0,0 +1,15 @@ +package main + +import ( + "testing" + + "github.com/moby/buildkit/util/testutil/integration" + "github.com/stretchr/testify/assert" +) + +func testPrune(t *testing.T, sb integration.Sandbox) { + t.Parallel() + cmd := sb.Cmd("prune") + err := cmd.Run() + assert.NoError(t, err) +} diff --git a/exporter/containerimage/writer.go b/exporter/containerimage/writer.go index 87c6530a..f156b824 100644 --- a/exporter/containerimage/writer.go +++ b/exporter/containerimage/writer.go @@ -248,7 +248,11 @@ func getRefDesciptions(ref cache.ImmutableRef, limit int) []string { if descr == "" { descr = defaultMsg } - return append(getRefDesciptions(ref.Parent(), limit-1), descr) + p := ref.Parent() + if p != nil { + defer p.Release(context.TODO()) + } + return append(getRefDesciptions(p, limit-1), descr) } func oneOffProgress(ctx context.Context, id string) func(err error) error {