From a18d515c4cd111db363c0fd49f00c4287235091e Mon Sep 17 00:00:00 2001 From: Rafael Quintero Date: Thu, 8 Aug 2019 11:25:46 -0400 Subject: [PATCH] mgr/dashboard: RBD Image Purge Trash, Move to Trash and Restore Fixes: https://tracker.ceph.com/issues/40922 Fixes: https://tracker.ceph.com/issues/40928 Signed-off-by: Adam King Signed-off-by: Rafael Quintero --- .../frontend/e2e/block/images.e2e-spec.ts | 49 +++++++++++++ .../dashboard/frontend/e2e/block/images.po.ts | 72 +++++++++++++++++++ .../rbd-trash-purge-modal.component.html | 7 +- 3 files changed, 126 insertions(+), 2 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/e2e/block/images.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/e2e/block/images.e2e-spec.ts index 724a8963d35..e5adea06ffa 100644 --- a/src/pybind/mgr/dashboard/frontend/e2e/block/images.e2e-spec.ts +++ b/src/pybind/mgr/dashboard/frontend/e2e/block/images.e2e-spec.ts @@ -70,4 +70,53 @@ describe('Images page', () => { await pools.exist(poolName, false); }); }); + + describe('move to trash, restore and purge image tests', () => { + const poolName = 'trashpool'; + const imageName = 'trashimage'; + const newImageName = 'newtrashimage'; + + beforeAll(async () => { + await pools.navigateTo('create'); // Need pool for image testing + await pools.create(poolName, 8, 'rbd'); + await pools.navigateTo(); + await pools.exist(poolName, true); + + await images.navigateTo(); // Need image for trash testing + await images.createImage(imageName, poolName, '1'); + await expect(images.getTableCell(imageName).isPresent()).toBe(true); + }); + + it('should move the image to the trash', async () => { + await images.moveToTrash(imageName); + await expect(images.getTableCell(imageName).isPresent()).toBe(true); + }); + + it('should restore image to images table', async () => { + await images.restoreImage(imageName, newImageName); + await expect(images.getTableCell(newImageName).isPresent()).toBe(true); + }); + + it('should purge trash in images trash tab', async () => { + await images.navigateTo(); + // Have had issues with image not restoring fast enough, thus these tests/waits are here + await images.waitPresence( + images.getTableCell(newImageName), + 'Timed out waiting for image to restore' + ); + await images.waitClickable( + images.getTableCell(newImageName), + 'Timed out waiting for image to be clickable' + ); + await images.moveToTrash(newImageName); + await images.purgeTrash(newImageName, poolName); + }); + + afterAll(async () => { + await pools.navigateTo(); + await pools.delete(poolName); // Deletes images test pool + await pools.navigateTo(); + await pools.exist(poolName, false); + }); + }); }); diff --git a/src/pybind/mgr/dashboard/frontend/e2e/block/images.po.ts b/src/pybind/mgr/dashboard/frontend/e2e/block/images.po.ts index 0b82b7131d9..a8e938295e4 100644 --- a/src/pybind/mgr/dashboard/frontend/e2e/block/images.po.ts +++ b/src/pybind/mgr/dashboard/frontend/e2e/block/images.po.ts @@ -60,6 +60,7 @@ export class ImagesPageHelper extends PageHelper { ).toMatch(newSize); } + // Deletes RBD image from table and checks that it is not present async deleteImage(name) { await this.navigateTo(); @@ -76,4 +77,75 @@ export class ImagesPageHelper extends PageHelper { await element(by.cssContainingText('button', 'Delete RBD')).click(); await this.waitStaleness(this.getTableCell(name)); } + + // Selects RBD image and moves it to the trash, checks that it is present in the + // trash table + async moveToTrash(name) { + await this.navigateTo(); + // wait for image to be created + await this.waitTextNotPresent($$('.datatable-body').first(), '(Creating...)'); + await this.waitClickable(this.getTableCell(name)); + await this.getTableCell(name).click(); + // click on the drop down and selects the move to trash option + await $$('.table-actions button.dropdown-toggle') + .first() + .click(); + await $('li.move-to-trash').click(); + await this.waitVisibility(element(by.cssContainingText('button', 'Move Image'))); + await element(by.cssContainingText('button', 'Move Image')).click(); + await this.navigateTo(); + // Clicks trash tab + await this.waitClickable(element(by.cssContainingText('.nav-link', 'Trash'))); + await element(by.cssContainingText('.nav-link', 'Trash')).click(); + } + + // Checks trash tab table for image and then restores it to the RBD Images table + // (could change name if new name is given) + async restoreImage(name, newName?: string) { + await this.navigateTo(); + // clicks on trash tab + await element(by.cssContainingText('.nav-link', 'Trash')).click(); + // wait for table to load + await this.waitClickable(this.getTableCell(name)); + await this.getTableCell(name).click(); + await element(by.cssContainingText('button', 'Restore')).click(); + // wait for pop-up to be visible (checks for title of pop-up) + await this.waitVisibility(element(by.id('name'))); + // If a new name for the image is passed, it changes the name of the image + if (newName !== undefined) { + await element(by.id('name')).click(); // click name box and send new name + await element(by.id('name')).clear(); + await element(by.id('name')).sendKeys(newName); + } + await element(by.cssContainingText('button', 'Restore Image')).click(); + await this.navigateTo(); + // clicks images tab + await element(by.cssContainingText('.nav-link', 'Images')).click(); + await this.navigateTo(); + await this.waitPresence(this.getTableCell(newName)); + } + + // Enters trash tab and purges trash, thus emptying the trash table. Checks if + // Image is still in the table. + async purgeTrash(name, pool?: string) { + await this.navigateTo(); + // clicks trash tab + await element(by.cssContainingText('.nav-link', 'Trash')).click(); + await element(by.cssContainingText('button', 'Purge Trash')).click(); + // Check for visibility of modal container + await this.waitVisibility(element(by.id('poolName'))); + // If purgeing a specific pool, selects that pool if given + if (pool !== undefined) { + const getPoolName = `[value="${pool}"]`; + await element(by.id('poolName')).click(); + await element(by.cssContainingText('select[name=poolName] option', pool)).click(); + await $(getPoolName).click(); + await expect(element(by.id('poolName')).getAttribute('class')).toContain('ng-valid'); // check if pool is selected + } + await this.waitClickable(element(by.id('purgeFormButton'))); + await element(by.id('purgeFormButton')).click(); + // Wait for image to delete and check it is not present + await this.waitStaleness(this.getTableCell(name), 'Timed out waiting for image to be purged'); + await expect(this.getTableCell(name).isPresent()).toBe(false); + } } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.html index c95556dbac1..6c26f4a731c 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.html @@ -23,7 +23,9 @@ i18n-placeholder formControlName="poolName" *ngIf="!poolPermission.read"> -