1
2
3
4 package gcs
5
6 import (
7 "fmt"
8 "io/ioutil"
9 "os"
10 "testing"
11
12 dcontext "github.com/docker/distribution/context"
13 storagedriver "github.com/docker/distribution/registry/storage/driver"
14 "github.com/docker/distribution/registry/storage/driver/testsuites"
15 "golang.org/x/oauth2"
16 "golang.org/x/oauth2/google"
17 "google.golang.org/api/googleapi"
18 "google.golang.org/cloud/storage"
19 "gopkg.in/check.v1"
20 )
21
22
23 func Test(t *testing.T) { check.TestingT(t) }
24
25 var gcsDriverConstructor func(rootDirectory string) (storagedriver.StorageDriver, error)
26 var skipGCS func() string
27
28 func init() {
29 bucket := os.Getenv("REGISTRY_STORAGE_GCS_BUCKET")
30 credentials := os.Getenv("GOOGLE_APPLICATION_CREDENTIALS")
31
32
33 skipGCS = func() string {
34 if bucket == "" || credentials == "" {
35 return "The following environment variables must be set to enable these tests: REGISTRY_STORAGE_GCS_BUCKET, GOOGLE_APPLICATION_CREDENTIALS"
36 }
37 return ""
38 }
39
40 if skipGCS() != "" {
41 return
42 }
43
44 root, err := ioutil.TempDir("", "driver-")
45 if err != nil {
46 panic(err)
47 }
48 defer os.Remove(root)
49 var ts oauth2.TokenSource
50 var email string
51 var privateKey []byte
52
53 ts, err = google.DefaultTokenSource(dcontext.Background(), storage.ScopeFullControl)
54 if err != nil {
55
56
57 jwtConfig, err := google.JWTConfigFromJSON([]byte(credentials), storage.ScopeFullControl)
58 if err != nil {
59 panic(fmt.Sprintf("Error reading JWT config : %s", err))
60 }
61 email = jwtConfig.Email
62 privateKey = jwtConfig.PrivateKey
63 if len(privateKey) == 0 {
64 panic("Error reading JWT config : missing private_key property")
65 }
66 if email == "" {
67 panic("Error reading JWT config : missing client_email property")
68 }
69 ts = jwtConfig.TokenSource(dcontext.Background())
70 }
71
72 gcsDriverConstructor = func(rootDirectory string) (storagedriver.StorageDriver, error) {
73 parameters := driverParameters{
74 bucket: bucket,
75 rootDirectory: root,
76 email: email,
77 privateKey: privateKey,
78 client: oauth2.NewClient(dcontext.Background(), ts),
79 chunkSize: defaultChunkSize,
80 }
81
82 return New(parameters)
83 }
84
85 testsuites.RegisterSuite(func() (storagedriver.StorageDriver, error) {
86 return gcsDriverConstructor(root)
87 }, skipGCS)
88 }
89
90
91 func TestCommitEmpty(t *testing.T) {
92 if skipGCS() != "" {
93 t.Skip(skipGCS())
94 }
95
96 validRoot, err := ioutil.TempDir("", "driver-")
97 if err != nil {
98 t.Fatalf("unexpected error creating temporary directory: %v", err)
99 }
100 defer os.Remove(validRoot)
101
102 driver, err := gcsDriverConstructor(validRoot)
103 if err != nil {
104 t.Fatalf("unexpected error creating rooted driver: %v", err)
105 }
106
107 filename := "/test"
108 ctx := dcontext.Background()
109
110 writer, err := driver.Writer(ctx, filename, false)
111 defer driver.Delete(ctx, filename)
112 if err != nil {
113 t.Fatalf("driver.Writer: unexpected error: %v", err)
114 }
115 err = writer.Commit()
116 if err != nil {
117 t.Fatalf("writer.Commit: unexpected error: %v", err)
118 }
119 err = writer.Close()
120 if err != nil {
121 t.Fatalf("writer.Close: unexpected error: %v", err)
122 }
123 if writer.Size() != 0 {
124 t.Fatalf("writer.Size: %d != 0", writer.Size())
125 }
126 readContents, err := driver.GetContent(ctx, filename)
127 if err != nil {
128 t.Fatalf("driver.GetContent: unexpected error: %v", err)
129 }
130 if len(readContents) != 0 {
131 t.Fatalf("len(driver.GetContent(..)): %d != 0", len(readContents))
132 }
133 }
134
135
136
137 func TestCommit(t *testing.T) {
138 if skipGCS() != "" {
139 t.Skip(skipGCS())
140 }
141
142 validRoot, err := ioutil.TempDir("", "driver-")
143 if err != nil {
144 t.Fatalf("unexpected error creating temporary directory: %v", err)
145 }
146 defer os.Remove(validRoot)
147
148 driver, err := gcsDriverConstructor(validRoot)
149 if err != nil {
150 t.Fatalf("unexpected error creating rooted driver: %v", err)
151 }
152
153 filename := "/test"
154 ctx := dcontext.Background()
155
156 contents := make([]byte, defaultChunkSize)
157 writer, err := driver.Writer(ctx, filename, false)
158 defer driver.Delete(ctx, filename)
159 if err != nil {
160 t.Fatalf("driver.Writer: unexpected error: %v", err)
161 }
162 _, err = writer.Write(contents)
163 if err != nil {
164 t.Fatalf("writer.Write: unexpected error: %v", err)
165 }
166 err = writer.Commit()
167 if err != nil {
168 t.Fatalf("writer.Commit: unexpected error: %v", err)
169 }
170 err = writer.Close()
171 if err != nil {
172 t.Fatalf("writer.Close: unexpected error: %v", err)
173 }
174 if writer.Size() != int64(len(contents)) {
175 t.Fatalf("writer.Size: %d != %d", writer.Size(), len(contents))
176 }
177 readContents, err := driver.GetContent(ctx, filename)
178 if err != nil {
179 t.Fatalf("driver.GetContent: unexpected error: %v", err)
180 }
181 if len(readContents) != len(contents) {
182 t.Fatalf("len(driver.GetContent(..)): %d != %d", len(readContents), len(contents))
183 }
184 }
185
186 func TestRetry(t *testing.T) {
187 if skipGCS() != "" {
188 t.Skip(skipGCS())
189 }
190
191 assertError := func(expected string, observed error) {
192 observedMsg := "<nil>"
193 if observed != nil {
194 observedMsg = observed.Error()
195 }
196 if observedMsg != expected {
197 t.Fatalf("expected %v, observed %v\n", expected, observedMsg)
198 }
199 }
200
201 err := retry(func() error {
202 return &googleapi.Error{
203 Code: 503,
204 Message: "google api error",
205 }
206 })
207 assertError("googleapi: Error 503: google api error", err)
208
209 err = retry(func() error {
210 return &googleapi.Error{
211 Code: 404,
212 Message: "google api error",
213 }
214 })
215 assertError("googleapi: Error 404: google api error", err)
216
217 err = retry(func() error {
218 return fmt.Errorf("error")
219 })
220 assertError("error", err)
221 }
222
223 func TestEmptyRootList(t *testing.T) {
224 if skipGCS() != "" {
225 t.Skip(skipGCS())
226 }
227
228 validRoot, err := ioutil.TempDir("", "driver-")
229 if err != nil {
230 t.Fatalf("unexpected error creating temporary directory: %v", err)
231 }
232 defer os.Remove(validRoot)
233
234 rootedDriver, err := gcsDriverConstructor(validRoot)
235 if err != nil {
236 t.Fatalf("unexpected error creating rooted driver: %v", err)
237 }
238
239 emptyRootDriver, err := gcsDriverConstructor("")
240 if err != nil {
241 t.Fatalf("unexpected error creating empty root driver: %v", err)
242 }
243
244 slashRootDriver, err := gcsDriverConstructor("/")
245 if err != nil {
246 t.Fatalf("unexpected error creating slash root driver: %v", err)
247 }
248
249 filename := "/test"
250 contents := []byte("contents")
251 ctx := dcontext.Background()
252 err = rootedDriver.PutContent(ctx, filename, contents)
253 if err != nil {
254 t.Fatalf("unexpected error creating content: %v", err)
255 }
256 defer func() {
257 err := rootedDriver.Delete(ctx, filename)
258 if err != nil {
259 t.Fatalf("failed to remove %v due to %v\n", filename, err)
260 }
261 }()
262 keys, err := emptyRootDriver.List(ctx, "/")
263 if err != nil {
264 t.Fatalf("unexpected error listing empty root content: %v", err)
265 }
266 for _, path := range keys {
267 if !storagedriver.PathRegexp.MatchString(path) {
268 t.Fatalf("unexpected string in path: %q != %q", path, storagedriver.PathRegexp)
269 }
270 }
271
272 keys, err = slashRootDriver.List(ctx, "/")
273 if err != nil {
274 t.Fatalf("unexpected error listing slash root content: %v", err)
275 }
276 for _, path := range keys {
277 if !storagedriver.PathRegexp.MatchString(path) {
278 t.Fatalf("unexpected string in path: %q != %q", path, storagedriver.PathRegexp)
279 }
280 }
281 }
282
283
284 func TestMoveDirectory(t *testing.T) {
285 if skipGCS() != "" {
286 t.Skip(skipGCS())
287 }
288
289 validRoot, err := ioutil.TempDir("", "driver-")
290 if err != nil {
291 t.Fatalf("unexpected error creating temporary directory: %v", err)
292 }
293 defer os.Remove(validRoot)
294
295 driver, err := gcsDriverConstructor(validRoot)
296 if err != nil {
297 t.Fatalf("unexpected error creating rooted driver: %v", err)
298 }
299
300 ctx := dcontext.Background()
301 contents := []byte("contents")
302
303 err = driver.PutContent(ctx, "/parent/dir/foo", contents)
304 if err != nil {
305 t.Fatalf("unexpected error creating content: %v", err)
306 }
307 defer func() {
308 err := driver.Delete(ctx, "/parent")
309 if err != nil {
310 t.Fatalf("failed to remove /parent due to %v\n", err)
311 }
312 }()
313
314 err = driver.Move(ctx, "/parent/dir", "/parent/other")
315 if err == nil {
316 t.Fatalf("Moving directory /parent/dir /parent/other should have return a non-nil error\n")
317 }
318 }
319
View as plain text