]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/dashboard: RBD Image Purge Trash, Move to Trash and Restore
authorRafael Quintero <rafaelq@bu.edu>
Thu, 8 Aug 2019 15:25:46 +0000 (11:25 -0400)
committerAdam King <kingamk3@gmail.com>
Fri, 30 Aug 2019 17:37:05 +0000 (13:37 -0400)
Fixes: https://tracker.ceph.com/issues/40922
Fixes: https://tracker.ceph.com/issues/40928
Signed-off-by: Adam King <adking@redhat.com>
Signed-off-by: Rafael Quintero <rquinter@redhat.com>
src/pybind/mgr/dashboard/frontend/e2e/block/images.e2e-spec.ts
src/pybind/mgr/dashboard/frontend/e2e/block/images.po.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-trash-purge-modal/rbd-trash-purge-modal.component.html

index 724a8963d359b2a7e7e700291eff03572943c2ab..e5adea06ffa115bf766d90d599e7af620cdcdd5c 100644 (file)
@@ -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);
+    });
+  });
 });
index 0b82b7131d905b6560d3872679aede31c27ee9bd..a8e938295e460dbe9f13ba096f2400afa12a577e 100644 (file)
@@ -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);
+  }
 }
index c95556dbac17c209cef675c2f226fd09af9d8270..6c26f4a731c10d7a9a9e062a9a199f9ccc639028 100644 (file)
@@ -23,7 +23,9 @@
                  i18n-placeholder
                  formControlName="poolName"
                  *ngIf="!poolPermission.read">
-          <select class="form-control custom-select"
+          <select id="poolName"
+                  name="poolName"
+                  class="form-control custom-select"
                   formControlName="poolName"
                   *ngIf="poolPermission.read">
             <option value=""
@@ -36,7 +38,8 @@
 
       <div class="modal-footer">
         <div class="button-group text-right">
-          <cd-submit-button [form]="purgeForm"
+          <cd-submit-button id="purgeFormButton"
+                            [form]="purgeForm"
                             (submitAction)="purge()"
                             i18n>Purge Trash</cd-submit-button>
           <cd-back-button [back]="modalRef.hide"