1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package daemon
16
17 import (
18 "context"
19 "errors"
20 "fmt"
21 "io"
22 "os"
23 "strings"
24 "testing"
25
26 "github.com/docker/docker/api/types/container"
27 api "github.com/docker/docker/api/types/image"
28
29 "github.com/docker/docker/api/types"
30 "github.com/google/go-containerregistry/internal/compare"
31 "github.com/google/go-containerregistry/pkg/name"
32 "github.com/google/go-containerregistry/pkg/v1/tarball"
33 "github.com/google/go-containerregistry/pkg/v1/validate"
34 )
35
36 var imagePath = "../tarball/testdata/test_image_1.tar"
37
38 var inspectResp = types.ImageInspect{
39 ID: "sha256:6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e",
40 RepoTags: []string{
41 "bazel/v1/tarball:test_image_1",
42 "test_image_2:latest",
43 },
44 Created: "1970-01-01T00:00:00Z",
45 Author: "Bazel",
46 Architecture: "amd64",
47 Os: "linux",
48 Size: 8,
49 VirtualSize: 8,
50 Config: &container.Config{},
51 GraphDriver: types.GraphDriverData{
52 Data: map[string]string{
53 "MergedDir": "/var/lib/docker/overlay2/988ecd005d048fd47b241dd57687231859563ba65a1dfd01ae1771ebfc4cb7c5/merged",
54 "UpperDir": "/var/lib/docker/overlay2/988ecd005d048fd47b241dd57687231859563ba65a1dfd01ae1771ebfc4cb7c5/diff",
55 "WorkDir": "/var/lib/docker/overlay2/988ecd005d048fd47b241dd57687231859563ba65a1dfd01ae1771ebfc4cb7c5/work",
56 },
57 Name: "overlay2",
58 },
59 RootFS: types.RootFS{
60 Type: "layers",
61 Layers: []string{
62 "sha256:8897395fd26dc44ad0e2a834335b33198cb41ac4d98dfddf58eced3853fa7b17",
63 },
64 },
65 }
66
67 type MockClient struct {
68 Client
69 path string
70 negotiated bool
71
72 wantCtx context.Context
73
74 loadErr error
75 loadBody io.ReadCloser
76
77 saveErr error
78 saveBody io.ReadCloser
79
80 inspectErr error
81 inspectResp types.ImageInspect
82 inspectBody []byte
83
84 tagErr error
85 }
86
87 func (m *MockClient) NegotiateAPIVersion(_ context.Context) {
88 m.negotiated = true
89 }
90
91 func (m *MockClient) ImageSave(_ context.Context, _ []string) (io.ReadCloser, error) {
92 if !m.negotiated {
93 return nil, errors.New("you forgot to call NegotiateAPIVersion before calling ImageSave")
94 }
95
96 if m.path != "" {
97 return os.Open(m.path)
98 }
99
100 return m.saveBody, m.saveErr
101 }
102
103 func (m *MockClient) ImageInspectWithRaw(_ context.Context, _ string) (types.ImageInspect, []byte, error) {
104 return m.inspectResp, m.inspectBody, m.inspectErr
105 }
106
107 func (m *MockClient) ImageHistory(_ context.Context, _ string) ([]api.HistoryResponseItem, error) {
108 return []api.HistoryResponseItem{
109 {
110 CreatedBy: "bazel build ...",
111 ID: "sha256:6e0b05049ed9c17d02e1a55e80d6599dbfcce7f4f4b022e3c673e685789c470e",
112 Size: 8,
113 Tags: []string{
114 "bazel/v1/tarball:test_image_1",
115 },
116 },
117 }, nil
118 }
119
120 func TestImage(t *testing.T) {
121 for _, tc := range []struct {
122 name string
123 buffered bool
124 client *MockClient
125 wantResponse string
126 wantErr string
127 }{{
128 name: "success",
129 client: &MockClient{
130 path: imagePath,
131 inspectResp: inspectResp,
132 },
133 }, {
134 name: "save err",
135 client: &MockClient{
136 saveBody: io.NopCloser(strings.NewReader("Loaded")),
137 saveErr: fmt.Errorf("locked and loaded"),
138 inspectResp: inspectResp,
139 },
140 wantErr: "locked and loaded",
141 }, {
142 name: "read err",
143 client: &MockClient{
144 inspectResp: inspectResp,
145 saveBody: io.NopCloser(&errReader{fmt.Errorf("goodbye, world")}),
146 },
147 wantErr: "goodbye, world",
148 }} {
149 run := func(t *testing.T) {
150 opts := []Option{WithClient(tc.client)}
151 if tc.buffered {
152 opts = append(opts, WithBufferedOpener())
153 } else {
154 opts = append(opts, WithUnbufferedOpener())
155 }
156 img, err := tarball.ImageFromPath(imagePath, nil)
157 if err != nil {
158 t.Fatalf("error loading test image: %s", err)
159 }
160
161 tag, err := name.NewTag("unused", name.WeakValidation)
162 if err != nil {
163 t.Fatalf("error creating test name: %s", err)
164 }
165
166 dmn, err := Image(tag, opts...)
167 if err != nil {
168 if tc.wantErr == "" {
169 t.Errorf("Error loading daemon image: %s", err)
170 } else if !strings.Contains(err.Error(), tc.wantErr) {
171 t.Errorf("wanted %s to contain %s", err.Error(), tc.wantErr)
172 }
173 return
174 }
175
176 err = compare.Images(img, dmn)
177 if err != nil {
178 if tc.wantErr == "" {
179 t.Errorf("compare.Images: %v", err)
180 } else if !strings.Contains(err.Error(), tc.wantErr) {
181 t.Errorf("wanted %s to contain %s", err.Error(), tc.wantErr)
182 }
183 }
184
185 err = validate.Image(dmn)
186 if err != nil {
187 if tc.wantErr == "" {
188 t.Errorf("validate.Image: %v", err)
189 } else if !strings.Contains(err.Error(), tc.wantErr) {
190 t.Errorf("wanted %s to contain %s", err.Error(), tc.wantErr)
191 }
192 }
193 }
194
195 tc.buffered = true
196 t.Run(tc.name+" buffered", run)
197
198 tc.buffered = false
199 t.Run(tc.name+" unbuffered", run)
200 }
201 }
202
203 func TestImageDefaultClient(t *testing.T) {
204 wantErr := fmt.Errorf("bad client")
205 defaultClient = func() (Client, error) {
206 return nil, wantErr
207 }
208
209 if _, err := Image(name.MustParseReference("unused")); !errors.Is(err, wantErr) {
210 t.Errorf("Image(): want %v; got %v", wantErr, err)
211 }
212 }
213
View as plain text