| // Copyright 2023 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| package storage |
| |
| import ( |
| "context" |
| "fmt" |
| "io" |
| "net/http" |
| "strings" |
| "testing" |
| |
| "github.com/googleapis/gax-go/v2/callctx" |
| "google.golang.org/api/option" |
| ) |
| |
| // Tests that sending a custom header via the context works as expected |
| // for a few different ops. |
| func TestCustomHeaders(t *testing.T) { |
| var cases = []struct { |
| name string |
| call func(ctx context.Context, client *Client) error |
| resp *http.Response |
| opts []option.ClientOption |
| wantURL string |
| }{ |
| { |
| name: "Metadata op", |
| call: func(ctx context.Context, client *Client) error { |
| _, err := client.Bucket("my-bucket").Attrs(ctx) |
| return err |
| }, |
| resp: &http.Response{ |
| StatusCode: 200, |
| Body: bodyReader(`{"name":"my-bucket"}`), |
| }, |
| wantURL: "https://storage.googleapis.com/storage/v1/b/my-bucket?alt=json&prettyPrint=false&projection=full", |
| }, |
| { |
| name: "Writer", |
| call: func(ctx context.Context, client *Client) error { |
| w := client.Bucket("my-bucket").Object("my-object").NewWriter(ctx) |
| if _, err := io.Copy(w, strings.NewReader("object data")); err != nil { |
| return fmt.Errorf("io.Copy: %w", err) |
| } |
| return w.Close() |
| }, |
| resp: &http.Response{ |
| StatusCode: 200, |
| Body: bodyReader(`{"name": "my-object"}`), |
| }, |
| wantURL: "https://storage.googleapis.com/upload/storage/v1/b/my-bucket/o?alt=json&name=my-object&prettyPrint=false&projection=full&uploadType=multipart", |
| }, |
| { |
| name: "Reader XML", |
| call: func(ctx context.Context, client *Client) error { |
| r, err := client.Bucket("my-bucket").Object("my-object").NewReader(ctx) |
| if err != nil { |
| return fmt.Errorf("NewReader: %w", err) |
| } |
| if _, err := io.Copy(io.Discard, r); err != nil { |
| return fmt.Errorf("io.Copy: %w", err) |
| } |
| return r.Close() |
| }, |
| resp: &http.Response{ |
| StatusCode: 200, |
| Body: bodyReader("object data"), |
| }, |
| opts: []option.ClientOption{WithXMLReads()}, |
| wantURL: "https://storage.googleapis.com/my-bucket/my-object", |
| }, |
| { |
| name: "Reader JSON", |
| call: func(ctx context.Context, client *Client) error { |
| r, err := client.Bucket("my-bucket").Object("my-object").NewReader(ctx) |
| if err != nil { |
| return fmt.Errorf("NewReader: %w", err) |
| } |
| if _, err := io.Copy(io.Discard, r); err != nil { |
| return fmt.Errorf("io.Copy: %w", err) |
| } |
| return r.Close() |
| }, |
| resp: &http.Response{ |
| StatusCode: 200, |
| Body: bodyReader("object data"), |
| }, |
| opts: []option.ClientOption{WithJSONReads()}, |
| wantURL: "https://storage.googleapis.com/storage/v1/b/my-bucket/o/my-object?alt=media&prettyPrint=false&projection=full", |
| }, |
| } |
| for _, c := range cases { |
| t.Run(c.name, func(r *testing.T) { |
| mt := &mockTransport{} |
| client := mockClient(t, mt, c.opts...) |
| |
| key := "x-goog-custom-audit-foo" |
| value := "bar" |
| ctx := callctx.SetHeaders(context.Background(), key, value) |
| |
| mt.addResult(c.resp, nil) |
| if err := c.call(ctx, client); err != nil { |
| r.Fatal(err) |
| } |
| if gotURL := mt.gotReq.URL.String(); gotURL != c.wantURL { |
| r.Errorf("Got URL %v, want %v", gotURL, c.wantURL) |
| } |
| if gotValue := mt.gotReq.Header.Get(key); gotValue != value { |
| r.Errorf("Got headers %v, want to contain %q: %q", mt.gotReq.Header, key, value) |
| } |
| }) |
| } |
| |
| } |