From 6c384c5ff55784d031178a9f8216ae1803d19397 Mon Sep 17 00:00:00 2001 From: Chris Cotter Date: Tue, 27 Sep 2022 23:06:13 -0400 Subject: [PATCH] test(storage): dual trans for HMAC / PostPolicyV4 (#6717) Add dual transport tests for HMAC keys and for PostPolicyV4. One PostPolicyV4 test creates a second client with custom key behavior. I split this test into two separate tests, one of which fails for gRPC. I left this as a skip for now since it will require some digging in the constructor creds logic to fix. I also cleaned up some layers of indirection around the various testConfig client methods, and now the multiTransportTest function can take client options to pass down to the client constructors which should make it easier to clean up some other tests which have custom client constructor logic. --- storage/integration_test.go | 606 +++++++++++++++++++----------------- 1 file changed, 316 insertions(+), 290 deletions(-) diff --git a/storage/integration_test.go b/storage/integration_test.go index e6e64316df5..db2a1e1b187 100644 --- a/storage/integration_test.go +++ b/storage/integration_test.go @@ -186,7 +186,10 @@ func initIntegrationTest() func() error { cleanup = cleanupBuckets } ctx := context.Background() - client := config(ctx) + client, err := newTestClient(ctx) + if err != nil { + log.Fatalf("NewClient: %v", err) + } if client == nil { return func() error { return nil } } @@ -216,11 +219,14 @@ func initUIDsAndRand(t time.Time) { // testConfig returns the Client used to access GCS. testConfig skips // the current test if credentials are not available or when being run // in Short mode. -func testConfig(ctx context.Context, t *testing.T, scopes ...string) *Client { +func testConfig(ctx context.Context, t *testing.T, opts ...option.ClientOption) *Client { if testing.Short() && !replaying { t.Skip("Integration tests skipped in short mode") } - client := config(ctx, scopes...) + client, err := newTestClient(ctx, opts...) + if err != nil { + t.Fatalf("NewClient: %v", err) + } if client == nil { t.Skip("Integration tests skipped. See CONTRIBUTING.md for details") } @@ -229,12 +235,12 @@ func testConfig(ctx context.Context, t *testing.T, scopes ...string) *Client { // testConfigGPRC returns a gRPC-based client to access GCS. testConfigGRPC // skips the curent test when being run in Short mode. -func testConfigGRPC(ctx context.Context, t *testing.T) (gc *Client) { +func testConfigGRPC(ctx context.Context, t *testing.T, opts ...option.ClientOption) (gc *Client) { if testing.Short() { t.Skip("Integration tests skipped in short mode") } - gc, err := newGRPCClient(ctx) + gc, err := newGRPCClient(ctx, opts...) if err != nil { t.Fatalf("newHybridClient: %v", err) } @@ -243,10 +249,10 @@ func testConfigGRPC(ctx context.Context, t *testing.T) (gc *Client) { } // initTransportClients initializes Storage clients for each supported transport. -func initTransportClients(ctx context.Context, t *testing.T) map[string]*Client { +func initTransportClients(ctx context.Context, t *testing.T, opts ...option.ClientOption) map[string]*Client { return map[string]*Client{ - "http": testConfig(ctx, t), - "grpc": testConfigGRPC(ctx, t), + "http": testConfig(ctx, t, opts...), + "grpc": testConfigGRPC(ctx, t, opts...), } } @@ -255,8 +261,10 @@ func initTransportClients(ctx context.Context, t *testing.T) map[string]*Client // test function with the sub-test instance, the context it was given, the name // of an existing bucket to use, a bucket name to use for bucket creation, and // the client to use. -func multiTransportTest(ctx context.Context, t *testing.T, test func(*testing.T, context.Context, string, string, *Client)) { - for transport, client := range initTransportClients(ctx, t) { +func multiTransportTest(ctx context.Context, t *testing.T, + test func(*testing.T, context.Context, string, string, *Client), + opts ...option.ClientOption) { + for transport, client := range initTransportClients(ctx, t, opts...) { t.Run(transport, func(t *testing.T) { defer client.Close() @@ -276,20 +284,6 @@ func multiTransportTest(ctx context.Context, t *testing.T, test func(*testing.T, } } -// config is like testConfig, but it doesn't need a *testing.T. -func config(ctx context.Context, scopes ...string) *Client { - scopes = append(scopes, ScopeFullControl) - ts := testutil.TokenSource(ctx, scopes...) - if ts == nil { - return nil - } - client, err := newTestClient(ctx, option.WithTokenSource(ts)) - if err != nil { - log.Fatalf("NewClient: %v", err) - } - return client -} - func TestIntegration_BucketCreateDelete(t *testing.T) { multiTransportTest(skipGRPC("with_attrs case fails due to b/245997450"), t, func(t *testing.T, ctx context.Context, _ string, prefix string, client *Client) { projectID := testutil.ProjID() @@ -4181,173 +4175,170 @@ func TestIntegration_NewReaderWithContentEncodingGzip(t *testing.T) { } func TestIntegration_HMACKey(t *testing.T) { - ctx := context.Background() - client := testConfig(ctx, t) - defer client.Close() - client.SetRetry(WithPolicy(RetryAlways)) + multiTransportTest(context.Background(), t, func(t *testing.T, ctx context.Context, _, _ string, client *Client) { + client.SetRetry(WithPolicy(RetryAlways)) - projectID := testutil.ProjID() + projectID := testutil.ProjID() - // Use the service account email from the user's credentials. Requires that the - // credentials are set via a JSON credentials file. - // Note that a service account may only have up to 5 active HMAC keys at once; if - // we see flakes because of this, we should consider switching to using a project - // pool. - credentials := testutil.CredentialsEnv(ctx, "GCLOUD_TESTS_GOLANG_KEY") - if credentials == nil { - t.Fatal("credentials could not be determined, is GCLOUD_TESTS_GOLANG_KEY set correctly?") - } - if credentials.JSON == nil { - t.Fatal("could not read the JSON key file, is GCLOUD_TESTS_GOLANG_KEY set correctly?") - } - conf, err := google.JWTConfigFromJSON(credentials.JSON) - if err != nil { - t.Fatal(err) - } - serviceAccountEmail := conf.Email + // Use the service account email from the user's credentials. Requires that the + // credentials are set via a JSON credentials file. + // Note that a service account may only have up to 5 active HMAC keys at once; if + // we see flakes because of this, we should consider switching to using a project + // pool. + credentials := testutil.CredentialsEnv(ctx, "GCLOUD_TESTS_GOLANG_KEY") + if credentials == nil { + t.Fatal("credentials could not be determined, is GCLOUD_TESTS_GOLANG_KEY set correctly?") + } + if credentials.JSON == nil { + t.Fatal("could not read the JSON key file, is GCLOUD_TESTS_GOLANG_KEY set correctly?") + } + conf, err := google.JWTConfigFromJSON(credentials.JSON) + if err != nil { + t.Fatal(err) + } + serviceAccountEmail := conf.Email - hmacKey, err := client.CreateHMACKey(ctx, projectID, serviceAccountEmail) - if err != nil { - t.Fatalf("Failed to create HMACKey: %v", err) - } - if hmacKey == nil { - t.Fatal("Unexpectedly got back a nil HMAC key") - } + hmacKey, err := client.CreateHMACKey(ctx, projectID, serviceAccountEmail) + if err != nil { + t.Fatalf("Failed to create HMACKey: %v", err) + } + if hmacKey == nil { + t.Fatal("Unexpectedly got back a nil HMAC key") + } - if hmacKey.State != Active { - t.Fatalf("Unexpected state %q, expected %q", hmacKey.State, Active) - } + if hmacKey.State != Active { + t.Fatalf("Unexpected state %q, expected %q", hmacKey.State, Active) + } - hkh := client.HMACKeyHandle(projectID, hmacKey.AccessID) - // 1. Ensure that we CANNOT delete an ACTIVE key. - if err := hkh.Delete(ctx); err == nil { - t.Fatal("Unexpectedly deleted key whose state is ACTIVE: No error from Delete.") - } + hkh := client.HMACKeyHandle(projectID, hmacKey.AccessID) + // 1. Ensure that we CANNOT delete an ACTIVE key. + if err := hkh.Delete(ctx); err == nil { + t.Fatal("Unexpectedly deleted key whose state is ACTIVE: No error from Delete.") + } - invalidStates := []HMACState{"", Deleted, "active", "inactive", "foo_bar"} - for _, invalidState := range invalidStates { - t.Run("invalid-"+string(invalidState), func(t *testing.T) { - _, err := hkh.Update(ctx, HMACKeyAttrsToUpdate{ - State: invalidState, + invalidStates := []HMACState{"", Deleted, "active", "inactive", "foo_bar"} + for _, invalidState := range invalidStates { + t.Run("invalid-"+string(invalidState), func(t *testing.T) { + _, err := hkh.Update(ctx, HMACKeyAttrsToUpdate{ + State: invalidState, + }) + if err == nil { + t.Fatal("Unexpectedly succeeded") + } + invalidStateMsg := fmt.Sprintf(`storage: invalid state %q for update, must be either "ACTIVE" or "INACTIVE"`, invalidState) + if err.Error() != invalidStateMsg { + t.Fatalf("Mismatched error: got: %q\nwant: %q", err, invalidStateMsg) + } }) - if err == nil { - t.Fatal("Unexpectedly succeeded") - } - invalidStateMsg := fmt.Sprintf(`storage: invalid state %q for update, must be either "ACTIVE" or "INACTIVE"`, invalidState) - if err.Error() != invalidStateMsg { - t.Fatalf("Mismatched error: got: %q\nwant: %q", err, invalidStateMsg) - } - }) - } + } - // 2.1. Setting the State to Inactive should succeed. - hu, err := hkh.Update(ctx, HMACKeyAttrsToUpdate{ - State: Inactive, - }) - if err != nil { - t.Fatalf("Unexpected Update failure: %v", err) - } - if got, want := hu.State, Inactive; got != want { - t.Fatalf("Unexpected updated state %q, expected %q", got, want) - } + // 2.1. Setting the State to Inactive should succeed. + hu, err := hkh.Update(ctx, HMACKeyAttrsToUpdate{ + State: Inactive, + }) + if err != nil { + t.Fatalf("Unexpected Update failure: %v", err) + } + if got, want := hu.State, Inactive; got != want { + t.Fatalf("Unexpected updated state %q, expected %q", got, want) + } - // 2.2. Setting the State back to Active should succeed. - hu, err = hkh.Update(ctx, HMACKeyAttrsToUpdate{ - State: Active, - }) - if err != nil { - t.Fatalf("Unexpected Update failure: %v", err) - } - if got, want := hu.State, Active; got != want { - t.Fatalf("Unexpected updated state %q, expected %q", got, want) - } + // 2.2. Setting the State back to Active should succeed. + hu, err = hkh.Update(ctx, HMACKeyAttrsToUpdate{ + State: Active, + }) + if err != nil { + t.Fatalf("Unexpected Update failure: %v", err) + } + if got, want := hu.State, Active; got != want { + t.Fatalf("Unexpected updated state %q, expected %q", got, want) + } - // 3. Verify that keys are listed as expected. - iter := client.ListHMACKeys(ctx, projectID) - count := 0 - for ; ; count++ { - _, err := iter.Next() - if err == iterator.Done { - break + // 3. Verify that keys are listed as expected. + iter := client.ListHMACKeys(ctx, projectID) + count := 0 + for ; ; count++ { + _, err := iter.Next() + if err == iterator.Done { + break + } + if err != nil { + t.Fatalf("Failed to ListHMACKeys: %v", err) + } } - if err != nil { - t.Fatalf("Failed to ListHMACKeys: %v", err) + if count == 0 { + t.Fatal("Failed to list any HMACKeys") } - } - if count == 0 { - t.Fatal("Failed to list any HMACKeys") - } - // 4. Finally set it to back to Inactive and - // then retry the deletion which should now succeed. - _, _ = hkh.Update(ctx, HMACKeyAttrsToUpdate{ - State: Inactive, - }) - if err := hkh.Delete(ctx); err != nil { - t.Fatalf("Unexpected deletion failure: %v", err) - } + // 4. Finally set it to back to Inactive and + // then retry the deletion which should now succeed. + _, _ = hkh.Update(ctx, HMACKeyAttrsToUpdate{ + State: Inactive, + }) + if err := hkh.Delete(ctx); err != nil { + t.Fatalf("Unexpected deletion failure: %v", err) + } - _, err = hkh.Get(ctx) - if err != nil && !strings.Contains(err.Error(), "404") { - // If the deleted key has already been garbage collected, a 404 is expected. - // Other errors should cause a failure and are not expected. - t.Fatalf("Unexpected error: %v", err) - } + _, err = hkh.Get(ctx) + if err != nil && !strings.Contains(err.Error(), "404") { + // If the deleted key has already been garbage collected, a 404 is expected. + // Other errors should cause a failure and are not expected. + t.Fatalf("Unexpected error: %v", err) + } + }) } func TestIntegration_PostPolicyV4(t *testing.T) { - jwtConf, err := testutil.JWTConfig() - if err != nil { - t.Fatal(err) - } - if jwtConf == nil { - t.Skip("JSON key file is not present") - } - - ctx := context.Background() - client := testConfig(ctx, t) - defer client.Close() + multiTransportTest(context.Background(), t, func(t *testing.T, ctx context.Context, _, prefix string, client *Client) { + jwtConf, err := testutil.JWTConfig() + if err != nil { + t.Fatal(err) + } + if jwtConf == nil { + t.Skip("JSON key file is not present") + } - projectID := testutil.ProjID() - newBucketName := uidSpace.New() - b := client.Bucket(newBucketName) - h := testHelper{t} - h.mustCreate(b, projectID, nil) - defer h.mustDeleteBucket(b) + projectID := testutil.ProjID() + newBucketName := prefix + uidSpace.New() + b := client.Bucket(newBucketName) + h := testHelper{t} + h.mustCreate(b, projectID, nil) + defer h.mustDeleteBucket(b) - statusCodeToRespond := 200 - opts := &PostPolicyV4Options{ - GoogleAccessID: jwtConf.Email, - PrivateKey: jwtConf.PrivateKey, + statusCodeToRespond := 200 + opts := &PostPolicyV4Options{ + GoogleAccessID: jwtConf.Email, + PrivateKey: jwtConf.PrivateKey, - Expires: time.Now().Add(30 * time.Minute), + Expires: time.Now().Add(30 * time.Minute), - Fields: &PolicyV4Fields{ - StatusCodeOnSuccess: statusCodeToRespond, - ContentType: "text/plain", - ACL: "public-read", - }, + Fields: &PolicyV4Fields{ + StatusCodeOnSuccess: statusCodeToRespond, + ContentType: "text/plain", + ACL: "public-read", + }, - // The conditions that the uploaded file will be expected to conform to. - Conditions: []PostPolicyV4Condition{ - // Make the file a maximum of 10mB. - ConditionContentLengthRange(0, 10<<20), - ConditionStartsWith("$acl", "public"), - }, - } + // The conditions that the uploaded file will be expected to conform to. + Conditions: []PostPolicyV4Condition{ + // Make the file a maximum of 10mB. + ConditionContentLengthRange(0, 10<<20), + ConditionStartsWith("$acl", "public"), + }, + } - objectName := uidSpace.New() - object := b.Object(objectName) - defer h.mustDeleteObject(object) + objectName := uidSpace.New() + object := b.Object(objectName) + defer h.mustDeleteObject(object) - pv4, err := b.GenerateSignedPostPolicyV4(objectName, opts) - if err != nil { - t.Fatal(err) - } + pv4, err := b.GenerateSignedPostPolicyV4(objectName, opts) + if err != nil { + t.Fatal(err) + } - if err := verifyPostPolicy(pv4, object, bytes.Repeat([]byte("a"), 25), statusCodeToRespond); err != nil { - t.Fatal(err) - } + if err := verifyPostPolicy(pv4, object, bytes.Repeat([]byte("a"), 25), statusCodeToRespond); err != nil { + t.Fatal(err) + } + }) } // Verify that custom scopes passed in by the user are applied correctly. @@ -4394,7 +4385,13 @@ func TestIntegration_SignedURL_Bucket(t *testing.T) { defer clientWithCredentials.Close() // Create another client to test the sign byte function as well - clientWithoutPrivateKey := testConfig(ctx, t, ScopeFullControl, "https://www.googleapis.com/auth/cloud-platform") + + scopes := []string{ScopeFullControl, "https://www.googleapis.com/auth/cloud-platform"} + ts := testutil.TokenSource(ctx, scopes...) + if ts == nil { + t.Fatalf("Cannot get token source to create client") + } + clientWithoutPrivateKey := testConfig(ctx, t, option.WithTokenSource(ts)) defer clientWithoutPrivateKey.Close() jwt, err := testutil.JWTConfig() @@ -4446,158 +4443,184 @@ func TestIntegration_SignedURL_Bucket(t *testing.T) { } } -func TestIntegration_PostPolicyV4_Bucket(t *testing.T) { - h := testHelper{t} +func TestIntegration_PostPolicyV4_WithCreds(t *testing.T) { ctx := context.Background() - - if testing.Short() && !replaying { - t.Skip("Integration tests skipped in short mode") - } - - // We explictly send the key to the client to sign with the private key - clientWithCredentials := newTestClientWithExplicitCredentials(ctx, t) - defer clientWithCredentials.Close() - - // Create another client to test the sign byte function as well - clientWithoutPrivateKey := testConfig(ctx, t, ScopeFullControl, "https://www.googleapis.com/auth/cloud-platform") - defer clientWithoutPrivateKey.Close() - - jwt, err := testutil.JWTConfig() + // By default we are authed with a token source, so don't have the context to + // read some of the fields from the keyfile. + // Here we explictly send the key to the client. + creds, err := findTestCredentials(ctx, "GCLOUD_TESTS_GOLANG_KEY", ScopeFullControl, "https://www.googleapis.com/auth/cloud-platform") if err != nil { t.Fatalf("unable to find test credentials: %v", err) } - statusCodeToRespond := 200 + multiTransportTest(skipGRPC("creds capture logic must be implemented for gRPC constructor"), + t, func(t *testing.T, ctx context.Context, bucket, _ string, clientWithCredentials *Client) { + h := testHelper{t} - for _, test := range []struct { - desc string - opts PostPolicyV4Options - client *Client - }{ - { - desc: "signing with the private key", - opts: PostPolicyV4Options{ - Expires: time.Now().Add(30 * time.Minute), + statusCodeToRespond := 200 - Fields: &PolicyV4Fields{ - StatusCodeOnSuccess: statusCodeToRespond, - ContentType: "text/plain", - ACL: "public-read", + for _, test := range []struct { + desc string + opts PostPolicyV4Options + client *Client + }{ + { + desc: "signing with the private key", + opts: PostPolicyV4Options{ + Expires: time.Now().Add(30 * time.Minute), + + Fields: &PolicyV4Fields{ + StatusCodeOnSuccess: statusCodeToRespond, + ContentType: "text/plain", + ACL: "public-read", + }, + }, + client: clientWithCredentials, }, - }, - client: clientWithCredentials, - }, - { - desc: "signing with the default sign bytes func", - opts: PostPolicyV4Options{ - Expires: time.Now().Add(30 * time.Minute), - GoogleAccessID: jwt.Email, - Fields: &PolicyV4Fields{ - StatusCodeOnSuccess: statusCodeToRespond, - ContentType: "text/plain", - ACL: "public-read", + } { + t.Run(test.desc, func(t *testing.T) { + objectName := uidSpace.New() + object := test.client.Bucket(bucket).Object(objectName) + defer h.mustDeleteObject(object) + + pv4, err := test.client.Bucket(bucket).GenerateSignedPostPolicyV4(objectName, &test.opts) + if err != nil { + t.Fatal(err) + } + + if err := verifyPostPolicy(pv4, object, bytes.Repeat([]byte("a"), 25), statusCodeToRespond); err != nil { + t.Fatal(err) + } + }) + } + }, option.WithCredentials(creds)) + +} + +func TestIntegration_PostPolicyV4_BucketDefault(t *testing.T) { + multiTransportTest(context.Background(), t, func(t *testing.T, ctx context.Context, bucket, _ string, clientWithoutPrivateKey *Client) { + h := testHelper{t} + + jwt, err := testutil.JWTConfig() + if err != nil { + t.Fatalf("unable to find test credentials: %v", err) + } + + statusCodeToRespond := 200 + + for _, test := range []struct { + desc string + opts PostPolicyV4Options + client *Client + }{ + { + desc: "signing with the default sign bytes func", + opts: PostPolicyV4Options{ + Expires: time.Now().Add(30 * time.Minute), + GoogleAccessID: jwt.Email, + Fields: &PolicyV4Fields{ + StatusCodeOnSuccess: statusCodeToRespond, + ContentType: "text/plain", + ACL: "public-read", + }, }, + client: clientWithoutPrivateKey, }, - client: clientWithoutPrivateKey, - }, - } { - t.Run(test.desc, func(t *testing.T) { - objectName := uidSpace.New() - object := test.client.Bucket(bucketName).Object(objectName) - defer h.mustDeleteObject(object) + } { + t.Run(test.desc, func(t *testing.T) { + objectName := uidSpace.New() + object := test.client.Bucket(bucket).Object(objectName) + defer h.mustDeleteObject(object) - pv4, err := test.client.Bucket(bucketName).GenerateSignedPostPolicyV4(objectName, &test.opts) - if err != nil { - t.Fatal(err) - } + pv4, err := test.client.Bucket(bucket).GenerateSignedPostPolicyV4(objectName, &test.opts) + if err != nil { + t.Fatal(err) + } + + if err := verifyPostPolicy(pv4, object, bytes.Repeat([]byte("a"), 25), statusCodeToRespond); err != nil { + t.Fatal(err) + } + }) + } + }) - if err := verifyPostPolicy(pv4, object, bytes.Repeat([]byte("a"), 25), statusCodeToRespond); err != nil { - t.Fatal(err) - } - }) - } } // Tests that the same SignBytes function works for both // SignRawBytes on GeneratePostPolicyV4 and SignBytes on SignedURL func TestIntegration_PostPolicyV4_SignedURL_WithSignBytes(t *testing.T) { - ctx := context.Background() - - if testing.Short() && !replaying { - t.Skip("Integration tests skipped in short mode") - } + multiTransportTest(context.Background(), t, func(t *testing.T, ctx context.Context, _, prefix string, client *Client) { - client := testConfig(ctx, t) - defer client.Close() + h := testHelper{t} + projectID := testutil.ProjID() + bucketName := prefix + uidSpace.New() + objectName := uidSpace.New() + fileBody := bytes.Repeat([]byte("b"), 25) + bucket := client.Bucket(bucketName) - h := testHelper{t} - projectID := testutil.ProjID() - bucketName := uidSpace.New() - objectName := uidSpace.New() - fileBody := bytes.Repeat([]byte("b"), 25) - bucket := client.Bucket(bucketName) + h.mustCreate(bucket, projectID, nil) + defer h.mustDeleteBucket(bucket) - h.mustCreate(bucket, projectID, nil) - defer h.mustDeleteBucket(bucket) + object := bucket.Object(objectName) + defer h.mustDeleteObject(object) - object := bucket.Object(objectName) - defer h.mustDeleteObject(object) + jwtConf, err := testutil.JWTConfig() + if err != nil { + t.Fatal(err) + } + if jwtConf == nil { + t.Skip("JSON key file is not present") + } - jwtConf, err := testutil.JWTConfig() - if err != nil { - t.Fatal(err) - } - if jwtConf == nil { - t.Skip("JSON key file is not present") - } + signingFunc := func(b []byte) ([]byte, error) { + parsedRSAPrivKey, err := parseKey(jwtConf.PrivateKey) + if err != nil { + return nil, err + } + sum := sha256.Sum256(b) + return rsa.SignPKCS1v15(cryptorand.Reader, parsedRSAPrivKey, crypto.SHA256, sum[:]) + } + + // Test Post Policy + successStatusCode := 200 + ppv4Opts := &PostPolicyV4Options{ + GoogleAccessID: jwtConf.Email, + SignRawBytes: signingFunc, + Expires: time.Now().Add(30 * time.Minute), + Fields: &PolicyV4Fields{ + StatusCodeOnSuccess: successStatusCode, + ContentType: "text/plain", + ACL: "public-read", + }, + } - signingFunc := func(b []byte) ([]byte, error) { - parsedRSAPrivKey, err := parseKey(jwtConf.PrivateKey) + pv4, err := GenerateSignedPostPolicyV4(bucketName, objectName, ppv4Opts) if err != nil { - return nil, err + t.Fatal(err) } - sum := sha256.Sum256(b) - return rsa.SignPKCS1v15(cryptorand.Reader, parsedRSAPrivKey, crypto.SHA256, sum[:]) - } - - // Test Post Policy - successStatusCode := 200 - ppv4Opts := &PostPolicyV4Options{ - GoogleAccessID: jwtConf.Email, - SignRawBytes: signingFunc, - Expires: time.Now().Add(30 * time.Minute), - Fields: &PolicyV4Fields{ - StatusCodeOnSuccess: successStatusCode, - ContentType: "text/plain", - ACL: "public-read", - }, - } - pv4, err := GenerateSignedPostPolicyV4(bucketName, objectName, ppv4Opts) - if err != nil { - t.Fatal(err) - } + if err := verifyPostPolicy(pv4, object, fileBody, successStatusCode); err != nil { + t.Fatal(err) + } - if err := verifyPostPolicy(pv4, object, fileBody, successStatusCode); err != nil { - t.Fatal(err) - } + // Test Signed URL + signURLOpts := &SignedURLOptions{ + GoogleAccessID: jwtConf.Email, + SignBytes: signingFunc, + Method: "GET", + Expires: time.Now().Add(30 * time.Second), + } - // Test Signed URL - signURLOpts := &SignedURLOptions{ - GoogleAccessID: jwtConf.Email, - SignBytes: signingFunc, - Method: "GET", - Expires: time.Now().Add(30 * time.Second), - } + url, err := bucket.SignedURL(objectName, signURLOpts) + if err != nil { + t.Fatalf("unable to create signed URL: %v", err) + } - url, err := bucket.SignedURL(objectName, signURLOpts) - if err != nil { - t.Fatalf("unable to create signed URL: %v", err) - } + if err := verifySignedURL(url, nil, fileBody); err != nil { + t.Fatal(err) + } + }) - if err := verifySignedURL(url, nil, fileBody); err != nil { - t.Fatal(err) - } } // verifySignedURL gets the bytes at the provided url and verifies them against the @@ -4850,7 +4873,10 @@ func cleanupBuckets() error { return nil // Don't clean up in short mode. } ctx := context.Background() - client := config(ctx) + client, err := newTestClient(ctx) + if err != nil { + log.Fatalf("NewClient: %v", err) + } if client == nil { return nil // Don't cleanup if we're not configured correctly. }