1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package storage
16
17 import (
18 "context"
19 "crypto/sha256"
20 "encoding/base64"
21 "errors"
22 "net/http"
23 "strings"
24 "testing"
25
26 "cloud.google.com/go/internal/testutil"
27 "google.golang.org/api/googleapi"
28 "google.golang.org/api/option"
29 )
30
31 var testEncryptionKey = []byte("secret-key-that-is-32-bytes-long")
32
33 func TestErrorOnObjectsInsertCall(t *testing.T) {
34 t.Parallel()
35 ctx := context.Background()
36 const contents = "hello world"
37
38 doWrite := func(mt *mockTransport) *Writer {
39 client := mockClient(t, mt)
40 wc := client.Bucket("bucketname").Object("filename1").If(Conditions{DoesNotExist: true}).NewWriter(ctx)
41 wc.ContentType = "text/plain"
42
43
44
45 wc.Write([]byte(contents))
46 return wc
47 }
48
49 wc := doWrite(&mockTransport{})
50
51
52 if err := wc.Close(); err == nil {
53 t.Errorf("expected error on close, got nil")
54 }
55
56
57 mt := &mockTransport{}
58 mt.addResult(&http.Response{StatusCode: 503, Body: bodyReader("")}, nil)
59 mt.addResult(&http.Response{StatusCode: 200, Body: bodyReader("{}")}, nil)
60
61 wc = doWrite(mt)
62 if err := wc.Close(); err != nil {
63 t.Errorf("got %v, want nil", err)
64 }
65 got := string(mt.gotBody)
66 if !strings.Contains(got, contents) {
67 t.Errorf("got body %q, which does not contain %q", got, contents)
68 }
69 }
70
71 func TestEncryption(t *testing.T) {
72 t.Parallel()
73 ctx := context.Background()
74 mt := &mockTransport{}
75 mt.addResult(&http.Response{StatusCode: 200, Body: bodyReader("{}")}, nil)
76 client := mockClient(t, mt)
77 obj := client.Bucket("bucketname").Object("filename1")
78 wc := obj.Key(testEncryptionKey).NewWriter(ctx)
79 if _, err := wc.Write([]byte("hello world")); err != nil {
80 t.Fatal(err)
81 }
82 if err := wc.Close(); err != nil {
83 t.Fatal(err)
84 }
85 if got, want := mt.gotReq.Header.Get("x-goog-encryption-algorithm"), "AES256"; got != want {
86 t.Errorf("algorithm: got %q, want %q", got, want)
87 }
88 gotKey, err := base64.StdEncoding.DecodeString(mt.gotReq.Header.Get("x-goog-encryption-key"))
89 if err != nil {
90 t.Fatalf("decoding key: %v", err)
91 }
92 if !testutil.Equal(gotKey, testEncryptionKey) {
93 t.Errorf("key: got %v, want %v", gotKey, testEncryptionKey)
94 }
95 wantHash := sha256.Sum256(testEncryptionKey)
96 gotHash, err := base64.StdEncoding.DecodeString(mt.gotReq.Header.Get("x-goog-encryption-key-sha256"))
97 if err != nil {
98 t.Fatalf("decoding hash: %v", err)
99 }
100 if !testutil.Equal(gotHash, wantHash[:]) {
101 t.Errorf("hash: got\n%v, want\n%v", gotHash, wantHash)
102 }
103
104
105 checkKMSError := func(msg string, err error) {
106 if err == nil {
107 t.Errorf("%s: got nil, want error", msg)
108 } else if !strings.Contains(err.Error(), "KMS") {
109 t.Errorf(`%s: got %q, want it to contain "KMS"`, msg, err)
110 }
111 }
112
113 wc = obj.Key(testEncryptionKey).NewWriter(ctx)
114 wc.KMSKeyName = "key"
115 _, err = wc.Write([]byte{})
116 checkKMSError("Write", err)
117 checkKMSError("Close", wc.Close())
118 }
119
120
121
122
123 func TestRaceOnCancelAfterWrite(t *testing.T) {
124 client := mockClient(t, &mockTransport{})
125 cctx, cancel := context.WithCancel(context.Background())
126 w := client.Bucket("b").Object("o").NewWriter(cctx)
127 w.ChunkSize = googleapi.MinUploadChunkSize
128 buf := make([]byte, w.ChunkSize)
129
130
131
132 w.Write(buf)
133
134
135 cancel()
136
137 w.Write([]byte(nil))
138 }
139
140
141
142
143 func TestRaceOnCancelBeforeWrite(t *testing.T) {
144 ctx, cancel := context.WithCancel(context.Background())
145 client := mockClient(t, &mockTransport{})
146 cancel()
147 writer := client.Bucket("foo").Object("bar").NewWriter(ctx)
148 writer.ChunkSize = googleapi.MinUploadChunkSize
149 writer.Write([]byte("data"))
150
151
152
153 if err := writer.Close(); !errors.Is(err, context.Canceled) {
154 t.Errorf("Writer.Close: got %v, want %v", err, context.Canceled)
155 }
156 }
157
158 func TestCancelDoesNotLeak(t *testing.T) {
159 ctx, cancel := context.WithCancel(context.Background())
160 const contents = "hello world"
161 mt := mockTransport{}
162
163 client, err := NewClient(ctx, option.WithHTTPClient(&http.Client{Transport: &mt}))
164 if err != nil {
165 t.Fatal(err)
166 }
167
168 wc := client.Bucket("bucketname").Object("filename1").NewWriter(ctx)
169 wc.ContentType = "text/plain"
170
171
172
173 wc.Write([]byte(contents))
174
175 cancel()
176 }
177
178 func TestCloseDoesNotLeak(t *testing.T) {
179 ctx := context.Background()
180 const contents = "hello world"
181 mt := mockTransport{}
182
183 client, err := NewClient(ctx, option.WithHTTPClient(&http.Client{Transport: &mt}))
184 if err != nil {
185 t.Fatal(err)
186 }
187
188 wc := client.Bucket("bucketname").Object("filename1").NewWriter(ctx)
189 wc.ContentType = "text/plain"
190
191
192
193 wc.Write([]byte(contents))
194
195 wc.Close()
196 }
197
View as plain text