Skip to content

Commit

Permalink
test: [M3-7133] - Add integration tests for AGLB certificate delete f…
Browse files Browse the repository at this point in the history
…low (#9846)

* M3-7133 Add integration tests for AGLB certificate delete flow

* Add changeset
  • Loading branch information
cliu-akamai authored Nov 3, 2023
1 parent 318c6a6 commit 4d25e1a
Show file tree
Hide file tree
Showing 3 changed files with 242 additions and 3 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-9846-added-1699023355495.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Added
---

Add integration tests for AGLB certificate delete flow ([#9846](https://github.com/linode/manager/pull/9846))
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,99 @@ import {
import { makeFeatureFlagData } from 'support/util/feature-flags';
import { loadbalancerFactory, certificateFactory } from '@src/factories';
import { ui } from 'support/ui';
import { randomLabel, randomString } from 'support/util/random';
import { randomItem, randomLabel, randomString } from 'support/util/random';
import {
mockDeleteLoadBalancerCertificate,
mockDeleteLoadBalancerCertificateError,
mockGetLoadBalancer,
mockGetLoadBalancerCertificates,
mockUploadLoadBalancerCertificate,
} from 'support/intercepts/load-balancers';
import { Loadbalancer, Certificate } from '@linode/api-v4/types';

/**
* Deletes the TLS / Service Target certificate in the AGLB landing page.
*
* @param loadBalancer - The load balancer that contains the certificate to be deleted.
* @param certificatesDeleteBefore - The array of certificates to be displayed before deleting.
* @param certificatesDeleteAfter - The array of certificates to be displayed after deleting.
*
* Asserts that the landing page has updated to reflect the changes.
*/
const deleteCertificate = (
loadBalancer: Loadbalancer,
certificatesDeleteBefore: Certificate[],
certificatesDeleteAfter: Certificate[]
) => {
mockAppendFeatureFlags({
aglb: makeFeatureFlagData(true),
}).as('getFeatureFlags');
mockGetFeatureFlagClientstream().as('getClientStream');
mockGetLoadBalancer(loadBalancer).as('getLoadBalancer');
mockGetLoadBalancerCertificates(loadBalancer.id, certificatesDeleteBefore).as(
'getCertificates'
);

cy.visitWithLogin(`/loadbalancers/${loadBalancer.id}/certificates`);
cy.wait([
'@getFeatureFlags',
'@getClientStream',
'@getLoadBalancer',
'@getCertificates',
]);

// Delete a TLS/Service Target certificate.
const certificateToDeleteLabel = certificatesDeleteBefore[0].label;
ui.actionMenu
.findByTitle(`Action Menu for certificate ${certificateToDeleteLabel}`)
.should('be.visible')
.click();
ui.actionMenuItem.findByTitle('Delete').should('be.visible').click();

mockDeleteLoadBalancerCertificate(
loadBalancer.id,
certificatesDeleteBefore[0].id
).as('deleteCertificate');

mockGetLoadBalancerCertificates(loadBalancer.id, certificatesDeleteAfter).as(
'getCertificates'
);

ui.dialog
.findByTitle(`Delete Certificate ${certificateToDeleteLabel}?`)
.should('be.visible')
.within(() => {
ui.button
.findByTitle('Delete')
.should('be.visible')
.should('be.enabled')
.click();
});

cy.wait(['@deleteCertificate', '@getCertificates']);

// Confirm that the deleted certificate is removed from the table with expected info.
cy.findByText(certificateToDeleteLabel).should('not.exist');

if (certificatesDeleteAfter.length === 0) {
// Confirm that Cloud Manager allows users to delete the last certificate, and display empty state gracefully.
cy.findByText('No items to display.').should('be.visible');
}
};

describe('Akamai Global Load Balancer certificates page', () => {
let mockLoadBalancer: Loadbalancer;

before(() => {
mockLoadBalancer = loadbalancerFactory.build();
});

/*
* - Confirms Load Balancer certificate upload UI flow using mocked API requests.
* - Confirms that TLS and Service Target certificates can be uploaded.
* - Confirms that certificates table update to reflects uploaded certificates.
*/
it('can upload a TLS certificate', () => {
const mockLoadBalancer = loadbalancerFactory.build();
const mockLoadBalancerCertTls = certificateFactory.build({
label: randomLabel(),
type: 'downstream',
Expand Down Expand Up @@ -94,8 +172,8 @@ describe('Akamai Global Load Balancer certificates page', () => {
// Confirm that new certificate is listed in the table with expected info.
cy.findByText(mockLoadBalancerCertTls.label).should('be.visible');
});

it('can upload a service target certificate', () => {
const mockLoadBalancer = loadbalancerFactory.build();
const mockLoadBalancerCertServiceTarget = certificateFactory.build({
label: randomLabel(),
type: 'ca',
Expand Down Expand Up @@ -162,4 +240,118 @@ describe('Akamai Global Load Balancer certificates page', () => {
// Confirm that both new certificates are listed in the table with expected info.
cy.findByText(mockLoadBalancerCertServiceTarget.label).should('be.visible');
});

/*
* - Confirms Load Balancer certificate delete UI flow using mocked API requests.
* - Confirms that TLS and Service Target certificates can be deleted.
* - Confirms that certificates table update to reflects deleted certificates.
* - Confirms that the last certificate can be deleted.
*/
it('can delete a TLS certificate', () => {
const mockLoadBalancerCertsTls = certificateFactory.buildList(5, {
type: 'downstream',
});
const mockLoadBalancerAfterDeleteCertsTls = mockLoadBalancerCertsTls.slice(
1
);

deleteCertificate(
mockLoadBalancer,
mockLoadBalancerCertsTls,
mockLoadBalancerAfterDeleteCertsTls
);
});

it('can delete a service target certificate', () => {
const mockLoadBalancerCertsTls = certificateFactory.buildList(5, {
type: 'ca',
});
const mockLoadBalancerAfterDeleteCertsTls = mockLoadBalancerCertsTls.slice(
1
);

deleteCertificate(
mockLoadBalancer,
mockLoadBalancerCertsTls,
mockLoadBalancerAfterDeleteCertsTls
);
});

it('can delete the last certificate', () => {
const mockLoadBalancerCertsTls = certificateFactory.buildList(1, {
type: randomItem(['ca', 'downstream']),
});
const mockLoadBalancerAfterDeleteCertsTls = mockLoadBalancerCertsTls.slice(
1
);

deleteCertificate(
mockLoadBalancer,
mockLoadBalancerCertsTls,
mockLoadBalancerAfterDeleteCertsTls
);
});

it('can handle server errors gracefully when failing to delete the certificate', () => {
const mockLoadBalancerCertsTls = certificateFactory.buildList(1, {
type: randomItem(['ca', 'downstream']),
});
const mockLoadBalancerAfterDeleteCertsTls = mockLoadBalancerCertsTls.slice(
1
);

mockAppendFeatureFlags({
aglb: makeFeatureFlagData(true),
}).as('getFeatureFlags');
mockGetFeatureFlagClientstream().as('getClientStream');
mockGetLoadBalancer(mockLoadBalancer).as('getLoadBalancer');
mockGetLoadBalancerCertificates(
mockLoadBalancer.id,
mockLoadBalancerCertsTls
).as('getCertificates');

cy.visitWithLogin(`/loadbalancers/${mockLoadBalancer.id}/certificates`);
cy.wait([
'@getFeatureFlags',
'@getClientStream',
'@getLoadBalancer',
'@getCertificates',
]);

// Delete a TLS/Service Target certificate.
const certificateToDeleteLabel = mockLoadBalancerCertsTls[0].label;
ui.actionMenu
.findByTitle(`Action Menu for certificate ${certificateToDeleteLabel}`)
.should('be.visible')
.click();
ui.actionMenuItem.findByTitle('Delete').should('be.visible').click();

mockDeleteLoadBalancerCertificateError(
mockLoadBalancer.id,
mockLoadBalancerCertsTls[0].id
).as('deleteCertificateError');

ui.dialog
.findByTitle(`Delete Certificate ${certificateToDeleteLabel}?`)
.should('be.visible')
.within(() => {
ui.button
.findByTitle('Delete')
.should('be.visible')
.should('be.enabled')
.click();
});

cy.wait('@deleteCertificateError');

ui.dialog
.findByTitle(`Delete Certificate ${certificateToDeleteLabel}?`)
.should('be.visible')
.within(() => {
// Confirm that an error message shows up in the dialog
cy.findByText(
'An error occurred while deleting Load Balancer certificate.'
).should('be.visible');
});
});
});
42 changes: 42 additions & 0 deletions packages/manager/cypress/support/intercepts/load-balancers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,48 @@ export const mockUploadLoadBalancerCertificate = (
);
};

/**
* Intercepts DELETE request to delete an AGLB load balancer certificate and mocks a success response.
*
* @param loadBalancerId - ID of load balancer for which to delete certificates.
* @param certificateId - ID of certificate for which to remove.
*
* @returns Cypress chainable.
*/
export const mockDeleteLoadBalancerCertificate = (
loadBalancerId: number,
certificateId: number
) => {
return cy.intercept(
'DELETE',
apiMatcher(`/aglb/${loadBalancerId}/certificates/${certificateId}`),
makeResponse()
);
};

/**
* Intercepts GET request to retrieve AGLB service targets and mocks HTTP 500 error response.
*
* @param loadBalancerId - ID of load balancer for which to delete certificates.
* @param certificateId - ID of certificate for which to remove.
* @param message - Optional error message with which to respond.
*
* @returns Cypress chainable.
*/
export const mockDeleteLoadBalancerCertificateError = (
loadBalancerId: number,
certificateId: number,
message?: string
) => {
const defaultMessage =
'An error occurred while deleting Load Balancer certificate.';
return cy.intercept(
'DELETE',
apiMatcher(`/aglb/${loadBalancerId}/certificates/${certificateId}`),
makeErrorResponse(message ?? defaultMessage, 500)
);
};

/**
* Intercepts GET request to retrieve AGLB service targets and mocks response.
*
Expand Down

0 comments on commit 4d25e1a

Please sign in to comment.