Im using s3's GetObjectRequest API to get the Request and use it to call Presign API.
type S3Client struct {
client s3iface.S3API
}
type S3API interface {
PutObject(input *s3.PutObjectInput) (*s3.PutObjectOutput, error)
GetObjectRequest(*s3.GetObjectInput) (*request.Request, *s3.GetObjectOutput)
}
type Request interface {
Presign(expire time.Duration) (string, error)
}
func NewS3Client() S3Client {
awsConfig := awstools.AWS{Config: &aws.Config{Region: aws.String("us-west-2")}}
awsSession, _ := awsConfig.Get()
return S3Client{
client: s3.New(awsSession),
}
}
func (s *S3Client) GetPreSignedUrl(bucket string, objectKey string) (string, error) {
req, _ := s.client.GetObjectRequest(&s3.GetObjectInput{
Bucket: aws.String(bucket),
Key: aws.String(objectKey),
})
urlStr, err := req.Presign(30 * 24 * time.Hour)
if err != nil {
return "", err
}
return urlStr, nil
}
Wondering how I can write unit tests for this snippet. So far I have the following but its not working. Would appreciate some help with this.
type MockRequestImpl struct {
request.Request
}
func (m *MockRequestImpl) Presign(input time.Duration) (string, error) {
return preSignFunc(input)
}
type MockS3Client struct {
s3iface.S3API
}
func init() {
s = S3Client{
client: &MockS3Client{},
}
}
func (m *MockS3Client) GetObjectRequest(input *s3.GetObjectInput) (*request.Request, *s3.GetObjectOutput) {
return getObjectFunc(input)
}
func TestS3Service_GetPreSignedUrl(t *testing.T) {
t.Run("should not throw error", func(t *testing.T) {
getObjectFunc = func(input *s3.GetObjectInput) (*request.Request, *s3.GetObjectOutput) {
m := MockRequestImpl{}.Request
return &m, &s3.GetObjectOutput{}
}
preSignFunc = func(expire time.Duration) (string, error) {
return "preSigned", nil
}
url, err := s.GetPreSignedUrl("bucket", "objectKey")
assert.Equal(t, "preSigned", url)
assert.NoError(t, err)
})
}
Getting the following error :
=== RUN TestS3Service_GetPreSignedUrl === RUN TestS3Service_GetPreSignedUrl/should_not_throw_error --- FAIL: TestS3Service_GetPreSignedUrl (0.00s) --- FAIL: TestS3Service_GetPreSignedUrl/should_not_throw_error (0.00s) panic: runtime error: invalid memory address or nil pointer dereference [recovered] panic: runtime error: invalid memory address or nil pointer dereference [signal SIGSEGV: segmentation violation code=0x2 addr=0x0 pc=0x102ca1eb4]
For line urlStr, err := req.Presign(30 * 24 * time.Hour). Guessing req is returned as nil
This is how I was able to successfully mock
GetObjectRequestandPresign.First let's set up our types.
Now let's create a function that creates our custom S3 client.
As you can probably tell at this point, when we make an
AWSClientfor testing, we're going to replace theobjectRequestClientwith a mockobjectRequestClientthat will do what we want.Now let's create our functions that will handle creating a presigned URL to an s3 resource.
The trick here is that we're going to create our own
ObjectRequestsClientthat will implementgetObjectRequestin a way we want it to and return something other than arequest.Requestbecause that needs AWS. It will however return something that looks like arequest.Requestin all the ways that matter which for this case, is conforming to thePresignableinterface.Now testing should be pretty straight forward. I'm using "github.com/stretchr/testify/mock" to make mocking our aws interactions simple. I wrote this very simple test to validate that we can run the function without any AWS interaction.