1 package schema2
2
3 import (
4 "context"
5 "reflect"
6 "testing"
7
8 "github.com/docker/distribution"
9 "github.com/opencontainers/go-digest"
10 )
11
12 type mockBlobService struct {
13 descriptors map[digest.Digest]distribution.Descriptor
14 }
15
16 func (bs *mockBlobService) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
17 if descriptor, ok := bs.descriptors[dgst]; ok {
18 return descriptor, nil
19 }
20 return distribution.Descriptor{}, distribution.ErrBlobUnknown
21 }
22
23 func (bs *mockBlobService) Get(ctx context.Context, dgst digest.Digest) ([]byte, error) {
24 panic("not implemented")
25 }
26
27 func (bs *mockBlobService) Open(ctx context.Context, dgst digest.Digest) (distribution.ReadSeekCloser, error) {
28 panic("not implemented")
29 }
30
31 func (bs *mockBlobService) Put(ctx context.Context, mediaType string, p []byte) (distribution.Descriptor, error) {
32 d := distribution.Descriptor{
33 Digest: digest.FromBytes(p),
34 Size: int64(len(p)),
35 MediaType: "application/octet-stream",
36 }
37 bs.descriptors[d.Digest] = d
38 return d, nil
39 }
40
41 func (bs *mockBlobService) Create(ctx context.Context, options ...distribution.BlobCreateOption) (distribution.BlobWriter, error) {
42 panic("not implemented")
43 }
44
45 func (bs *mockBlobService) Resume(ctx context.Context, id string) (distribution.BlobWriter, error) {
46 panic("not implemented")
47 }
48
49 func TestBuilder(t *testing.T) {
50 imgJSON := []byte(`{
51 "architecture": "amd64",
52 "config": {
53 "AttachStderr": false,
54 "AttachStdin": false,
55 "AttachStdout": false,
56 "Cmd": [
57 "/bin/sh",
58 "-c",
59 "echo hi"
60 ],
61 "Domainname": "",
62 "Entrypoint": null,
63 "Env": [
64 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
65 "derived=true",
66 "asdf=true"
67 ],
68 "Hostname": "23304fc829f9",
69 "Image": "sha256:4ab15c48b859c2920dd5224f92aabcd39a52794c5b3cf088fb3bbb438756c246",
70 "Labels": {},
71 "OnBuild": [],
72 "OpenStdin": false,
73 "StdinOnce": false,
74 "Tty": false,
75 "User": "",
76 "Volumes": null,
77 "WorkingDir": ""
78 },
79 "container": "e91032eb0403a61bfe085ff5a5a48e3659e5a6deae9f4d678daa2ae399d5a001",
80 "container_config": {
81 "AttachStderr": false,
82 "AttachStdin": false,
83 "AttachStdout": false,
84 "Cmd": [
85 "/bin/sh",
86 "-c",
87 "#(nop) CMD [\"/bin/sh\" \"-c\" \"echo hi\"]"
88 ],
89 "Domainname": "",
90 "Entrypoint": null,
91 "Env": [
92 "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
93 "derived=true",
94 "asdf=true"
95 ],
96 "Hostname": "23304fc829f9",
97 "Image": "sha256:4ab15c48b859c2920dd5224f92aabcd39a52794c5b3cf088fb3bbb438756c246",
98 "Labels": {},
99 "OnBuild": [],
100 "OpenStdin": false,
101 "StdinOnce": false,
102 "Tty": false,
103 "User": "",
104 "Volumes": null,
105 "WorkingDir": ""
106 },
107 "created": "2015-11-04T23:06:32.365666163Z",
108 "docker_version": "1.9.0-dev",
109 "history": [
110 {
111 "created": "2015-10-31T22:22:54.690851953Z",
112 "created_by": "/bin/sh -c #(nop) ADD file:a3bc1e842b69636f9df5256c49c5374fb4eef1e281fe3f282c65fb853ee171c5 in /"
113 },
114 {
115 "created": "2015-10-31T22:22:55.613815829Z",
116 "created_by": "/bin/sh -c #(nop) CMD [\"sh\"]"
117 },
118 {
119 "created": "2015-11-04T23:06:30.934316144Z",
120 "created_by": "/bin/sh -c #(nop) ENV derived=true",
121 "empty_layer": true
122 },
123 {
124 "created": "2015-11-04T23:06:31.192097572Z",
125 "created_by": "/bin/sh -c #(nop) ENV asdf=true",
126 "empty_layer": true
127 },
128 {
129 "created": "2015-11-04T23:06:32.083868454Z",
130 "created_by": "/bin/sh -c dd if=/dev/zero of=/file bs=1024 count=1024"
131 },
132 {
133 "created": "2015-11-04T23:06:32.365666163Z",
134 "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\" \"-c\" \"echo hi\"]",
135 "empty_layer": true
136 }
137 ],
138 "os": "linux",
139 "rootfs": {
140 "diff_ids": [
141 "sha256:c6f988f4874bb0add23a778f753c65efe992244e148a1d2ec2a8b664fb66bbd1",
142 "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
143 "sha256:13f53e08df5a220ab6d13c58b2bf83a59cbdc2e04d0a3f041ddf4b0ba4112d49"
144 ],
145 "type": "layers"
146 }
147 }`)
148 configDigest := digest.FromBytes(imgJSON)
149
150 descriptors := []distribution.Descriptor{
151 {
152 Digest: digest.Digest("sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"),
153 Size: 5312,
154 MediaType: MediaTypeLayer,
155 },
156 {
157 Digest: digest.Digest("sha256:86e0e091d0da6bde2456dbb48306f3956bbeb2eae1b5b9a43045843f69fe4aaa"),
158 Size: 235231,
159 MediaType: MediaTypeLayer,
160 },
161 {
162 Digest: digest.Digest("sha256:b4ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"),
163 Size: 639152,
164 MediaType: MediaTypeLayer,
165 },
166 }
167
168 bs := &mockBlobService{descriptors: make(map[digest.Digest]distribution.Descriptor)}
169 builder := NewManifestBuilder(bs, MediaTypeImageConfig, imgJSON)
170
171 for _, d := range descriptors {
172 if err := builder.AppendReference(d); err != nil {
173 t.Fatalf("AppendReference returned error: %v", err)
174 }
175 }
176
177 built, err := builder.Build(context.Background())
178 if err != nil {
179 t.Fatalf("Build returned error: %v", err)
180 }
181
182
183 _, err = bs.Stat(context.Background(), configDigest)
184 if err != nil {
185 t.Fatal("config was not put in the blob store")
186 }
187
188 manifest := built.(*DeserializedManifest).Manifest
189
190 if manifest.Versioned.SchemaVersion != 2 {
191 t.Fatal("SchemaVersion != 2")
192 }
193
194 target := manifest.Target()
195 if target.Digest != configDigest {
196 t.Fatalf("unexpected digest in target: %s", target.Digest.String())
197 }
198 if target.MediaType != MediaTypeImageConfig {
199 t.Fatalf("unexpected media type in target: %s", target.MediaType)
200 }
201 if target.Size != 3153 {
202 t.Fatalf("unexpected size in target: %d", target.Size)
203 }
204
205 references := manifest.References()
206 expected := append([]distribution.Descriptor{manifest.Target()}, descriptors...)
207 if !reflect.DeepEqual(references, expected) {
208 t.Fatal("References() does not match the descriptors added")
209 }
210 }
211
View as plain text