Skip to content

Commit

Permalink
test: [M3-8435] - Cypress integration test for Object Storage Gen2: E…
Browse files Browse the repository at this point in the history
…3 Endpoint (#10880)

* test: [M3-8435] - Cypress integration test for Object Storage Gen2: E3 Endpoint

* Added changeset: Cypress integration test for Object Storage Gen2: E3 Endpoint

* Review updates @coliu-akamai

---------

Co-authored-by: Jaalah Ramos <jaalah.ramos@gmail.com>
  • Loading branch information
jaalah-akamai and jaalah authored Sep 9, 2024
1 parent 86987f5 commit 516ae68
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 88 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-10880-tests-1725646735341.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Tests
---

Cypress integration test for Object Storage Gen2: E3 Endpoint ([#10880](https://github.com/linode/manager/pull/10880))
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,28 @@ import {
regionFactory,
} from 'src/factories';
import { chooseRegion } from 'support/util/regions';
import type { ObjectStorageEndpoint } from '@linode/api-v4';
import type {
ObjectStorageEndpoint,
ObjectStorageEndpointTypes,
} from '@linode/api-v4';

describe('Object Storage Gen2 create bucket tests', () => {
beforeEach(() => {
mockAppendFeatureFlags({
objMultiCluster: true,
objectStorageGen2: { enabled: true },
}).as('getFeatureFlags');
mockGetAccount(
accountFactory.build({
capabilities: [
'Object Storage',
'Object Storage Endpoint Types',
'Object Storage Access Key Regions',
],
})
).as('getAccount');
});

// Moved these constants to top of scope - they will likely be used for other obj storage gen2 bucket create tests
const mockRegions = regionFactory.buildList(10, {
capabilities: ['Object Storage'],
Expand Down Expand Up @@ -53,6 +72,36 @@ describe('Object Storage Gen2 create bucket tests', () => {
}),
];

const checkRateLimitsTable = (endpointType: ObjectStorageEndpointTypes) => {
const expectedHeaders = ['Limits', 'GET', 'PUT', 'LIST', 'DELETE', 'OTHER'];
const expectedBasicValues = ['Basic', '2,000', '500', '100', '200', '400'];
const expectedHighValues =
endpointType === 'E3'
? ['High', '20,000', '2,000', '400', '400', '1,000']
: ['High', '5,000', '1,000', '200', '200', '800'];

cy.get('[data-testid="bucket-rate-limit-table"]').within(() => {
expectedHeaders.forEach((header, index) => {
cy.get('th').eq(index).should('contain.text', header);
});

cy.contains('tr', 'Basic').within(() => {
expectedBasicValues.forEach((value, index) => {
cy.get('td').eq(index).should('contain.text', value);
});
});

cy.contains('tr', 'High').within(() => {
expectedHighValues.forEach((value, index) => {
cy.get('td').eq(index).should('contain.text', value);
});
});

// Check that Basic radio button is checked
cy.findByLabelText('Basic').should('be.checked');
});
};

/**
* Confirms UI flow for creating a gen2 Object Storage bucket with endpoint E0
* Confirms all endpoints are displayed regardless if there's multiple of the same type
Expand Down Expand Up @@ -83,15 +132,6 @@ describe('Object Storage Gen2 create bucket tests', () => {
objMultiCluster: true,
objectStorageGen2: { enabled: true },
}).as('getFeatureFlags');
mockGetAccount(
accountFactory.build({
capabilities: [
'Object Storage',
'Object Storage Endpoint Types',
'Object Storage Access Key Regions',
],
})
).as('getAccount');

mockGetObjectStorageEndpoints(mockEndpoints).as(
'getObjectStorageEndpoints'
Expand Down Expand Up @@ -222,20 +262,6 @@ describe('Object Storage Gen2 create bucket tests', () => {
region: mockRegion.id,
}).as('createBucket');

mockAppendFeatureFlags({
objMultiCluster: true,
objectStorageGen2: { enabled: true },
}).as('getFeatureFlags');
mockGetAccount(
accountFactory.build({
capabilities: [
'Object Storage',
'Object Storage Endpoint Types',
'Object Storage Access Key Regions',
],
})
).as('getAccount');

mockGetObjectStorageEndpoints(mockEndpoints).as(
'getObjectStorageEndpoints'
);
Expand Down Expand Up @@ -277,69 +303,7 @@ describe('Object Storage Gen2 create bucket tests', () => {
cy.get('[data-testid="bucket-rate-limit-table"]').should('exist');

// Confirm that basic rate limits table is displayed
cy.get('[data-testid="bucket-rate-limit-table"]').within(() => {
const expectedHeaders = [
'Limits',
'GET',
'PUT',
'LIST',
'DELETE',
'OTHER',
];
const expectedBasicValues = [
'Basic',
'2,000',
'500',
'100',
'200',
'400',
];
const expectedHighValues = [
'High',
'5,000',
'1,000',
'200',
'200',
'800',
];

// Check visible elements first
cy.findByText('Limits').should('be.visible');

// Function to check a row of values
const checkRowValues = (rowIndex: number, values: string[]) => {
cy.findAllByRole('row')
.eq(rowIndex)
.within(() => {
values.forEach((value, columnIndex) => {
if (columnIndex === 0) {
// First column should always be visible
cy.findByText(value).should('be.visible');
} else {
// For other columns, use column index to avoid ambiguity
cy.get(
`td:nth-child(${columnIndex + 1}), th:nth-child(${
columnIndex + 1
})`
)
.scrollIntoView()
.should('be.visible')
.and('contain.text', value);
}
});
});
};

// Assert that the table has the expected values
checkRowValues(0, expectedHeaders);
checkRowValues(1, expectedBasicValues);
checkRowValues(2, expectedHighValues);

cy.findByText('Limits').scrollIntoView();

// Confirm that basic radio button is checked by default
cy.findByLabelText('Basic').should('be.checked');
});
checkRateLimitsTable(mockBucket.endpoint_type!);

ui.buttonGroup
.findButtonByTitle('Create Bucket')
Expand Down Expand Up @@ -387,4 +351,119 @@ describe('Object Storage Gen2 create bucket tests', () => {
cy.wait(['@deleteBucket', '@getBuckets']);
cy.findByText(bucketLabel).should('not.exist');
});

/**
* Confirms UI flow for creating a gen2 Object Storage bucket with endpoint E3
*/
it('can create a bucket with endpoint type 3', () => {
const endpointTypeE3 = 'Standard (E3)';
const bucketLabel = randomLabel();

//wait for the newly 'created' mocked bucket to appear
const mockBucket = objectStorageBucketFactoryGen2.build({
label: bucketLabel,
region: mockRegion.id,
endpoint_type: 'E3',
s3_endpoint: undefined,
});

mockGetBuckets([]).as('getBuckets');
mockDeleteBucket(bucketLabel, mockRegion.id).as('deleteBucket');
mockCreateBucket({
label: bucketLabel,
endpoint_type: 'E3',
cors_enabled: false,
region: mockRegion.id,
}).as('createBucket');

mockGetObjectStorageEndpoints(mockEndpoints).as(
'getObjectStorageEndpoints'
);

mockGetRegions(mockRegions);

cy.visitWithLogin('/object-storage/buckets/create');
cy.wait([
'@getFeatureFlags',
'@getBuckets',
'@getAccount',
'@getObjectStorageEndpoints',
]);

ui.drawer
.findByTitle('Create Bucket')
.should('be.visible')
.within(() => {
cy.findByText('Label').click().type(bucketLabel);
ui.regionSelect.find().click().type(`${mockRegion.label}{enter}`);
cy.findByLabelText('Object Storage Endpoint Type')
.should('be.visible')
.click();

// Select E3 endpoint
ui.autocompletePopper
.findByTitle('Standard (E3)')
.scrollIntoView()
.should('be.visible')
.should('be.enabled')
.click();

// Confirm bucket rate limits text for E3 endpoint
cy.findByText('Bucket Rate Limits').should('be.visible');
cy.contains(
'Specifies the maximum Requests Per Second (RPS) for a bucket. To increase it to High, open a support ticket. Understand bucket rate limits.'
).should('be.visible');

// Confirm bucket rate limit table should exist when E3 endpoint is selected
cy.get('[data-testid="bucket-rate-limit-table"]').should('exist');

// Confirm that basic rate limits table is displayed
checkRateLimitsTable(mockBucket.endpoint_type!);

ui.buttonGroup
.findButtonByTitle('Create Bucket')
.should('be.visible')
.should('be.enabled')
.click();
});

mockGetBuckets([mockBucket]).as('getBuckets');
cy.wait(['@getBuckets']);

// Confirm request body has expected data
cy.wait('@createBucket').then((xhr) => {
const requestPayload = xhr.request.body;
expect(requestPayload['endpoint_type']).to.equal('E3');
expect(requestPayload['cors_enabled']).to.equal(false);
});

ui.drawer.find().should('not.exist');

// Confirm that bucket is created, initiate deletion for cleanup
cy.findByText(endpointTypeE3).should('be.visible');
cy.findByText(bucketLabel)
.should('be.visible')
.closest('tr')
.within(() => {
cy.findByText(mockRegion.label).should('be.visible');
ui.button.findByTitle('Delete').should('be.visible').click();
});

ui.dialog
.findByTitle(`Delete Bucket ${bucketLabel}`)
.should('be.visible')
.within(() => {
cy.findByLabelText('Bucket Name').click().type(bucketLabel);
ui.buttonGroup
.findButtonByTitle('Delete')
.should('be.visible')
.should('be.enabled')
.click();
});

// Confirm bucket gets deleted
mockGetBuckets([]).as('getBuckets');
cy.wait(['@deleteBucket', '@getBuckets']);
cy.findByText(bucketLabel).should('not.exist');
});
});
2 changes: 1 addition & 1 deletion packages/manager/src/mocks/serverHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ export const handlers = [
];
return HttpResponse.json(makeResourcePage(objectStorageTypes));
}),
http.get('*/v4/object-storage/endpoints', ({ }) => {
http.get('*/v4/object-storage/endpoints', ({}) => {
const endpoints = [
objectStorageEndpointsFactory.build({
endpoint_type: 'E0',
Expand Down

0 comments on commit 516ae68

Please sign in to comment.