Skip to content

Commit 3d55fc5

Browse files
authored
test(integration/bench): wait for an image load and remove images after tests (fanal#86)
* bench: remove images after finishing benchmarks * test(integration): remove images after finishing tests * test(bench): merge master branch * debug * chore(Makefile): exclude all tests when running benchmarks * test(bench): wait for an image load * fix(image): close source * test(integration): wait for an image load * test(bench): clean up debug code
1 parent 495332c commit 3d55fc5

File tree

5 files changed

+83
-38
lines changed

5 files changed

+83
-38
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ test-integration: integration/testdata/fixtures/*.tar.gz
2424

2525
.PHONY: test-performance
2626
test-performance: integration/testdata/fixtures/*.tar.gz
27-
go test -v -benchtime=10x -tags="performance containers_image_storage_stub" -bench=. ./integration/...
27+
go test -v -benchtime=10x -run=^$$ -tags="performance containers_image_storage_stub" -bench=. ./integration/...

extractor/docker/docker.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ import (
99
"strings"
1010
"time"
1111

12+
digest "github.com/opencontainers/go-digest"
13+
"golang.org/x/xerrors"
14+
1215
"github.com/aquasecurity/fanal/analyzer/library"
1316
"github.com/aquasecurity/fanal/cache"
1417
"github.com/aquasecurity/fanal/extractor"
@@ -18,8 +21,6 @@ import (
1821
"github.com/aquasecurity/fanal/types"
1922
"github.com/aquasecurity/fanal/utils"
2023
"github.com/knqyf263/nested"
21-
"github.com/opencontainers/go-digest"
22-
"golang.org/x/xerrors"
2324
)
2425

2526
const (
@@ -111,6 +112,8 @@ func (d Extractor) Extract(ctx context.Context, imgRef image.Reference, transpor
111112
return nil, xerrors.Errorf("unable to initialize a image struct: %w", err)
112113
}
113114

115+
defer img.Close()
116+
114117
var layerIDs []string
115118
layers, err := img.LayerInfos()
116119
if err != nil {

extractor/image/image.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"github.com/containers/image/transports/alltransports"
1313
imageTypes "github.com/containers/image/types"
1414
"github.com/docker/distribution/reference"
15-
"github.com/opencontainers/go-digest"
15+
digest "github.com/opencontainers/go-digest"
1616
"golang.org/x/xerrors"
1717

1818
"github.com/aquasecurity/fanal/cache"
@@ -21,11 +21,13 @@ import (
2121

2222
type ImageSource interface {
2323
GetBlob(ctx context.Context, info imageTypes.BlobInfo, cache imageTypes.BlobInfoCache) (reader io.ReadCloser, n int64, err error)
24+
Close() error
2425
}
2526

2627
type ImageCloser interface {
2728
LayerInfos() (layerInfos []imageTypes.BlobInfo)
2829
ConfigBlob(ctx context.Context) (blob []byte, err error)
30+
Close() error
2931
}
3032

3133
type Reference struct {
@@ -236,3 +238,12 @@ func (img *Image) GetBlob(ctx context.Context, dig digest.Digest) (io.ReadCloser
236238

237239
return ioutil.NopCloser(r), cleanup, nil
238240
}
241+
242+
func (img *Image) Close() {
243+
if img.src != nil {
244+
img.src.Close()
245+
}
246+
if img.rawSource != nil {
247+
img.rawSource.Close()
248+
}
249+
}

integration/benchmark_test.go

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ package integration
55
import (
66
"context"
77
"fmt"
8+
"io"
89
"io/ioutil"
910
"os"
1011
"testing"
1112
"time"
1213

14+
"github.com/aquasecurity/fanal/analyzer"
1315
_ "github.com/aquasecurity/fanal/analyzer/command/apk"
1416
_ "github.com/aquasecurity/fanal/analyzer/library/bundler"
1517
_ "github.com/aquasecurity/fanal/analyzer/library/cargo"
@@ -27,8 +29,6 @@ import (
2729
_ "github.com/aquasecurity/fanal/analyzer/pkg/apk"
2830
_ "github.com/aquasecurity/fanal/analyzer/pkg/dpkg"
2931
_ "github.com/aquasecurity/fanal/analyzer/pkg/rpm"
30-
31-
"github.com/aquasecurity/fanal/analyzer"
3232
"github.com/aquasecurity/fanal/cache"
3333
"github.com/aquasecurity/fanal/extractor/docker"
3434
"github.com/aquasecurity/fanal/types"
@@ -46,37 +46,37 @@ type testCase struct {
4646

4747
var testCases = []testCase{
4848
{
49-
name: "happy path, alpine:3.10",
49+
name: "happy path alpine:3.10",
5050
imageName: "alpine:3.10",
5151
imageFile: "testdata/fixtures/alpine-310.tar.gz",
5252
},
5353
{
54-
name: "happy path, amazonlinux:2",
54+
name: "happy path amazonlinux:2",
5555
imageName: "amazonlinux:2",
5656
imageFile: "testdata/fixtures/amazon-2.tar.gz",
5757
},
5858
{
59-
name: "happy path, debian:buster",
59+
name: "happy path debian:buster",
6060
imageName: "debian:buster",
6161
imageFile: "testdata/fixtures/debian-buster.tar.gz",
6262
},
6363
{
64-
name: "happy path, photon:1.0",
64+
name: "happy path photon:1.0",
6565
imageName: "photon:1.0-20190823",
6666
imageFile: "testdata/fixtures/photon-10.tar.gz",
6767
},
6868
{
69-
name: "happy path, registry.redhat.io/ubi7",
69+
name: "happy path registry.redhat.io/ubi7",
7070
imageName: "registry.redhat.io/ubi7",
7171
imageFile: "testdata/fixtures/ubi-7.tar.gz",
7272
},
7373
{
74-
name: "happy path, opensuse leap 15.1",
74+
name: "happy path opensuse leap 15.1",
7575
imageName: "opensuse/leap:latest",
7676
imageFile: "testdata/fixtures/opensuse-leap-151.tar.gz",
7777
},
7878
{
79-
name: "happy path, vulnimage with lock files",
79+
name: "happy path vulnimage with lock files",
8080
imageName: "knqyf263/vuln-image:1.2.3",
8181
imageFile: "testdata/fixtures/vulnimage.tar.gz",
8282
},
@@ -103,50 +103,62 @@ func runChecksBench(b *testing.B, ctx context.Context, imageName string, ac anal
103103
for i := 0; i < b.N; i++ {
104104
run(b, ctx, imageName, ac)
105105
if c != nil {
106-
c.Clear()
106+
_ = c.Clear()
107107
}
108108
}
109109
}
110110

111-
func BenchmarkFanal_Library_DockerMode_WithoutCache(b *testing.B) {
112-
benchCache, _ := ioutil.TempDir("", "BenchmarkFanal_Library_DockerMode_WithoutCache_*")
113-
defer os.RemoveAll(benchCache)
114-
111+
func BenchmarkDockerMode_WithoutCache(b *testing.B) {
115112
for _, tc := range testCases {
116-
ctx, imageName, c, cli, ac := setup(b, tc, benchCache)
113+
tc := tc
117114
b.Run(tc.name, func(b *testing.B) {
115+
benchCache, err := ioutil.TempDir("", "DockerMode_WithoutCache_")
116+
require.NoError(b, err)
117+
defer os.RemoveAll(benchCache)
118+
119+
ctx, imageName, c, cli, ac := setup(b, tc, benchCache)
120+
118121
b.ReportAllocs()
119122
b.ResetTimer()
120123
runChecksBench(b, ctx, imageName, ac, c)
121124
b.StopTimer()
122-
})
123125

124-
teardown(b, ctx, imageName, cli)
126+
teardown(b, ctx, tc.imageName, imageName, cli)
127+
})
125128
}
126129
}
127130

128-
func BenchmarkFanal_Library_DockerMode_WithCache(b *testing.B) {
129-
benchCache, _ := ioutil.TempDir("", "BenchmarkFanal_Library_DockerMode_WithCache_*")
130-
defer os.RemoveAll(benchCache)
131-
131+
func BenchmarkDockerMode_WithCache(b *testing.B) {
132132
for _, tc := range testCases {
133-
ctx, imageName, _, cli, ac := setup(b, tc, benchCache)
134-
// run once to generate cache
135-
run(b, ctx, imageName, ac)
136-
133+
tc := tc
137134
b.Run(tc.name, func(b *testing.B) {
135+
benchCache, err := ioutil.TempDir("", "DockerMode_WithCache_")
136+
require.NoError(b, err)
137+
defer os.RemoveAll(benchCache)
138+
139+
ctx, imageName, _, cli, ac := setup(b, tc, benchCache)
140+
// run once to generate cache
141+
run(b, ctx, imageName, ac)
142+
138143
b.ReportAllocs()
139144
b.ResetTimer()
140145
runChecksBench(b, ctx, imageName, ac, nil)
141146
b.StopTimer()
147+
148+
teardown(b, ctx, tc.imageName, imageName, cli)
142149
})
143150

144-
teardown(b, ctx, imageName, cli)
145151
}
146152
}
147153

148-
func teardown(b *testing.B, ctx context.Context, imageName string, cli *client.Client) {
149-
_, err := cli.ImageRemove(ctx, imageName, dtypes.ImageRemoveOptions{
154+
func teardown(b *testing.B, ctx context.Context, originalImageName, imageName string, cli *client.Client) {
155+
_, err := cli.ImageRemove(ctx, originalImageName, dtypes.ImageRemoveOptions{
156+
Force: true,
157+
PruneChildren: true,
158+
})
159+
assert.NoError(b, err)
160+
161+
_, err = cli.ImageRemove(ctx, imageName, dtypes.ImageRemoveOptions{
150162
Force: true,
151163
PruneChildren: true,
152164
})
@@ -165,15 +177,24 @@ func setup(b *testing.B, tc testCase, cacheDir string) (context.Context, string,
165177
cli, err := client.NewClientWithOpts(client.FromEnv)
166178
require.NoError(b, err, tc.name)
167179

168-
testfile, err := os.Open(tc.imageFile)
180+
// ensure image doesnt already exists
181+
_, _ = cli.ImageRemove(ctx, tc.imageName, dtypes.ImageRemoveOptions{
182+
Force: true,
183+
PruneChildren: true,
184+
})
185+
186+
testFile, err := os.Open(tc.imageFile)
169187
require.NoError(b, err)
170188

171189
// load image into docker engine
172-
_, err = cli.ImageLoad(ctx, testfile, true)
190+
resp, err := cli.ImageLoad(ctx, testFile, false)
173191
require.NoError(b, err, tc.name)
174192

193+
// ensure an image has finished being loaded.
194+
io.Copy(ioutil.Discard, resp.Body)
195+
require.NoError(b, resp.Body.Close())
196+
175197
imageName := fmt.Sprintf("%s-%s", tc.imageName, nextRandom())
176-
fmt.Println(imageName)
177198

178199
// tag our image to something unique
179200
err = cli.ImageTag(ctx, tc.imageName, imageName)

integration/library_test.go

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"context"
77
"encoding/json"
88
"fmt"
9+
"io"
910
"io/ioutil"
1011
"os"
1112
"strings"
@@ -112,7 +113,7 @@ func TestFanal_Library_DockerMode(t *testing.T) {
112113
t.Run(tc.name, func(t *testing.T) {
113114
t.Parallel()
114115
ctx := context.Background()
115-
d, _ := ioutil.TempDir("", "TestFanal_Library_*")
116+
d, _ := ioutil.TempDir("", "TestFanal_Library_")
116117
defer os.RemoveAll(d)
117118
c := cache.New(d)
118119
opt := types.DockerOption{
@@ -127,8 +128,9 @@ func TestFanal_Library_DockerMode(t *testing.T) {
127128
require.NoError(t, err)
128129

129130
// load image into docker engine
130-
_, err = cli.ImageLoad(ctx, testfile, true)
131+
resp, err := cli.ImageLoad(ctx, testfile, true)
131132
require.NoError(t, err, tc.name)
133+
io.Copy(ioutil.Discard, resp.Body)
132134

133135
// tag our image to something unique
134136
err = cli.ImageTag(ctx, tc.imageName, tc.imageFile)
@@ -151,6 +153,14 @@ func TestFanal_Library_DockerMode(t *testing.T) {
151153
PruneChildren: true,
152154
})
153155
assert.NoError(t, err, tc.name)
156+
_, err = cli.ImageRemove(ctx, tc.imageName, dtypes.ImageRemoveOptions{
157+
Force: true,
158+
PruneChildren: true,
159+
})
160+
assert.NoError(t, err, tc.name)
161+
162+
// clear Cache
163+
require.NoError(t, c.Clear(), tc.name)
154164
})
155165
}
156166
}
@@ -162,7 +172,7 @@ func TestFanal_Library_TarMode(t *testing.T) {
162172
t.Run(tc.name, func(t *testing.T) {
163173
t.Parallel()
164174
ctx := context.Background()
165-
d, _ := ioutil.TempDir("", "TestFanal_Library_*")
175+
d, _ := ioutil.TempDir("", "TestFanal_Library_")
166176
defer os.RemoveAll(d)
167177
c := cache.New(d)
168178

0 commit comments

Comments
 (0)