]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: E2E Test for RBD Mirroring and Images 29381/head
authorRafael Quintero <rafaelq@bu.edu>
Mon, 29 Jul 2019 13:02:12 +0000 (09:02 -0400)
committerRafael Quintero <rafaelq@bu.edu>
Wed, 14 Aug 2019 13:06:04 +0000 (09:06 -0400)
Fixes: https://tracker.ceph.com/issues/38701
Fixes: https://tracker.ceph.com/issues/40581
Fixes: https://tracker.ceph.com/issues/40956
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/e2e/block/mirroring.e2e-spec.ts
src/pybind/mgr/dashboard/frontend/e2e/block/mirroring.po.ts
src/pybind/mgr/dashboard/frontend/e2e/pools/pools.po.ts

index 44c97415e344df76670fd22dd6bc6e4fef7bc5e6..290d78eaae3aece2d4d3cdb01b3f451ee46a5811 100644 (file)
@@ -2,9 +2,11 @@ import { Helper } from '../helper.po';
 
 describe('Images page', () => {
   let images: Helper['images'];
+  let pools: Helper['pools'];
 
   beforeAll(() => {
     images = new Helper().images;
+    pools = new Helper().pools;
   });
 
   afterEach(() => {
@@ -30,4 +32,42 @@ describe('Images page', () => {
       expect(images.getTabText(2)).toEqual('Overall Performance');
     });
   });
+
+  describe('create, edit & delete image test', () => {
+    const poolName = 'e2e_images_pool';
+    const imageName = 'e2e_images_image';
+    const newImageName = 'e2e_images_image_new';
+
+    beforeAll(() => {
+      pools.navigateTo('create'); // Need pool for image testing
+      pools.create(poolName, 8, 'rbd').then(() => {
+        pools.navigateTo();
+        pools.exist(poolName, true);
+      });
+      images.navigateTo();
+    });
+
+    it('should create image', () => {
+      images.createImage(imageName, poolName, '1');
+      expect(images.getTableCell(imageName).isPresent()).toBe(true);
+    });
+
+    it('should edit image', () => {
+      images.editImage(imageName, poolName, newImageName, '2');
+      expect(images.getTableCell(newImageName).isPresent()).toBe(true);
+    });
+
+    it('should delete image', () => {
+      images.deleteImage(newImageName);
+      expect(images.getTableCell(newImageName).isPresent()).toBe(false);
+    });
+
+    afterAll(() => {
+      pools.navigateTo(); // Deletes images test pool
+      pools.delete(poolName).then(() => {
+        pools.navigateTo();
+        pools.exist(poolName, false);
+      });
+    });
+  });
 });
index ad659ed33accdae6ce4527aa0dae109a482a16d0..eec5642f48b2fa9173bc7c2879b80cef8ce02711 100644 (file)
@@ -1,5 +1,92 @@
+import { $, $$, browser, by, element } from 'protractor';
+import { Helper } from '../helper.po';
 import { PageHelper } from '../page-helper.po';
 
 export class ImagesPageHelper extends PageHelper {
-  pages = { index: '/#/block/rbd' };
+  pages = {
+    index: '/#/block/rbd',
+    create: '/#/block/rbd/create'
+  };
+
+  // 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, pool, size) {
+    this.navigateTo('create');
+
+    // Need the string '[value="<pool>"]' to find the pool in the dropdown menu
+    const getPoolName = `[value="${pool}"]`;
+
+    element(by.id('name')).sendKeys(name); // Enter in image name
+
+    // Select image pool
+    element(by.id('pool')).click();
+    element(by.cssContainingText('select[name=pool] option', pool)).click();
+    $(getPoolName).click();
+    expect(element(by.id('pool')).getAttribute('class')).toContain('ng-valid'); // check if selected
+
+    // Enter in the size of the image
+    element(by.id('size')).click();
+    element(by.id('size')).sendKeys(size);
+
+    // Click the create button and wait for image to be made
+    element(by.cssContainingText('button', 'Create RBD'))
+      .click()
+      .then(() => {
+        browser.wait(Helper.EC.presenceOf(this.getTableCell(name)), Helper.TIMEOUT);
+      });
+  }
+
+  editImage(name, pool, newName, newSize) {
+    const base_url = '/#/block/rbd/edit/';
+    const editURL = base_url
+      .concat(pool)
+      .concat('/')
+      .concat(name);
+    browser.get(editURL);
+
+    element(by.id('name')).click(); // click name box and send new name
+    element(by.id('name')).clear();
+    element(by.id('name')).sendKeys(newName);
+    element(by.id('size')).click();
+    element(by.id('size')).clear();
+    element(by.id('size')).sendKeys(newSize); // click the size box and send new size
+
+    element(by.cssContainingText('button', 'Edit RBD'))
+      .click()
+      .then(() => {
+        this.navigateTo();
+        browser
+          .wait(Helper.EC.elementToBeClickable(this.getTableCell(newName)), Helper.TIMEOUT)
+          .then(() => {
+            this.getTableCell(newName).click();
+            expect(
+              element
+                .all(by.css('.table.table-striped.table-bordered'))
+                .first()
+                .getText()
+            ).toMatch(newSize);
+          }); // click edit button and wait to make sure new owner is present in table
+      });
+  }
+
+  deleteImage(name) {
+    this.navigateTo();
+
+    // wait for table to load
+    browser.wait(Helper.EC.elementToBeClickable(this.getTableCell(name)), Helper.TIMEOUT);
+    this.getTableCell(name).click(); // click on the image you want to delete in the table
+    $$('.table-actions button.dropdown-toggle')
+      .first()
+      .click(); // click toggle menu
+    $('li.delete.ng-star-inserted').click(); // click delete
+    // wait for pop-up to be visible (checks for title of pop-up)
+    browser.wait(Helper.EC.visibilityOf($('.modal-body')), Helper.TIMEOUT).then(() => {
+      $('.custom-control-label').click(); // click confirmation checkbox
+      element(by.cssContainingText('button', 'Delete RBD'))
+        .click()
+        .then(() => {
+          browser.wait(Helper.EC.stalenessOf(this.getTableCell(name)), Helper.TIMEOUT);
+        });
+    });
+  }
 }
index b0108f0cb5c4a2e725895e2b9ed1054501ebb66f..9b1695517dd7bfcfa0f446b4fc6b5cfce0743512 100644 (file)
@@ -2,9 +2,11 @@ import { Helper } from '../helper.po';
 
 describe('Mirroring page', () => {
   let mirroring: Helper['mirroring'];
+  let pools: Helper['pools'];
 
   beforeAll(() => {
     mirroring = new Helper().mirroring;
+    pools = new Helper().pools;
   });
 
   afterEach(() => {
@@ -30,4 +32,34 @@ describe('Mirroring page', () => {
       expect(mirroring.getTabText(2)).toEqual('Ready');
     });
   });
+
+  describe('checks that edit mode functionality shows in the pools table', () => {
+    const poolName = 'mirrorpoolrq';
+
+    beforeAll(() => {
+      pools.navigateTo('create'); // Need pool for mirroring testing
+      pools.create(poolName, 8, 'rbd').then(() => {
+        pools.navigateTo();
+        pools.exist(poolName, true);
+      });
+    });
+
+    it('tests editing mode for pools', () => {
+      mirroring.navigateTo();
+      expect(mirroring.editMirror(poolName, 'Pool'));
+      expect(mirroring.getFirstTableCellWithText('pool').isPresent()).toBe(true);
+      expect(mirroring.editMirror(poolName, 'Image'));
+      expect(mirroring.getFirstTableCellWithText('image').isPresent()).toBe(true);
+      expect(mirroring.editMirror(poolName, 'Disabled'));
+      expect(mirroring.getFirstTableCellWithText('disabled').isPresent()).toBe(true);
+    });
+
+    afterAll(() => {
+      pools.navigateTo(); // Deletes mirroring test pool
+      pools.delete(poolName).then(() => {
+        pools.navigateTo();
+        pools.exist(poolName, false);
+      });
+    });
+  });
 });
index f1d562ca4c4c1d20dc908ccab7c21b4a4e8a1e6d..b9d778044589f7b5c5f1c9b66ee48b2eb0609078 100644 (file)
@@ -1,5 +1,50 @@
+import { $, browser, by, element } from 'protractor';
+import { Helper } from '../helper.po';
 import { PageHelper } from '../page-helper.po';
 
 export class MirroringPageHelper extends PageHelper {
   pages = { index: '/#/block/mirroring' };
+
+  // Goes to the mirroring page and edits a pool in the Pool table. Clicks on the
+  // pool and chooses a option (either pool, image, or disabled)
+  editMirror(name, option) {
+    this.navigateTo();
+    // Clicks the pool in the table
+    browser
+      .wait(Helper.EC.elementToBeClickable(this.getFirstTableCellWithText(name)), Helper.TIMEOUT)
+      .then(() => {
+        this.getFirstTableCellWithText(name).click();
+      });
+
+    // Clicks the Edit Mode button
+    const editModeButton = element(by.cssContainingText('button', 'Edit Mode'));
+    browser.wait(Helper.EC.elementToBeClickable(editModeButton), Helper.TIMEOUT).then(() => {
+      editModeButton.click();
+    });
+    // Clicks the drop down in the edit pop-up, then clicks the Update button
+    browser.wait(Helper.EC.visibilityOf($('.modal-content')), Helper.TIMEOUT).then(() => {
+      const mirrorDrop = element(by.id('mirrorMode'));
+      this.moveClick(mirrorDrop);
+      element(by.cssContainingText('select[name=mirrorMode] option', option)).click();
+    });
+    // Clicks update button and checks if the mode has been changed
+    element(by.cssContainingText('button', 'Update'))
+      .click()
+      .then(() => {
+        browser
+          .wait(
+            Helper.EC.stalenessOf(
+              element(by.cssContainingText('.modal-dialog', 'Edit pool mirror mode'))
+            ),
+            Helper.TIMEOUT
+          )
+          .then(() => {
+            const val = option.toLowerCase(); // used since entries in table are lower case
+            browser.wait(
+              Helper.EC.visibilityOf(this.getFirstTableCellWithText(val)),
+              Helper.TIMEOUT
+            );
+          });
+      });
+  }
 }
index 535542fcc841c29ed39eb71c89ddf64772b3e8b8..968bcde019f63cb3288b8c594e34751dd59282d5 100644 (file)
@@ -29,7 +29,7 @@ export class PoolPageHelper extends PageHelper {
   }
 
   @PageHelper.restrictTo(pages.create)
-  create(name: string, placement_groups: number): promise.Promise<any> {
+  create(name: string, placement_groups: number, ...apps: string[]): promise.Promise<any> {
     const nameInput = $('input[name=name]');
     nameInput.clear();
     if (!this.isPowerOf2(placement_groups)) {
@@ -45,12 +45,33 @@ export class PoolPageHelper extends PageHelper {
           $('input[name=pgNum]')
             .sendKeys(protractor.Key.CONTROL, 'a', protractor.Key.NULL, placement_groups)
             .then(() => {
+              this.setApplications(apps);
               return element(by.css('cd-submit-button')).click();
             });
         });
     });
   }
 
+  private setApplications(apps: string[]) {
+    if (!apps || apps.length === 0) {
+      return;
+    }
+    element(by.css('.float-left.mr-2.select-menu-edit'))
+      .click()
+      .then(() => {
+        browser
+          .wait(
+            Helper.EC.visibilityOf(element(by.css('.popover-content.popover-body'))),
+            Helper.TIMEOUT
+          )
+          .then(() =>
+            apps.forEach((app) =>
+              element(by.cssContainingText('.select-menu-item-content', app)).click()
+            )
+          );
+      });
+  }
+
   @PageHelper.restrictTo(pages.index)
   delete(name: string): promise.Promise<any> {
     return this.getTableCellByContent(name).then((tableCell: ElementFinder) => {
@@ -61,13 +82,17 @@ export class PoolPageHelper extends PageHelper {
             return $('li.delete a') // click on "delete" menu item
               .click()
               .then(() => {
-                const getConfirmationCheckbox = () => $('#confirmation');
                 browser
-                  .wait(() => EC.visibilityOf(getConfirmationCheckbox()), Helper.TIMEOUT)
+                  .wait(Helper.EC.visibilityOf($('.custom-control-label')), Helper.TIMEOUT)
                   .then(() => {
-                    this.moveClick(getConfirmationCheckbox()).then(() => {
-                      return element(by.cssContainingText('button', 'Delete Pool')).click(); // Click Delete item
-                    });
+                    const getConfirmationCheckbox = () => $('.custom-control-label');
+                    browser
+                      .wait(Helper.EC.visibilityOf(getConfirmationCheckbox()), Helper.TIMEOUT)
+                      .then(() => {
+                        this.moveClick(getConfirmationCheckbox()).then(() => {
+                          return element(by.cssContainingText('button', 'Delete Pool')).click(); // Click Delete item
+                        });
+                      });
                   });
               });
           });