summaryrefslogtreecommitdiffstats
path: root/src/pybind/mgr/dashboard/frontend/cypress/e2e/block
diff options
context:
space:
mode:
Diffstat (limited to 'src/pybind/mgr/dashboard/frontend/cypress/e2e/block')
-rw-r--r--src/pybind/mgr/dashboard/frontend/cypress/e2e/block/images.e2e-spec.ts92
-rw-r--r--src/pybind/mgr/dashboard/frontend/cypress/e2e/block/images.po.ts110
-rw-r--r--src/pybind/mgr/dashboard/frontend/cypress/e2e/block/iscsi.e2e-spec.ts24
-rw-r--r--src/pybind/mgr/dashboard/frontend/cypress/e2e/block/iscsi.po.ts7
-rw-r--r--src/pybind/mgr/dashboard/frontend/cypress/e2e/block/mirroring.e2e-spec.ts117
-rw-r--r--src/pybind/mgr/dashboard/frontend/cypress/e2e/block/mirroring.po.ts61
6 files changed, 411 insertions, 0 deletions
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/images.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/images.e2e-spec.ts
new file mode 100644
index 000000000..962c135d5
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/images.e2e-spec.ts
@@ -0,0 +1,92 @@
+import { PoolPageHelper } from '../pools/pools.po';
+import { ImagesPageHelper } from './images.po';
+
+describe('Images page', () => {
+ const pools = new PoolPageHelper();
+ const images = new ImagesPageHelper();
+
+ const poolName = 'e2e_images_pool';
+
+ before(() => {
+ cy.login();
+ // Need pool for image testing
+ pools.navigateTo('create');
+ pools.create(poolName, 8, 'rbd');
+ pools.existTableCell(poolName);
+ });
+
+ after(() => {
+ // Deletes images test pool
+ pools.navigateTo();
+ pools.delete(poolName);
+ pools.navigateTo();
+ pools.existTableCell(poolName, false);
+ });
+
+ beforeEach(() => {
+ cy.login();
+ images.navigateTo();
+ });
+
+ it('should open and show breadcrumb', () => {
+ images.expectBreadcrumbText('Images');
+ });
+
+ it('should show four tabs', () => {
+ images.getTabsCount().should('eq', 4);
+ });
+
+ it('should show text for all tabs', () => {
+ images.getTabText(0).should('eq', 'Images');
+ images.getTabText(1).should('eq', 'Namespaces');
+ images.getTabText(2).should('eq', 'Trash');
+ images.getTabText(3).should('eq', 'Overall Performance');
+ });
+
+ describe('create, edit & delete image test', () => {
+ const imageName = 'e2e_images#image';
+ const newImageName = 'e2e_images#image_new';
+
+ it('should create image', () => {
+ images.createImage(imageName, poolName, '1');
+ images.getFirstTableCell(imageName).should('exist');
+ });
+
+ it('should edit image', () => {
+ images.editImage(imageName, poolName, newImageName, '2');
+ images.getFirstTableCell(newImageName).should('exist');
+ });
+
+ it('should delete image', () => {
+ images.delete(newImageName);
+ });
+ });
+
+ describe('move to trash, restore and purge image tests', () => {
+ const imageName = 'e2e_trash#image';
+ const newImageName = 'e2e_newtrash#image';
+
+ before(() => {
+ cy.login();
+ // Need image for trash testing
+ images.createImage(imageName, poolName, '1');
+ images.getFirstTableCell(imageName).should('exist');
+ });
+
+ it('should move the image to the trash', () => {
+ images.moveToTrash(imageName);
+ images.getFirstTableCell(imageName).should('exist');
+ });
+
+ it('should restore image to images table', () => {
+ images.restoreImage(imageName, newImageName);
+ images.getFirstTableCell(newImageName).should('exist');
+ });
+
+ it('should purge trash in images trash tab', () => {
+ images.getFirstTableCell(newImageName).should('exist');
+ images.moveToTrash(newImageName);
+ images.purgeTrash(newImageName, poolName);
+ });
+ });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/images.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/images.po.ts
new file mode 100644
index 000000000..bf6cbc052
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/images.po.ts
@@ -0,0 +1,110 @@
+import { PageHelper } from '../page-helper.po';
+
+export class ImagesPageHelper extends PageHelper {
+ pages = {
+ index: { url: '#/block/rbd', id: 'cd-rbd-list' },
+ create: { url: '#/block/rbd/create', id: 'cd-rbd-form' }
+ };
+
+ // Creates a block image and fills in the name, pool, and size fields.
+ // Then checks if the image is present in the Images table.
+ createImage(name: string, pool: string, size: string) {
+ this.navigateTo('create');
+
+ cy.get('#name').type(name); // Enter in image name
+
+ // Select image pool
+ cy.contains('Loading...').should('not.exist');
+ this.selectOption('pool', pool);
+ cy.get('#pool').should('have.class', 'ng-valid'); // check if selected
+
+ // Enter in the size of the image
+ cy.get('#size').type(size);
+
+ // Click the create button and wait for image to be made
+ cy.get('[data-cy=submitBtn]').click();
+ this.getFirstTableCell(name).should('exist');
+ }
+
+ editImage(name: string, pool: string, newName: string, newSize: string) {
+ this.navigateEdit(name);
+
+ // Wait until data is loaded
+ cy.get('#pool').should('contain.value', pool);
+
+ cy.get('#name').clear().type(newName);
+ cy.get('#size').clear().type(newSize); // click the size box and send new size
+
+ cy.get('[data-cy=submitBtn]').click();
+
+ this.getExpandCollapseElement(newName).click();
+ cy.get('.table.table-striped.table-bordered').contains('td', newSize);
+ }
+
+ // Selects RBD image and moves it to the trash,
+ // checks that it is present in the trash table
+ moveToTrash(name: string) {
+ // wait for image to be created
+ cy.get('.datatable-body').first().should('not.contain.text', '(Creating...)');
+
+ this.getFirstTableCell(name).click();
+
+ // click on the drop down and selects the move to trash option
+ cy.get('.table-actions button.dropdown-toggle').first().click();
+ cy.get('button.move-to-trash').click();
+
+ cy.get('[data-cy=submitBtn]').should('be.visible').click();
+
+ // Clicks trash tab
+ cy.contains('.nav-link', 'Trash').click();
+ this.getFirstTableCell(name).should('exist');
+ }
+
+ // Checks trash tab table for image and then restores it to the RBD Images table
+ // (could change name if new name is given)
+ restoreImage(name: string, newName?: string) {
+ // clicks on trash tab
+ cy.contains('.nav-link', 'Trash').click();
+
+ // wait for table to load
+ this.getFirstTableCell(name).click();
+ cy.contains('button', 'Restore').click();
+
+ // wait for pop-up to be visible (checks for title of pop-up)
+ cy.get('cd-modal #name').should('be.visible');
+
+ // If a new name for the image is passed, it changes the name of the image
+ if (newName !== undefined) {
+ // click name box and send new name
+ cy.get('cd-modal #name').clear().type(newName);
+ }
+
+ cy.get('[data-cy=submitBtn]').click();
+
+ // clicks images tab
+ cy.contains('.nav-link', 'Images').click();
+
+ this.getFirstTableCell(newName).should('exist');
+ }
+
+ // Enters trash tab and purges trash, thus emptying the trash table.
+ // Checks if Image is still in the table.
+ purgeTrash(name: string, pool?: string) {
+ // clicks trash tab
+ cy.contains('.nav-link', 'Trash').click();
+ cy.contains('button', 'Purge Trash').click();
+
+ // Check for visibility of modal container
+ cy.get('.modal-header').should('be.visible');
+
+ // If purgeing a specific pool, selects that pool if given
+ if (pool !== undefined) {
+ this.selectOption('poolName', pool);
+ cy.get('#poolName').should('have.class', 'ng-valid'); // check if pool is selected
+ }
+ cy.get('[data-cy=submitBtn]').click();
+ // Wait for image to delete and check it is not present
+
+ this.getFirstTableCell(name).should('not.exist');
+ }
+}
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/iscsi.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/iscsi.e2e-spec.ts
new file mode 100644
index 000000000..2788c4f9b
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/iscsi.e2e-spec.ts
@@ -0,0 +1,24 @@
+import { IscsiPageHelper } from './iscsi.po';
+
+describe('Iscsi Page', () => {
+ const iscsi = new IscsiPageHelper();
+
+ beforeEach(() => {
+ cy.login();
+ iscsi.navigateTo();
+ });
+
+ it('should open and show breadcrumb', () => {
+ iscsi.expectBreadcrumbText('Overview');
+ });
+
+ it('should check that tables are displayed and legends are correct', () => {
+ // Check tables are displayed
+ iscsi.getDataTables().its(0).should('be.visible');
+ iscsi.getDataTables().its(1).should('be.visible');
+
+ // Check that legends are correct
+ iscsi.getLegends().its(0).should('contain.text', 'Gateways');
+ iscsi.getLegends().its(1).should('contain.text', 'Images');
+ });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/iscsi.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/iscsi.po.ts
new file mode 100644
index 000000000..08efa6408
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/iscsi.po.ts
@@ -0,0 +1,7 @@
+import { PageHelper } from '../page-helper.po';
+
+export class IscsiPageHelper extends PageHelper {
+ pages = {
+ index: { url: '#/block/iscsi/overview', id: 'cd-iscsi' }
+ };
+}
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/mirroring.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/mirroring.e2e-spec.ts
new file mode 100644
index 000000000..fb7db2712
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/mirroring.e2e-spec.ts
@@ -0,0 +1,117 @@
+import { PoolPageHelper } from '../pools/pools.po';
+import { MirroringPageHelper } from './mirroring.po';
+
+describe('Mirroring page', () => {
+ const pools = new PoolPageHelper();
+ const mirroring = new MirroringPageHelper();
+
+ beforeEach(() => {
+ cy.login();
+ mirroring.navigateTo();
+ });
+
+ it('should open and show breadcrumb', () => {
+ mirroring.expectBreadcrumbText('Mirroring');
+ });
+
+ it('should show three tabs', () => {
+ mirroring.getTabsCount().should('eq', 3);
+ });
+
+ it('should show text for all tabs', () => {
+ mirroring.getTabText(0).should('eq', 'Issues (0)');
+ mirroring.getTabText(1).should('eq', 'Syncing (0)');
+ mirroring.getTabText(2).should('eq', 'Ready (0)');
+ });
+
+ describe('rbd mirroring bootstrap', () => {
+ const poolName = 'rbd-mirror';
+
+ beforeEach(() => {
+ // login to the second ceph cluster
+ cy.ceph2Login();
+ cy.login();
+ pools.navigateTo('create');
+ pools.create(poolName, 8, 'rbd');
+ pools.navigateTo();
+ pools.existTableCell(poolName, true);
+ mirroring.navigateTo();
+ });
+
+ it('should generate and import the bootstrap token between clusters', () => {
+ const url: string = Cypress.env('CEPH2_URL');
+ mirroring.navigateTo();
+ mirroring.generateToken(poolName);
+ cy.get('@token').then((bootstrapToken) => {
+ // pass the token to the origin as an arg
+ const args = { name: poolName, bootstrapToken: String(bootstrapToken) };
+ // can't use any imports or functions inside the origin
+ // so writing the code to copy the token inside the origin manually
+ // rather than using a function call
+ // @ts-ignore
+ cy.origin(url, { args }, ({ name, bootstrapToken }) => {
+ // Create an rbd pool in the second cluster
+
+ // Login to the second cluster
+ // Somehow its not working with the cypress login function
+ cy.visit('#/pool/create').wait(100);
+
+ cy.get('[name=username]').type('admin');
+ cy.get('#password').type('admin');
+ cy.get('[type=submit]').click();
+ cy.get('input[name=name]').clear().type(name);
+ cy.get(`select[name=poolType]`).select('replicated');
+ cy.get(`select[name=poolType] option:checked`).contains('replicated');
+ cy.get('.float-start.me-2.select-menu-edit').click();
+ cy.get('.popover-body').should('be.visible');
+ // Choose rbd as the application label
+ cy.get('.select-menu-item-content').contains('rbd').click();
+ cy.get('cd-submit-button').click();
+ cy.get('cd-pool-list').should('exist');
+
+ cy.visit('#/block/mirroring').wait(1000);
+ cy.get('.table-actions button.dropdown-toggle').first().click();
+ cy.get('[aria-label="Import Bootstrap Token"]').click();
+ cy.get('cd-bootstrap-import-modal').within(() => {
+ cy.get(`label[for=${name}]`).click();
+ cy.get('textarea[id=token]').wait(100).type(bootstrapToken);
+ cy.get('button[type=submit]').click();
+ });
+ });
+ });
+
+ // login again since origin removes all the cookies
+ // sessions, localStorage items etc..
+ cy.login();
+ mirroring.navigateTo();
+ mirroring.checkPoolHealthStatus(poolName, 'OK');
+ });
+ });
+
+ describe('checks that edit mode functionality shows in the pools table', () => {
+ const poolName = 'mirroring_test';
+
+ beforeEach(() => {
+ pools.navigateTo('create'); // Need pool for mirroring testing
+ pools.create(poolName, 8, 'rbd');
+ pools.navigateTo();
+ pools.existTableCell(poolName, true);
+ });
+
+ it('tests editing mode for pools', () => {
+ mirroring.navigateTo();
+
+ mirroring.editMirror(poolName, 'Pool');
+ mirroring.getFirstTableCell('pool').should('be.visible');
+ mirroring.editMirror(poolName, 'Image');
+ mirroring.getFirstTableCell('image').should('be.visible');
+ mirroring.editMirror(poolName, 'Disabled');
+ mirroring.getFirstTableCell('disabled').should('be.visible');
+ });
+
+ afterEach(() => {
+ pools.navigateTo();
+ pools.delete(poolName);
+ });
+ });
+});
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/mirroring.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/mirroring.po.ts
new file mode 100644
index 000000000..c4adca8b7
--- /dev/null
+++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/block/mirroring.po.ts
@@ -0,0 +1,61 @@
+import { PageHelper } from '../page-helper.po';
+
+const pages = {
+ index: { url: '#/block/mirroring', id: 'cd-mirroring' }
+};
+
+export class MirroringPageHelper extends PageHelper {
+ pages = pages;
+
+ poolsColumnIndex = {
+ name: 1,
+ health: 6
+ };
+
+ /**
+ * Goes to the mirroring page and edits a pool in the Pool table. Clicks on the
+ * pool and chooses an option (either pool, image, or disabled)
+ */
+ @PageHelper.restrictTo(pages.index.url)
+ editMirror(name: string, option: string) {
+ // Clicks the pool in the table
+ this.getFirstTableCell(name).click();
+
+ // Clicks the Edit Mode button
+ cy.contains('button', 'Edit Mode').click();
+
+ // Clicks the drop down in the edit pop-up, then clicks the Update button
+ cy.get('.modal-content').should('be.visible');
+ this.selectOption('mirrorMode', option);
+
+ // Clicks update button and checks if the mode has been changed
+ cy.contains('button', 'Update').click();
+ cy.contains('.modal-dialog', 'Edit pool mirror mode').should('not.exist');
+ const val = option.toLowerCase(); // used since entries in table are lower case
+ this.getFirstTableCell(val).should('be.visible');
+ }
+
+ @PageHelper.restrictTo(pages.index.url)
+ generateToken(poolName: string) {
+ cy.get('[aria-label="Create Bootstrap Token"]').first().click();
+ cy.get('cd-bootstrap-create-modal').within(() => {
+ cy.get(`label[for=${poolName}]`).click();
+ cy.get('button[type=submit]').click();
+ cy.get('textarea[id=token]').wait(200).invoke('val').as('token');
+ cy.get('[aria-label="Back"]').click();
+ });
+ }
+
+ @PageHelper.restrictTo(pages.index.url)
+ checkPoolHealthStatus(poolName: string, status: string) {
+ cy.get('cd-mirroring-pools').within(() => {
+ this.getTableCell(this.poolsColumnIndex.name, poolName)
+ .parent()
+ .find(`datatable-body-cell:nth-child(${this.poolsColumnIndex.health}) .badge`)
+ .should(($ele) => {
+ const newLabels = $ele.toArray().map((v) => v.innerText);
+ expect(newLabels).to.include(status);
+ });
+ });
+ }
+}