Skip to content

Commit 2254920

Browse files
cojencodanielduhh
andauthored
test(storage): update retry conformance tests for dual transports (#8486)
* test(storage): add dual transport to retry test resource and skip unimplemented * direct to http or grpc client with x-retry-test-id header * replace json with http * remove wrappedClient and rountrip; SetHeaders per test call * update test * skip bidiwrite tests --------- Co-authored-by: Daniel B <danielduhh@gmail.com>
1 parent 8deb9ab commit 2254920

File tree

2 files changed

+60
-86
lines changed

2 files changed

+60
-86
lines changed

storage/internal/test/conformance/retry_tests.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,6 @@
9090
{"name": "storage.objects.compose", "resources": ["BUCKET", "OBJECT"]},
9191
{"name": "storage.objects.copy", "resources": ["BUCKET", "OBJECT"]},
9292
{"name": "storage.objects.delete", "resources": ["BUCKET", "OBJECT"]},
93-
{"name": "storage.objects.insert", "resources": ["BUCKET"]},
9493
{"name": "storage.objects.patch", "resources": ["BUCKET", "OBJECT"]},
9594
{"name": "storage.objects.rewrite", "resources": ["BUCKET", "OBJECT"]},
9695
{"name": "storage.objects.update", "resources": ["BUCKET", "OBJECT"]}

storage/retry_conformance_test.go

Lines changed: 60 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,15 @@ import (
2323
"io"
2424
"io/ioutil"
2525
"net/http"
26-
"net/http/httputil"
2726
"net/url"
2827
"os"
2928
"strings"
3029
"testing"
3130

3231
"cloud.google.com/go/internal/uid"
3332
storage_v1_tests "cloud.google.com/go/storage/internal/test/conformance"
33+
"github.com/googleapis/gax-go/v2/callctx"
3434
"google.golang.org/api/iterator"
35-
"google.golang.org/api/option"
36-
htransport "google.golang.org/api/transport/http"
3735
)
3836

3937
var (
@@ -521,34 +519,43 @@ func TestRetryConformance(t *testing.T) {
521519
t.Logf("No tests for operation %v", methodName)
522520
}
523521
for i, fn := range methods[methodName] {
524-
testName := fmt.Sprintf("%v-%v-%v-%v", retryTest.Id, instructions.Instructions, methodName, i)
525-
t.Run(testName, func(t *testing.T) {
526-
527-
// Create the retry subtest
528-
subtest := &emulatorTest{T: t, name: testName, host: endpoint}
529-
subtest.create(map[string][]string{
530-
method.Name: instructions.Instructions,
531-
})
532-
533-
// Create necessary test resources in the emulator
534-
subtest.populateResources(ctx, client, method.Resources)
535-
536-
// Test
537-
err = fn(ctx, subtest.wrappedClient, &subtest.resources, retryTest.PreconditionProvided)
538-
if retryTest.ExpectSuccess && err != nil {
539-
t.Errorf("want success, got %v", err)
540-
}
541-
if !retryTest.ExpectSuccess && err == nil {
542-
t.Errorf("want failure, got success")
522+
transports := []string{"http", "grpc"}
523+
for _, transport := range transports {
524+
if transport == "grpc" && method.Name == "storage.objects.insert" {
525+
t.Skip("Implementation in testbench pending: https://github.com/googleapis/storage-testbench/issues/568")
543526
}
544-
545-
// Verify that all instructions were used up during the test
546-
// (indicates that the client sent the correct requests).
547-
subtest.check()
548-
549-
// Close out test in emulator.
550-
subtest.delete()
551-
})
527+
testName := fmt.Sprintf("%v-%v-%v-%v-%v", transport, retryTest.Id, instructions.Instructions, methodName, i)
528+
t.Run(testName, func(t *testing.T) {
529+
530+
// Create the retry subtest
531+
subtest := &emulatorTest{T: t, name: testName, host: endpoint}
532+
subtest.create(map[string][]string{
533+
method.Name: instructions.Instructions,
534+
}, transport)
535+
536+
// Create necessary test resources in the emulator
537+
subtest.populateResources(ctx, client, method.Resources)
538+
539+
// Test
540+
// Set retry test id through headers per test call
541+
ctx := context.Background()
542+
ctx = callctx.SetHeaders(ctx, "x-retry-test-id", subtest.id)
543+
err = fn(ctx, subtest.transportClient, &subtest.resources, retryTest.PreconditionProvided)
544+
if retryTest.ExpectSuccess && err != nil {
545+
t.Errorf("want success, got %v", err)
546+
}
547+
if !retryTest.ExpectSuccess && err == nil {
548+
t.Errorf("want failure, got success")
549+
}
550+
551+
// Verify that all instructions were used up during the test
552+
// (indicates that the client sent the correct requests).
553+
subtest.check()
554+
555+
// Close out test in emulator.
556+
subtest.delete()
557+
})
558+
}
552559
}
553560
}
554561
}
@@ -558,11 +565,11 @@ func TestRetryConformance(t *testing.T) {
558565

559566
type emulatorTest struct {
560567
*testing.T
561-
name string
562-
id string // ID to pass as a header in the test execution
563-
resources resources
564-
host *url.URL // set the path when using; path is not guaranteed between calls
565-
wrappedClient *Client
568+
name string
569+
id string // ID to pass as a header in the test execution
570+
resources resources
571+
host *url.URL // set the path when using; path is not guaranteed between calls
572+
transportClient *Client
566573
}
567574

568575
// Holds the resources for a particular test case. Only the necessary fields will
@@ -651,12 +658,14 @@ func uploadTestObject(bucketName, objName string, n []byte) error {
651658
}
652659

653660
// Creates a retry test resource in the emulator
654-
func (et *emulatorTest) create(instructions map[string][]string) {
661+
func (et *emulatorTest) create(instructions map[string][]string, transport string) {
655662
c := http.DefaultClient
656663
data := struct {
657664
Instructions map[string][]string `json:"instructions"`
665+
Transport string `json:"transport"`
658666
}{
659667
Instructions: instructions,
668+
Transport: transport,
660669
}
661670

662671
buf := new(bytes.Buffer)
@@ -666,6 +675,9 @@ func (et *emulatorTest) create(instructions map[string][]string) {
666675

667676
et.host.Path = "retry_test"
668677
resp, err := c.Post(et.host.String(), "application/json", buf)
678+
if resp.StatusCode == 501 {
679+
et.T.Skip("This retry test case is not yet supported in the testbench.")
680+
}
669681
if err != nil || resp.StatusCode != 200 {
670682
et.Fatalf("creating retry test: err: %v, resp: %+v", err, resp)
671683
}
@@ -683,14 +695,21 @@ func (et *emulatorTest) create(instructions map[string][]string) {
683695
}
684696

685697
et.id = testRes.TestID
686-
687-
// Create wrapped client which will send emulator instructions
688698
et.host.Path = ""
689-
client, err := wrappedClient(et.T, et.id)
699+
700+
// Create transportClient for http or grpc
701+
ctx := context.Background()
702+
transportClient, err := NewClient(ctx)
690703
if err != nil {
691-
et.Fatalf("creating wrapped client: %v", err)
704+
et.Fatalf("HTTP transportClient: %v", err)
705+
}
706+
if transport == "grpc" {
707+
transportClient, err = NewGRPCClient(ctx)
708+
if err != nil {
709+
et.Fatalf("GRPC transportClient: %v", err)
710+
}
692711
}
693-
et.wrappedClient = client
712+
et.transportClient = transportClient
694713
}
695714

696715
// Verifies that all instructions for a given retry testID have been used up
@@ -732,47 +751,3 @@ func (et *emulatorTest) delete() {
732751
et.Errorf("deleting test: err: %v, resp: %+v", err, resp)
733752
}
734753
}
735-
736-
// retryTestRoundTripper sends the retry test ID to the emulator with each request
737-
type retryTestRoundTripper struct {
738-
*testing.T
739-
rt http.RoundTripper
740-
testID string
741-
}
742-
743-
func (wt *retryTestRoundTripper) RoundTrip(r *http.Request) (*http.Response, error) {
744-
r.Header.Set("x-retry-test-id", wt.testID)
745-
746-
requestDump, err := httputil.DumpRequest(r, false)
747-
if err != nil {
748-
wt.Logf("error creating request dump: %v", err)
749-
}
750-
751-
resp, err := wt.rt.RoundTrip(r)
752-
if err != nil {
753-
wt.Logf("roundtrip error (may be expected): %v\nrequest: %s", err, requestDump)
754-
}
755-
return resp, err
756-
}
757-
758-
// Create custom client that sends instructions to the storage testbench Retry Test API
759-
func wrappedClient(t *testing.T, testID string) (*Client, error) {
760-
ctx := context.Background()
761-
base := http.DefaultTransport
762-
763-
trans, err := htransport.NewTransport(ctx, base, option.WithoutAuthentication(), option.WithUserAgent("custom-user-agent"))
764-
if err != nil {
765-
return nil, fmt.Errorf("failed to create http client: %v", err)
766-
}
767-
768-
c := http.Client{Transport: trans}
769-
770-
// Add RoundTripper to the created HTTP client
771-
wrappedTrans := &retryTestRoundTripper{rt: c.Transport, testID: testID, T: t}
772-
c.Transport = wrappedTrans
773-
774-
// Supply this client to storage.NewClient
775-
// STORAGE_EMULATOR_HOST takes care of setting the correct endpoint
776-
client, err := NewClient(ctx, option.WithHTTPClient(&c))
777-
return client, err
778-
}

0 commit comments

Comments
 (0)