Skip to content

Commit

Permalink
feat(storage): support force refresh location credentials (#13589)
Browse files Browse the repository at this point in the history
  • Loading branch information
AllanZhengYP authored Jul 30, 2024
1 parent a17ed4d commit ed29226
Show file tree
Hide file tree
Showing 29 changed files with 595 additions and 90 deletions.
60 changes: 30 additions & 30 deletions packages/aws-amplify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -293,31 +293,31 @@
"name": "[Analytics] record (Pinpoint)",
"path": "./dist/esm/analytics/index.mjs",
"import": "{ record }",
"limit": "17.23 kB"
"limit": "17.28 kB"
},
{
"name": "[Analytics] record (Kinesis)",
"path": "./dist/esm/analytics/kinesis/index.mjs",
"import": "{ record }",
"limit": "48.65 kB"
"limit": "48.69 kB"
},
{
"name": "[Analytics] record (Kinesis Firehose)",
"path": "./dist/esm/analytics/kinesis-firehose/index.mjs",
"import": "{ record }",
"limit": "45.81 kB"
"limit": "45.85 kB"
},
{
"name": "[Analytics] record (Personalize)",
"path": "./dist/esm/analytics/personalize/index.mjs",
"import": "{ record }",
"limit": "49.63 kB"
"limit": "49.67 kB"
},
{
"name": "[Analytics] identifyUser (Pinpoint)",
"path": "./dist/esm/analytics/index.mjs",
"import": "{ identifyUser }",
"limit": "15.73 kB"
"limit": "15.79 kB"
},
{
"name": "[Analytics] enable",
Expand All @@ -335,7 +335,7 @@
"name": "[API] generateClient (AppSync)",
"path": "./dist/esm/api/index.mjs",
"import": "{ generateClient }",
"limit": "40.19 kB"
"limit": "40.23 kB"
},
{
"name": "[API] REST API handlers",
Expand All @@ -353,61 +353,61 @@
"name": "[Auth] resetPassword (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ resetPassword }",
"limit": "12.58 kB"
"limit": "12.62 kB"
},
{
"name": "[Auth] confirmResetPassword (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ confirmResetPassword }",
"limit": "12.52 kB"
"limit": "12.56 kB"
},
{
"name": "[Auth] signIn (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ signIn }",
"limit": "30.00 kB"
"limit": "28.78 kB"
},
{
"name": "[Auth] resendSignUpCode (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ resendSignUpCode }",
"limit": "12.53 kB"
"limit": "12.57 kB"
},
{
"name": "[Auth] confirmSignUp (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ confirmSignUp }",
"limit": "31.00 kB"
"limit": "29.40 kB"
},
{
"name": "[Auth] confirmSignIn (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ confirmSignIn }",
"limit": "28.42 kB"
"limit": "28.46 kB"
},
{
"name": "[Auth] updateMFAPreference (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ updateMFAPreference }",
"limit": "11.87 kB"
"limit": "11.92 kB"
},
{
"name": "[Auth] fetchMFAPreference (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ fetchMFAPreference }",
"limit": "11.91 kB"
"limit": "11.94 kB"
},
{
"name": "[Auth] verifyTOTPSetup (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ verifyTOTPSetup }",
"limit": "12.75 kB"
"limit": "12.78 kB"
},
{
"name": "[Auth] updatePassword (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ updatePassword }",
"limit": "12.76 kB"
"limit": "12.80 kB"
},
{
"name": "[Auth] setUpTOTP (Cognito)",
Expand All @@ -419,85 +419,85 @@
"name": "[Auth] updateUserAttributes (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ updateUserAttributes }",
"limit": "11.99 kB"
"limit": "12.03 kB"
},
{
"name": "[Auth] getCurrentUser (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ getCurrentUser }",
"limit": "7.85 kB"
"limit": "7.86 kB"
},
{
"name": "[Auth] confirmUserAttribute (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ confirmUserAttribute }",
"limit": "12.75 kB"
"limit": "12.79 kB"
},
{
"name": "[Auth] signInWithRedirect (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ signInWithRedirect }",
"limit": "21.19 kB"
"limit": "21.21 kB"
},
{
"name": "[Auth] fetchUserAttributes (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ fetchUserAttributes }",
"limit": "11.82 kB"
"limit": "11.86 kB"
},
{
"name": "[Auth] Basic Auth Flow (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ signIn, signOut, fetchAuthSession, confirmSignIn }",
"limit": "30.20 kB"
"limit": "30.23 kB"
},
{
"name": "[Auth] OAuth Auth Flow (Cognito)",
"path": "./dist/esm/auth/index.mjs",
"import": "{ signInWithRedirect, signOut, fetchAuthSession }",
"limit": "21.62 kB"
"limit": "21.64 kB"
},
{
"name": "[Storage] copy (S3)",
"path": "./dist/esm/storage/index.mjs",
"import": "{ copy }",
"limit": "15.24 kB"
"limit": "15.42 kB"
},
{
"name": "[Storage] downloadData (S3)",
"path": "./dist/esm/storage/index.mjs",
"import": "{ downloadData }",
"limit": "15.76 kB"
"limit": "15.93 kB"
},
{
"name": "[Storage] getProperties (S3)",
"path": "./dist/esm/storage/index.mjs",
"import": "{ getProperties }",
"limit": "15.03 kB"
"limit": "15.20 kB"
},
{
"name": "[Storage] getUrl (S3)",
"path": "./dist/esm/storage/index.mjs",
"import": "{ getUrl }",
"limit": "16.09 kB"
"limit": "16.26 kB"
},
{
"name": "[Storage] list (S3)",
"path": "./dist/esm/storage/index.mjs",
"import": "{ list }",
"limit": "15.65 kB"
"limit": "15.82 kB"
},
{
"name": "[Storage] remove (S3)",
"path": "./dist/esm/storage/index.mjs",
"import": "{ remove }",
"limit": "14.88 kB"
"limit": "15.05 kB"
},
{
"name": "[Storage] uploadData (S3)",
"path": "./dist/esm/storage/index.mjs",
"import": "{ uploadData }",
"limit": "20.30 kB"
"limit": "20.48 kB"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { HttpResponse } from '../../../../src/clients';
import { getRetryDecider } from '../../../../src/clients/middleware/retry';
import { isClockSkewError } from '../../../../src/clients/middleware/retry/isClockSkewError';

jest.mock('../../../../src/clients/middleware/retry/isClockSkewError');

const mockIsClockSkewError = jest.mocked(isClockSkewError);

describe('getRetryDecider', () => {
const mockErrorParser = jest.fn();
const mockHttpResponse: HttpResponse = {
statusCode: 200,
headers: {},
body: 'body' as any,
};

beforeEach(() => {
jest.resetAllMocks();
});

it('should handle network errors', async () => {
expect.assertions(2);
const retryDecider = getRetryDecider(mockErrorParser);
const connectionError = Object.assign(new Error(), {
name: 'Network error',
});
const { retryable, isCredentialsExpiredError } = await retryDecider(
mockHttpResponse,
connectionError,
);
expect(retryable).toBe(true);
expect(isCredentialsExpiredError).toBeFalsy();
});

describe('handling throttling errors', () => {
it.each([
'BandwidthLimitExceeded',
'EC2ThrottledException',
'LimitExceededException',
'PriorRequestNotComplete',
'ProvisionedThroughputExceededException',
'RequestLimitExceeded',
'RequestThrottled',
'RequestThrottledException',
'SlowDown',
'ThrottledException',
'Throttling',
'ThrottlingException',
'TooManyRequestsException',
])('should return retryable at %s error', async errorCode => {
expect.assertions(2);
mockErrorParser.mockResolvedValueOnce({
code: errorCode,
});
const retryDecider = getRetryDecider(mockErrorParser);
const { retryable, isCredentialsExpiredError } = await retryDecider(
mockHttpResponse,
undefined,
);
expect(retryable).toBe(true);
expect(isCredentialsExpiredError).toBeFalsy();
});

it('should set retryable for 402 error', async () => {
expect.assertions(2);
const retryDecider = getRetryDecider(mockErrorParser);
const {
retryable,
isCredentialsExpiredError: isInvalidCredentialsError,
} = await retryDecider(
{
...mockHttpResponse,
statusCode: 429,
},
undefined,
);
expect(retryable).toBe(true);
expect(isInvalidCredentialsError).toBeFalsy();
});
});

describe('handling clockskew error', () => {
it.each([{ code: 'ClockSkew' }, { name: 'ClockSkew' }])(
'should handle clockskew error %o',
async parsedError => {
expect.assertions(3);
mockErrorParser.mockResolvedValue(parsedError);
mockIsClockSkewError.mockReturnValue(true);
const retryDecider = getRetryDecider(mockErrorParser);
const { retryable, isCredentialsExpiredError } = await retryDecider(
mockHttpResponse,
undefined,
);
expect(retryable).toBe(true);
expect(isCredentialsExpiredError).toBeFalsy();
expect(mockIsClockSkewError).toHaveBeenCalledWith(
Object.values(parsedError)[0],
);
},
);
});

it.each([500, 502, 503, 504])(
'should handle server-side status code %s',
async statusCode => {
const retryDecider = getRetryDecider(mockErrorParser);
const { retryable, isCredentialsExpiredError } = await retryDecider(
{
...mockHttpResponse,
statusCode,
},
undefined,
);
expect(retryable).toBe(true);
expect(isCredentialsExpiredError).toBeFalsy();
},
);

it.each(['TimeoutError', 'RequestTimeout', 'RequestTimeoutException'])(
'should handle server-side timeout error code %s',
async errorCode => {
expect.assertions(2);
mockErrorParser.mockResolvedValue({ code: errorCode });
const retryDecider = getRetryDecider(mockErrorParser);
const { retryable, isCredentialsExpiredError } = await retryDecider(
mockHttpResponse,
undefined,
);
expect(retryable).toBe(true);
expect(isCredentialsExpiredError).toBeFalsy();
},
);
});
Loading

0 comments on commit ed29226

Please sign in to comment.