-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
…eam action table and test
- Loading branch information
1 parent
19fb7f6
commit ffe1a90
Showing
22 changed files
with
798 additions
and
229 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ import { | |
useCreatePolicyMutation, | ||
usePutObjectMutation, | ||
usePutBucketTaggingMutation, | ||
useCreateUserAccessKeyMutation, | ||
} from './mutations'; | ||
import { NewWrapper, TEST_API_BASE_URL } from '../react/utils/testUtil'; | ||
import { | ||
|
@@ -17,15 +18,16 @@ import { | |
VEEAM_IMMUTABLE_POLICY_NAME, | ||
VEEAM_XML_PREFIX, | ||
} from '../react/ui-elements/Veeam/VeeamConstants'; | ||
import { INSTANCE_ID } from '../react/actions/__tests__/utils/testUtil'; | ||
|
||
//Subject Under Testing | ||
const SUT = jest.fn(); | ||
const instanceId = 'a5c1ad24-27a2-4aaf-a609-26b708729363'; | ||
const accountName = 'Veeam-Account'; | ||
const instanceId = INSTANCE_ID; | ||
const accountName = 'Veeam'; | ||
const accountNameAlreadyExist = 'Veeam-Account-Error'; | ||
const accountEmail = '[email protected]'; | ||
const accountId = '749861052561'; | ||
const bucketName = 'Veeam-Bucket'; | ||
export const bucketName = 'veeam'; | ||
const bucketNameWithErrorTriggered = 'Veeam-Bucket-Error'; | ||
const userName = 'Veeam-User'; | ||
const userNameWithErrorTriggered = 'Veeam-User-Error'; | ||
|
@@ -43,7 +45,7 @@ const veeamPolicyArn = `arn:aws:iam::${accountId}:policy/${veeamPolicyName}`; | |
const policyNameWithErrorTriggered = `${VEEAM_IMMUTABLE_POLICY_NAME}-${bucketNameWithErrorTriggered}`; | ||
const veeamObjectKey = `${VEEAM_XML_PREFIX}/system.xml`; | ||
|
||
const server = setupServer( | ||
export const getVeeamMutationHandler = () => [ | ||
// create endpoint | ||
rest.post( | ||
`${TEST_API_BASE_URL}/api/v1/config/${instanceId}/endpoint`, | ||
|
@@ -85,11 +87,18 @@ const server = setupServer( | |
); | ||
}, | ||
), | ||
|
||
rest.post(`${TEST_API_BASE_URL}/`, (req, res, ctx) => { | ||
//@ts-ignore | ||
const params = new URLSearchParams(req.body); | ||
SUT(params); | ||
// Assume Role | ||
if (params.get('Action') === 'AssumeRoleWithWebIdentity') { | ||
return res( | ||
ctx.status(200), | ||
ctx.xml(` | ||
<AssumeRoleWithWebIdentityResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"><AssumeRoleWithWebIdentityResult><AssumedRoleUser><Arn>arn:aws:sts::${accountId}:assumed-role/storage-manager-role/ui-9160673b-2c2a-4a6f-a1ef-a3cb6ce25d7f</Arn><AssumedRoleId>OES3SPDIYW4L92S8K1QE6MINE31LQG04:ui-9160673b-2c2a-4a6f-a1ef-a3cb6ce25d7f</AssumedRoleId></AssumedRoleUser><Credentials><SecretAccessKey>v/0Nq1YMw4nNbvtgQlgi0l6m/PXWjlk1VLmn2I5q</SecretAccessKey><AccessKeyId>72SPRZFF71WPWXXUG6XF</AccessKeyId><SessionToken>eyJzYWx0IjoicVIvVGdIdS9FVjJ4TjN5RmtXSnVLZGE0M0krK0g1L3lFVDU5UkV0enpYYz0iLCJ0YWciOiI4d05WRTIwTlQxWTVKbWtZemo2ZGJ3PT0iLCJjaXBoZXJ0ZXh0IjoiQVNIanI0M0VZc3dzK0QwWDFkVXRXQ2JMbzlFOVZ5SzF5WWt6a21lRjRXOUpCU3hwbmNxS21zWnpIU3ZvYlZEYjNKaDRNTm16bW1yVUd6dTU1bmRwMTk0eTVlVjFSVWMzaHZnSTFxZTRuYmJxNHBPdit5V3VZQ3RtSExUbE5BTHpDK3VhYW1tZDdzWk9BVXNKQlhRcmVHUG5sTFphb0kySTFveXJjbk10QlVpb1AvYnNjNUd6RHFqdTFWMjVQRE9PQWgzM2JFSktHdmorbEoyL2lWV0x5UHBQU1pLZmdZUnd1QjRXczdGaG81dHhaem9uWWhpaG9ocnFtdmFnNUJSNytiN2lGN3ZxZjBVSnFPZXI5Wm9ldDk1dlpqL01qTU04aGhGQXI1MmZnTHpzOHAzVlN3dHV0OENFSTBoVEJJNlVycUY4SWxiUmhFOUtlaHo0cnRiZHRKQzVmVHFRSkVPZWltb0RIbGpZZXZqOVlIZzZPVFhDR2ZhVzRIWDc3T0g5M1BRa0dHc1RCSjVpRTEyZEdYQjhYWWdSM1VackIwUzdQejdLQnpvSUVodTZOWUkrK1NPZ2pwMlFaUmhaWGtkbDdDdU5EMWg2UE9qN2twREY0QXhHbWdwcjBMbmpOdVp1UzJaWlJTck5OZG1WL3B5dWpUM3BtcFNJNUZkNW5Wby9SV1dTSGhoR0FVcWRJS0EyV00xdVJ2TkVFS25rb25keWNuVHRrSHpDVUwrN0RtTXNuL202eTcyZjFReHY2VFQyejRzRVFSUDFhWUcwdnBWSTlXbUpWdW5yTFFVNmxSUmpsb1VFSFVkZ2xCMGd1eTZGZTNYR29YQjdVc1J5UUpxbEJ0elpvdFdkR1AvSjZaMllNODFDSy8zZjJZTXVnNTZlbXQxTmJJZ0hrVWxnaGxpclRsNVdrckVRbG5XTW4zT2dzRk9wMjJKSTV1UGoxSENUMlNhTlBXZEQrY0VCcTZycC9tc1FDOW02Q3prSkMwTWMyclZ0RmdnZitaSEV5dVZvdEVzeUFtY1V5QTdFZzJtY3BXd1pnbHZrYkZQQmI5M2NDN0ZhZGhpNEUzQ0hQbm9BczF5eVNKNkxIOTZZTHJoaXk1Q1h3VWloSTlRdmxuSDNlV3EwaElBZTFGc2N6bThzVWRCTGU2SWlVc3ZJVDlpMjJzcTZnaVpmdld5czVlaU9NZzRQMFBaZCtPK0VDRmdmd3dxdUhYcFdEL1F5RnR1RENVb0xxblNyMU9lOHdCQ2lXNDFYaGtacmEzWTdtVW1QYXlNWTN6MXpOZm1XRllJV0dWZzlBNVFUaUZLWGlZTngxdUtWZGJ3Qk54SmowVmxlTTE4azlDNFR3Z2U3dVYyKzEzcWVkTW5xOUpLa2Uwa1NsNmMxMWM5N1RUbGJ4TUx5YS9WY1JLWkNkbHJaTGZNK0hjSTJWaGdkSzNzWHJIVEN6UENFRC9lMVBRTkg1RVZBVThLRlNHWGEzb1dPWm9VcmlSYlk1L3R5eTQvbHRKTkVhNnV3R2hra0ljR3JLMjltUndkaDJHSE94R1laYmdGL0VVUDYreUs5cjQrVzc5Y1RYc3NRcEpSM1M1bkZpUHE2bHR6NXM1ZlNYalNkcUxSM0gvTVZlcXV6K3RON0czMk1ieW9halZvcVJxcks2WjZIVm1vM3pDZ1M4TURQQk9jVkY3Ymc0QmhXaXFUTjc5a0ZqV0xkWWZSVlB5Qk1VaXBHNmZCcGlBdUZCZEV1S2lLMHBwVkhQNUpZL0h5ZXRBbVgxMzdVK1U5d3prbmw3eXhyOEQ0TkdNL05yaVhBT21hSDN4YVEifQ==</SessionToken><Expiration>2023-11-28T10:16:13Z</Expiration></Credentials><Provider>www.scality.com</Provider></AssumeRoleWithWebIdentityResult><ResponseMetadata><RequestId>8e94c64ebf4486567b0e</RequestId></ResponseMetadata></AssumeRoleWithWebIdentityResponse>`), | ||
); | ||
} | ||
if (params.get('Action') === 'CreateUser') { | ||
if (params.get('UserName') === userNameWithErrorTriggered) { | ||
return res( | ||
|
@@ -123,6 +132,26 @@ const server = setupServer( | |
); | ||
} | ||
if (params.get('Action') === 'AttachUserPolicy') { | ||
if (params.get('UserName') === userNameWithErrorTriggered) { | ||
return res( | ||
ctx.status(400), | ||
ctx.xml( | ||
`<ErrorResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"><Error><Code>ValidationError</Code><Message>The specified value is invalid.</Message></Error><RequestId>caeb1338404c9f821a2d</RequestId></ErrorResponse>`, | ||
), | ||
); | ||
} | ||
return res( | ||
ctx.status(200), | ||
ctx.xml(` | ||
<AttachUserPolicyResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"> | ||
<ResponseMetadata> | ||
<RequestId>2e30c3c68e45ad7122f7</RequestId> | ||
</ResponseMetadata> | ||
</AttachUserPolicyResponse>; | ||
`), | ||
); | ||
} | ||
if (params.get('Action') === 'CreateAccessKey') { | ||
if (params.get('UserName') === userNameWithErrorTriggered) { | ||
return res( | ||
ctx.status(400), | ||
|
@@ -133,29 +162,41 @@ const server = setupServer( | |
} | ||
return res( | ||
ctx.xml(` | ||
<AttachUserPolicyResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"> | ||
<ResponseMetadata> | ||
<RequestId>2e30c3c68e45ad7122f7</RequestId> | ||
</ResponseMetadata> | ||
</AttachUserPolicyResponse>; | ||
`), | ||
<CreateAccessKeyResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/"> | ||
<CreateAccessKeyResult> | ||
<AccessKey> | ||
<UserName>${userName}</UserName> | ||
<AccessKeyId>AKIAIOSFODNN7EXAMPLE</AccessKeyId> | ||
<Status>Active</Status> | ||
<SecretAccessKey>wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY</SecretAccessKey> | ||
<CreateDate>2023-11-15T14:29:06Z</CreateDate> | ||
</AccessKey> | ||
</CreateAccessKeyResult> | ||
<ResponseMetadata> | ||
<RequestId>2e30c3c68e45ad7122f7</RequestId> | ||
</ResponseMetadata> | ||
</CreateAccessKeyResponse>; | ||
`), | ||
); | ||
} | ||
}), | ||
// putBucketTagging | ||
|
||
rest.put(`${TEST_API_BASE_URL}/${bucketName}`, (req, res, ctx) => { | ||
// putBucketTagging | ||
if (req.url.searchParams.get('tagging') === '') { | ||
SUT(req.body); | ||
return res( | ||
ctx.xml(` | ||
<PutBucketTaggingResponse xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> | ||
<ResponseMetadata> | ||
<RequestId>2e30c3c68e45ad7122f7</RequestId> | ||
</ResponseMetadata> | ||
</PutBucketTaggingResponse>; | ||
`), | ||
<PutBucketTaggingResponse xmlns="http://s3.amazonaws.com/doc/2006-03-01/"> | ||
<ResponseMetadata> | ||
<RequestId>2e30c3c68e45ad7122f7</RequestId> | ||
</ResponseMetadata> | ||
</PutBucketTaggingResponse>; | ||
`), | ||
); | ||
} | ||
//create bucket | ||
return res(ctx.status(200)); | ||
}), | ||
rest.put( | ||
`${TEST_API_BASE_URL}/${bucketNameWithErrorTriggered}`, | ||
|
@@ -172,6 +213,20 @@ const server = setupServer( | |
}, | ||
), | ||
// putObject | ||
rest.put( | ||
`${TEST_API_BASE_URL}/${bucketName}/${VEEAM_XML_PREFIX}`, | ||
(req, res, ctx) => { | ||
SUT(req.body); | ||
return res(ctx.status(200)); | ||
}, | ||
), | ||
rest.put( | ||
`${TEST_API_BASE_URL}/${bucketName}/${VEEAM_XML_PREFIX}/capacity.xml`, | ||
(req, res, ctx) => { | ||
SUT(req.body); | ||
return res(ctx.status(200)); | ||
}, | ||
), | ||
rest.put( | ||
`${TEST_API_BASE_URL}/${bucketName}/${veeamObjectKey}`, | ||
(req, res, ctx) => { | ||
|
@@ -191,7 +246,8 @@ const server = setupServer( | |
); | ||
}, | ||
), | ||
); | ||
]; | ||
const server = setupServer(...getVeeamMutationHandler()); | ||
|
||
beforeAll(() => server.listen()); | ||
afterEach(() => { | ||
|
@@ -536,4 +592,44 @@ describe('mutations', () => { | |
}); | ||
expect(SUT).toHaveBeenCalledWith(SYSTEM_XML_CONTENT); | ||
}); | ||
it('should handle the useCreateUserAccessKeyMutation', async () => { | ||
//Setup | ||
const { result, waitFor } = renderHook( | ||
() => useCreateUserAccessKeyMutation(), | ||
{ wrapper: NewWrapper() }, | ||
); | ||
//Exercise | ||
result.current.mutate({ userName }); | ||
//Verify | ||
await waitFor(() => { | ||
expect(result.current.isSuccess).toBe(true); | ||
}); | ||
expect(SUT).toHaveBeenCalledWith( | ||
new URLSearchParams({ | ||
Action: 'CreateAccessKey', | ||
UserName: userName, | ||
Version: '2010-05-08', | ||
}), | ||
); | ||
}); | ||
it('should handle the error case of useCreateUserAccessKeyMutation', async () => { | ||
//Setup | ||
const { result, waitFor } = renderHook( | ||
() => useCreateUserAccessKeyMutation(), | ||
{ wrapper: NewWrapper() }, | ||
); | ||
//Exercise | ||
result.current.mutate({ userName: userNameWithErrorTriggered }); | ||
//Verify | ||
await waitFor(() => { | ||
expect(result.current.isError).toBe(true); | ||
}); | ||
expect(SUT).toHaveBeenCalledWith( | ||
new URLSearchParams({ | ||
Action: 'CreateAccessKey', | ||
UserName: userNameWithErrorTriggered, | ||
Version: '2010-05-08', | ||
}), | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { useRef } from 'react'; | ||
|
||
type MinimalMutation<TVariables = unknown, TData = unknown> = { | ||
mutate: ( | ||
variables: TVariables, | ||
mutationOptions: { onSuccess: (data: TData) => void }, | ||
) => void; | ||
isSuccess: boolean; | ||
data: TData; | ||
}; | ||
|
||
export const useChainedMutations = ({ | ||
mutations, | ||
}: { | ||
mutations: MinimalMutation[]; | ||
}): { | ||
mutate: ( | ||
computeVariablesForNext: (results: unknown[]) => unknown, | ||
index?: number, | ||
) => unknown; | ||
mutationsWithRetry: (MinimalMutation & { | ||
status: 'loading' | 'success' | 'error'; | ||
retry: () => void; | ||
})[]; | ||
} => { | ||
const mutationsWithRetry = useRef< | ||
(MinimalMutation & { | ||
status: 'loading' | 'success' | 'error'; | ||
retry: () => void; | ||
})[] | ||
//@ts-expect-error initial value | ||
>(mutations); | ||
const go = ( | ||
computeVariablesForNext: (results: unknown[]) => unknown, | ||
results: unknown[] = [], | ||
) => { | ||
const index = results.length; | ||
mutationsWithRetry.current[index].retry = () => { | ||
mutations[index].mutate(computeVariablesForNext(results), { | ||
onSuccess: (data) => { | ||
if (index < mutations.length - 1) { | ||
go(computeVariablesForNext, [...results, data]); | ||
} | ||
}, | ||
}); | ||
}; | ||
mutations[index].mutate(computeVariablesForNext(results), { | ||
onSuccess: (data) => { | ||
if (index < mutations.length - 1) { | ||
go(computeVariablesForNext, [...results, data]); | ||
} | ||
}, | ||
}); | ||
}; | ||
return { mutate: go, mutationsWithRetry: mutationsWithRetry.current }; | ||
}; |
Oops, something went wrong.