Skip to content

Commit

Permalink
ZKUI-397: implement the logic of getBucketTagging and add use-case se…
Browse files Browse the repository at this point in the history
…ssion in bucket overview
  • Loading branch information
ChengYanJin committed Nov 13, 2023
1 parent 664a0d0 commit 8cd5ddb
Show file tree
Hide file tree
Showing 10 changed files with 360 additions and 39 deletions.
67 changes: 67 additions & 0 deletions src/js/mock/S3ClientMSWHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,43 @@ export function mockBucketOperations(
);
}

if (req.url.searchParams.has('cors')) {
return res(
ctx.xml(`
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
</CORSConfiguration>
`),
);
}

if (req.url.searchParams.has('acl')) {
return res(
ctx.xml(`
<?xml version="1.0" encoding="UTF-8"?>
<AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Owner>
<ID>1234</ID>
<DisplayName>test</DisplayName>
</Owner>
<AccessControlList>
</AccessControlList>
</AccessControlPolicy>
`),
);
}

if (req.url.searchParams.has('object-lock')) {
return res(
ctx.xml(`
<?xml version="1.0" encoding="UTF-8"?>
<ObjectLockConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<ObjectLockEnabled>Enabled</ObjectLockEnabled>
</ObjectLockConfiguration>
`),
);
}

return res(ctx.status(404));
},
);
Expand Down Expand Up @@ -178,3 +215,33 @@ export const mockObjectEmpty = (bucketName: string) => {
},
);
};

export const mockGetBucketTagging = (bucketName: string) => {
return rest.get(
`${zenkoUITestConfig.zenkoEndpoint}/${bucketName}`,
(req, res, ctx) => {
if (req.url.searchParams.has('tagging')) {
return res(
ctx.xml(`
<?xml version="1.0" encoding="UTF-8"?>
<Tagging>
<TagSet>
<Tag><Key>X-Scality-Usecase</Key><Value>Veeam 12</Value></Tag>
</TagSet>
</Tagging>`),
);
}
},
);
};

export const mockGetBucketTaggingError = (bucketName: string) => {
return rest.get(
`${zenkoUITestConfig.zenkoEndpoint}/${bucketName}`,
(req, res, ctx) => {
if (req.url.searchParams.has('tagging')) {
return res(ctx.status(500));
}
},
);
};
115 changes: 93 additions & 22 deletions src/react/databrowser/buckets/details/Overview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import { ConstrainedText, Icon, Toggle, Tooltip } from '@scality/core-ui';
import {
ConstrainedText,
Icon,
Toast,
Toggle,
Tooltip,
} from '@scality/core-ui';
import { SmallerText } from '@scality/core-ui/dist/components/text/Text.component';
import { useHistory } from 'react-router-dom';
import { useDispatch, useSelector } from 'react-redux';
Expand All @@ -10,7 +16,10 @@ import type { BucketInfo } from '../../../../types/s3';
import type { AppState } from '../../../../types/state';
import { useCurrentAccount } from '../../../DataServiceRoleProvider';
import { getBucketInfo, toggleBucketVersioning } from '../../../actions';
import { useChangeBucketVersionning } from '../../../next-architecture/domain/business/buckets';
import {
useBucketTagging,
useChangeBucketVersionning,
} from '../../../next-architecture/domain/business/buckets';
import { Bucket } from '../../../next-architecture/domain/entities/bucket';
import { ButtonContainer } from '../../../ui-elements/Container';
import { DeleteBucket } from '../../../ui-elements/DeleteBucket';
Expand All @@ -26,6 +35,11 @@ import {
import { useWorkflows } from '../../../workflow/Workflows';
import { useEffect, useState } from 'react';
import { Button } from '@scality/core-ui/dist/next';
import {
BUCKET_TAG_USECASE,
VEEAMVERSION11,
VEEAMVERSION12,
} from '../../../ui-elements/Veeam/VeeamConstants';

function capitalize(string: string) {
return string.toLowerCase().replace(/^\w/, (c) => {
Expand Down Expand Up @@ -88,6 +102,17 @@ function Overview({ bucket, ingestionStates }: Props) {
const features = useSelector((state: AppState) => state.auth.config.features);
const { account } = useCurrentAccount();
const [isErrorModalOpen, setIsErrorModalOpen] = useState(false);
const [bucketTaggingToast, setBucketTaggingToast] = useState(true);
const { tags } = useBucketTagging({ bucketName: bucket.name });
const VEEAM_FEATURE_FLAG_ENABLED = features.includes('Veeam');
const isVeeamBucket =
tags.status === 'success' &&
(tags.value?.[BUCKET_TAG_USECASE] === VEEAMVERSION11 ||
tags.value?.[BUCKET_TAG_USECASE] === VEEAMVERSION12) &&
VEEAM_FEATURE_FLAG_ENABLED;

const isVeeam12 =
isVeeamBucket && tags.value?.[BUCKET_TAG_USECASE] === VEEAMVERSION12;

useEffect(() => {
dispatch(getBucketInfo(bucket.name));
Expand Down Expand Up @@ -136,6 +161,14 @@ function Overview({ bucket, ingestionStates }: Props) {
: null
}
/>
<Toast
message="Encountered issues loading bucket tagging, causing uncertainty about the use-case. Please refresh the page."
open={tags.status === 'error' && bucketTaggingToast}
status="error"
onClose={() => {
setBucketTaggingToast(false);
}}
/>
<ButtonContainer>
<EmptyBucket bucketName={bucket.name} />
<DeleteBucket bucketName={bucket.name} />
Expand Down Expand Up @@ -208,6 +241,58 @@ function Overview({ bucket, ingestionStates }: Props) {
)}
</T.Value>
</T.Row>
<T.Row>
<T.Key> Location </T.Key>
<T.Value>
{bucketInfo.locationConstraint || 'us-east-1'}
{' / '}
<small>
{locations &&
getLocationType(locations[bucketInfo.locationConstraint])}
</small>
</T.Value>
</T.Row>
{features.includes(XDM_FEATURE) && (
<T.Row>
<T.Key> Async Metadata updates </T.Key>
<T.Value>
{ingestionValue}
{isIngestion && <HelpAsyncNotification />}
</T.Value>
</T.Row>
)}
</T.GroupContent>
</T.Group>
{isVeeamBucket && (
<T.Group>
<T.GroupName> Use-case </T.GroupName>
<T.Row>
<T.Key> Use-case </T.Key>
<T.Value> Backup - {tags.value?.[BUCKET_TAG_USECASE]}</T.Value>
</T.Row>
{isVeeam12 && (
<T.Row>
<T.Key> Max repository Capacity </T.Key>
<T.GroupValues>
{/* TODO */}
<>5TB</>
<Button
variant="outline"
label="Edit"
aria-label="Edit max capacity"
icon={<Icon name="Pencil" />}
onClick={() => {
//TODO: open the modal to modify the capacity
}}
/>
</T.GroupValues>
</T.Row>
)}
</T.Group>
)}
<T.Group>
<T.GroupName> Data protection </T.GroupName>
<T.GroupContent>
{bucketInfo.objectLockConfiguration.ObjectLockEnabled ===
'Enabled' && (
<T.Row>
Expand All @@ -218,12 +303,18 @@ function Overview({ bucket, ingestionStates }: Props) {
id="edit-retention-btn"
variant="outline"
label="Edit"
aria-label="Edit default retention"
icon={<Icon name="Pencil" />}
onClick={() => {
history.push(
`/accounts/${account?.Name}/buckets/${bucket.name}/retention-setting`,
);
}}
disabled={isVeeamBucket}
tooltip={{
overlay:
'Edition is disabled as it is managed by Veeam.',
}}
/>
</T.GroupValues>
</T.Row>
Expand All @@ -235,26 +326,6 @@ function Overview({ bucket, ingestionStates }: Props) {
<T.Value>Disabled</T.Value>
</T.Row>
)}
<T.Row>
<T.Key> Location </T.Key>
<T.Value>
{bucketInfo.locationConstraint || 'us-east-1'}
{' / '}
<small>
{locations &&
getLocationType(locations[bucketInfo.locationConstraint])}
</small>
</T.Value>
</T.Row>
{features.includes(XDM_FEATURE) && (
<T.Row>
<T.Key> Async Metadata updates </T.Key>
<T.Value>
{ingestionValue}
{isIngestion && <HelpAsyncNotification />}
</T.Value>
</T.Row>
)}
</T.GroupContent>
</T.Group>
<T.Group>
Expand Down
77 changes: 69 additions & 8 deletions src/react/databrowser/buckets/details/__tests__/Overview.test.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import * as T from '../../../../ui-elements/TableKeyValue2';
import * as actions from '../../../../actions/s3bucket';
import {
bucketInfoResponseNoVersioning,
Expand All @@ -9,17 +8,18 @@ import {
bucketInfoResponseObjectLockDefaultRetention,
} from '../../../../../js/mock/S3Client';
import Overview from '../Overview';
import { Toggle } from '@scality/core-ui';
import { NewWrapper, zenkoUITestConfig } from '../../../../utils/testUtil';
import {
reduxMount,
reduxRender,
zenkoUITestConfig,
} from '../../../../utils/testUtil';
import { fireEvent, screen, waitFor, within } from '@testing-library/react';
fireEvent,
render,
screen,
waitFor,
within,
} from '@testing-library/react';
import Immutable from 'immutable';
import userEvent from '@testing-library/user-event';
import { renderWithRouterMatch } from '../../../../utils/testUtil';
import { debug } from 'jest-preview';

const BUCKET = {
CreationDate: 'Tue Oct 12 2020 18:38:56',
LocationConstraint: '',
Expand Down Expand Up @@ -54,6 +54,7 @@ const TEST_STATE = {
counter: 0,
messages: Immutable.List(),
},
auth: { config: { features: ['Veeam'] } },
};
//TODO: Those tests are testing implementation details based on child component names. We should refactor them.
describe('Overview', () => {
Expand Down Expand Up @@ -198,6 +199,11 @@ import {
getConfigOverlay,
getStorageConsumptionMetricsHandlers,
} from '../../../../../js/mock/managementClientMSWHandlers';
import {
mockBucketOperations,
mockGetBucketTagging,
mockGetBucketTaggingError,
} from '../../../../../js/mock/S3ClientMSWHandlers';
const mockResponse =
'<VersioningConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Status>Enabled</Status></VersioningConfiguration>';
const TEST_ACCOUNT =
Expand Down Expand Up @@ -235,13 +241,29 @@ const server = setupServer(
zenkoUITestConfig.managementEndpoint,
INSTANCE_ID,
),
mockBucketOperations(),
);
beforeAll(() => {
server.listen({ onUnhandledRequest: 'error' });
});
afterAll(() => server.close());
afterEach(() => server.resetHandlers());

const selectors = {
editDefaultRetentionButton: () =>
screen.getByRole('button', {
name: /edit default retention/i,
}),
bucketTaggingErrorToastCloseButton: () =>
screen.getByRole('button', {
name: /close/i,
}),
bucketTaggingErrorToast: () =>
screen.getByText(
/Encountered issues loading bucket tagging, causing uncertainty about the use-case. Please refresh the page./i,
),
};

describe('Overview', () => {
it('should call the updateBucketVersioning function when clicking on the toggle versioning button', async () => {
const useUpdateBucketVersioningMock = jest.fn();
Expand Down Expand Up @@ -273,4 +295,43 @@ describe('Overview', () => {
expect(useUpdateBucketVersioningMock).toHaveBeenCalledWith(mockResponse);
});
});

it('should display the Veeam use-case and disable the edition of default retention', async () => {
//Setup
server.use(mockGetBucketTagging(bucketName));
//Exersise
render(<Overview bucket={{ name: bucketName }} />, {
wrapper: NewWrapper(),
});
//Verify
await waitFor(() => {
expect(
screen.getByText(new RegExp(`Backup - Veeam 12`, 'i')),
).toBeInTheDocument();
});
expect(selectors.editDefaultRetentionButton()).toBeDisabled();
});

it('should show error toast when loading bucket tagging failed', async () => {
//Setup
server.use(mockGetBucketTaggingError(bucketName));
//Exersise
render(<Overview bucket={{ name: bucketName }} />, {
wrapper: NewWrapper(),
});
//Verify
await waitFor(() => {
expect(selectors.bucketTaggingErrorToast()).toBeInTheDocument();
});
//Exersise
userEvent.click(selectors.bucketTaggingErrorToastCloseButton());
//Verify
await waitFor(() => {
expect(
screen.queryByText(
/Encountered issues loading bucket tagging, causing uncertainty about the use-case. Please refresh the page./i,
),
).toBe(null);
});
});
});
Loading

0 comments on commit 8cd5ddb

Please sign in to comment.