Skip to content
This repository was archived by the owner on Dec 2, 2020. It is now read-only.

Commit 377ac90

Browse files
committed
RepackImage unit tests
1 parent 45127b5 commit 377ac90

File tree

5 files changed

+348
-87
lines changed

5 files changed

+348
-87
lines changed

img2lambda/extract/repack_image.go

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,6 @@ func RepackImage(imageName string, layerOutputDir string) (layers []types.Lambda
3030
return nil, err
3131
}
3232

33-
return repackImage(ref, imageName, layerOutputDir)
34-
}
35-
36-
func repackImage(ref imgtypes.ImageReference, imageName string, layerOutputDir string) (layers []types.LambdaLayer, retErr error) {
3733
sys := &imgtypes.SystemContext{}
3834

3935
ctx := context.Background()
@@ -59,21 +55,42 @@ func repackImage(ref imgtypes.ImageReference, imageName string, layerOutputDir s
5955
}
6056
}()
6157

62-
layerInfos := src.LayerInfos()
58+
return repackImage(&repackOptions{
59+
ctx: ctx,
60+
cache: cache,
61+
imageSource: src,
62+
rawImageSource: rawSource,
63+
imageName: imageName,
64+
layerOutputDir: layerOutputDir,
65+
})
66+
}
67+
68+
type repackOptions struct {
69+
ctx context.Context
70+
cache imgtypes.BlobInfoCache
71+
imageSource imgtypes.ImageCloser
72+
rawImageSource imgtypes.ImageSource
73+
imageName string
74+
layerOutputDir string
75+
}
76+
77+
func repackImage(opts *repackOptions) (layers []types.LambdaLayer, retErr error) {
78+
79+
layerInfos := opts.imageSource.LayerInfos()
6380

64-
log.Printf("Image %s has %d layers", imageName, len(layerInfos))
81+
log.Printf("Image %s has %d layers", opts.imageName, len(layerInfos))
6582

6683
// Unpack and inspect each image layer, copy relevant files to new Lambda layer
67-
if err := os.MkdirAll(layerOutputDir, 0777); err != nil {
84+
if err := os.MkdirAll(opts.layerOutputDir, 0777); err != nil {
6885
return nil, err
6986
}
7087

7188
lambdaLayerNum := 1
7289

7390
for _, layerInfo := range layerInfos {
74-
lambdaLayerFilename := filepath.Join(layerOutputDir, fmt.Sprintf("layer-%d.zip", lambdaLayerNum))
91+
lambdaLayerFilename := filepath.Join(opts.layerOutputDir, fmt.Sprintf("layer-%d.zip", lambdaLayerNum))
7592

76-
layerStream, _, err := rawSource.GetBlob(ctx, layerInfo, cache)
93+
layerStream, _, err := opts.rawImageSource.GetBlob(opts.ctx, layerInfo, opts.cache)
7794
if err != nil {
7895
return nil, err
7996
}
@@ -93,7 +110,7 @@ func repackImage(ref imgtypes.ImageReference, imageName string, layerOutputDir s
93110
}
94111
}
95112

96-
log.Printf("Created %d Lambda layer files for image %s", len(layers), imageName)
113+
log.Printf("Created %d Lambda layer files for image %s", len(layers), opts.imageName)
97114

98115
return layers, nil
99116
}
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
package extract
2+
3+
import (
4+
"archive/zip"
5+
"bufio"
6+
"bytes"
7+
"io"
8+
"io/ioutil"
9+
"os"
10+
"testing"
11+
12+
"github.com/awslabs/aws-lambda-container-image-converter/img2lambda/internal/testing/mocks"
13+
"github.com/awslabs/aws-lambda-container-image-converter/img2lambda/types"
14+
imgtypes "github.com/containers/image/types"
15+
"github.com/golang/mock/gomock"
16+
"github.com/mholt/archiver"
17+
godigest "github.com/opencontainers/go-digest"
18+
"github.com/stretchr/testify/assert"
19+
)
20+
21+
func createImageLayer(t *testing.T,
22+
rawSource *mocks.MockImageSource,
23+
filename string,
24+
fileContents string,
25+
digest string) *imgtypes.BlobInfo {
26+
27+
tar := archiver.NewTar()
28+
29+
layerFile, err := ioutil.TempFile("", "")
30+
assert.Nil(t, err)
31+
_, err = layerFile.WriteString(fileContents)
32+
assert.Nil(t, err)
33+
err = layerFile.Close()
34+
assert.Nil(t, err)
35+
layerFileInfo, err := os.Stat(layerFile.Name())
36+
assert.Nil(t, err)
37+
38+
var tarContents bytes.Buffer
39+
bufWriter := bufio.NewWriter(&tarContents)
40+
layerFile, err = os.Open(layerFile.Name())
41+
assert.Nil(t, err)
42+
err = tar.Create(bufWriter)
43+
assert.Nil(t, err)
44+
err = tar.Write(archiver.File{
45+
FileInfo: archiver.FileInfo{
46+
FileInfo: layerFileInfo,
47+
CustomName: filename,
48+
},
49+
ReadCloser: layerFile,
50+
})
51+
assert.Nil(t, err)
52+
err = bufWriter.Flush()
53+
assert.Nil(t, err)
54+
err = tar.Close()
55+
assert.Nil(t, err)
56+
err = layerFile.Close()
57+
assert.Nil(t, err)
58+
err = os.Remove(layerFile.Name())
59+
assert.Nil(t, err)
60+
61+
blobInfo := imgtypes.BlobInfo{Digest: godigest.Digest(digest)}
62+
63+
rawSource.EXPECT().GetBlob(gomock.Any(),
64+
blobInfo,
65+
gomock.Any()).Return(ioutil.NopCloser(bytes.NewReader(tarContents.Bytes())), int64(0), nil)
66+
67+
return &blobInfo
68+
}
69+
70+
func validateLambdaLayer(t *testing.T,
71+
layer *types.LambdaLayer,
72+
expectedFilename string,
73+
expectedFileContents string,
74+
expectedDigest string) {
75+
76+
assert.Equal(t, expectedDigest, layer.Digest)
77+
78+
z := archiver.NewZip()
79+
80+
zipFile, err := os.Open(layer.File)
81+
assert.Nil(t, err)
82+
zipFileInfo, err := os.Stat(zipFile.Name())
83+
assert.Nil(t, err)
84+
85+
err = z.Open(zipFile, zipFileInfo.Size())
86+
assert.Nil(t, err)
87+
88+
contentsFile, err := z.Read()
89+
assert.Nil(t, err)
90+
zfh, ok := contentsFile.Header.(zip.FileHeader)
91+
assert.True(t, ok)
92+
assert.Equal(t, expectedFilename, zfh.Name)
93+
94+
buf := new(bytes.Buffer)
95+
_, err = buf.ReadFrom(contentsFile.ReadCloser)
96+
assert.Nil(t, err)
97+
contents := buf.String()
98+
assert.Equal(t, expectedFileContents, contents)
99+
100+
_, err = z.Read()
101+
assert.NotNil(t, err)
102+
assert.Equal(t, io.EOF, err)
103+
104+
err = z.Close()
105+
assert.Nil(t, err)
106+
err = zipFile.Close()
107+
assert.Nil(t, err)
108+
err = os.Remove(zipFile.Name())
109+
assert.Nil(t, err)
110+
}
111+
112+
func TestRepack(t *testing.T) {
113+
ctrl := gomock.NewController(t)
114+
defer ctrl.Finish()
115+
116+
source := mocks.NewMockImageCloser(ctrl)
117+
rawSource := mocks.NewMockImageSource(ctrl)
118+
119+
// Create layer tar files
120+
var blobInfos []imgtypes.BlobInfo
121+
122+
// First matching file
123+
blobInfo1 := createImageLayer(t, rawSource, "opt/file1", "hello world 1", "digest1")
124+
blobInfos = append(blobInfos, *blobInfo1)
125+
126+
// Second matching file
127+
blobInfo2 := createImageLayer(t, rawSource, "opt/hello/file2", "hello world 2", "digest2")
128+
blobInfos = append(blobInfos, *blobInfo2)
129+
130+
// Irrelevant file
131+
blobInfo3 := createImageLayer(t, rawSource, "local/hello", "hello world 3", "digest3")
132+
blobInfos = append(blobInfos, *blobInfo3)
133+
134+
// Overwriting previous file
135+
blobInfo4 := createImageLayer(t, rawSource, "opt/file1", "hello world 4", "digest4")
136+
blobInfos = append(blobInfos, *blobInfo4)
137+
138+
source.EXPECT().LayerInfos().Return(blobInfos)
139+
140+
dir, err := ioutil.TempDir("", "")
141+
assert.Nil(t, err)
142+
143+
layers, err := repackImage(&repackOptions{
144+
ctx: nil,
145+
cache: nil,
146+
imageSource: source,
147+
rawImageSource: rawSource,
148+
imageName: "test-image",
149+
layerOutputDir: dir,
150+
})
151+
152+
assert.Nil(t, err)
153+
assert.Len(t, layers, 3)
154+
155+
validateLambdaLayer(t, &layers[0], "file1", "hello world 1", "digest1")
156+
validateLambdaLayer(t, &layers[1], "hello/file2", "hello world 2", "digest2")
157+
validateLambdaLayer(t, &layers[2], "file1", "hello world 4", "digest4")
158+
159+
err = os.Remove(dir)
160+
assert.Nil(t, err)
161+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
package testing
22

33
//go:generate mockgen.sh github.com/aws/aws-sdk-go/service/lambda/lambdaiface LambdaAPI mocks/lambda_mocks.go
4-
//go:generate mockgen.sh github.com/containers/image/types ImageReference,ImageSource mocks/image_mocks.go
4+
//go:generate mockgen.sh github.com/containers/image/types ImageCloser,ImageSource mocks/image_mocks.go

0 commit comments

Comments
 (0)