github.com/release-engineering/exodus-rsync@v1.11.2/internal/gw/s3_helpers_test.go (about) 1 package gw 2 3 import ( 4 "context" 5 "sync" 6 "testing" 7 8 "github.com/aws/aws-sdk-go/aws/awserr" 9 "github.com/aws/aws-sdk-go/aws/request" 10 "github.com/aws/aws-sdk-go/service/s3" 11 ) 12 13 type blobMap map[string][]error 14 15 type fakeS3 struct { 16 t *testing.T 17 mu sync.Mutex 18 19 blobs blobMap 20 } 21 22 func newFakeS3(t *testing.T, client *client) *fakeS3 { 23 out := fakeS3{t: t, blobs: make(blobMap)} 24 25 out.install(client) 26 27 return &out 28 } 29 30 func (f *fakeS3) reset() { 31 f.blobs = make(blobMap) 32 } 33 34 func (f *fakeS3) install(client *client) { 35 handlers := &client.s3.Client.Handlers 36 37 // Clear all default handlers, preventing requests from 38 // actually being sent or parsed. 39 handlers.Clear() 40 41 // This handler is invoked to unpack the response from AWS into 42 // an output object and is an appropriate place to hook in our own logic. 43 handlers.Unmarshal.PushBack(f.unmarshal) 44 } 45 46 func (f *fakeS3) unmarshal(r *request.Request) { 47 switch v := r.Params.(type) { 48 case *s3.HeadObjectInput: 49 f.headObject(r, v) 50 case *s3.PutObjectInput: 51 f.putObject(r, v) 52 default: 53 r.Error = awserr.New("NotImplemented", "not supported by fake S3", nil) 54 } 55 } 56 57 func (f *fakeS3) headObject(r *request.Request, input *s3.HeadObjectInput) { 58 f.mu.Lock() 59 defer f.mu.Unlock() 60 61 errors, haveBlob := f.blobs[*input.Key] 62 if !haveBlob { 63 r.Error = awserr.New("NotFound", "object not found", nil) 64 return 65 } 66 67 if errors == nil || len(errors) == 0 { 68 // No specific instructions for this blob, don't need to do anything. 69 return 70 } 71 72 // Pop the next error. 73 err := errors[0] 74 f.blobs[*input.Key] = errors[1:] 75 76 if err != nil { 77 r.Error = err 78 } 79 } 80 81 func (f *fakeS3) putObject(r *request.Request, input *s3.PutObjectInput) { 82 f.mu.Lock() 83 defer f.mu.Unlock() 84 85 errors, haveBlob := f.blobs[*input.Key] 86 if !haveBlob { 87 // Mark that we have this blob, and don't return any errors for it. 88 f.blobs[*input.Key] = make([]error, 0) 89 } 90 91 if errors == nil || len(errors) == 0 { 92 // No specific instructions for this blob, write succeeds 93 return 94 } 95 96 // Pop the next error. 97 err := errors[0] 98 f.blobs[*input.Key] = errors[1:] 99 100 if err != nil { 101 r.Error = err 102 } 103 } 104 105 func newClientWithFakeS3(t *testing.T) (*client, *fakeS3) { 106 cfg := testConfig(t) 107 108 iface, err := Package.NewClient(context.Background(), cfg) 109 if err != nil { 110 t.Fatal("creating client:", err) 111 } 112 113 out := iface.(*client) 114 115 return out, newFakeS3(t, out) 116 }