]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Write E2E test to verify that Manager modules have editing functionality 29407/head
authorRafael Quintero <rafaelq@bu.edu>
Tue, 30 Jul 2019 20:49:24 +0000 (16:49 -0400)
committerRafael Quintero <rafaelq@bu.edu>
Tue, 6 Aug 2019 18:05:35 +0000 (14:05 -0400)
Fixes: https://tracker.ceph.com/issues/40823
Signed-off-by: Adam King <adking@redhat.com>
Signed-off-by: Rafael Quintero <rquinter@redhat.com>
src/pybind/mgr/dashboard/frontend/e2e/cluster/mgr-modules.e2e-spec.ts
src/pybind/mgr/dashboard/frontend/e2e/cluster/mgr-modules.po.ts
src/pybind/mgr/dashboard/frontend/e2e/page-helper.po.ts

index 2dc916b0ba43fec0d62d973178a34ebded6b2f19..0da02af6b396fd9672fa6d1500e08e56cb071442 100644 (file)
@@ -20,4 +20,44 @@ describe('Manager modules page', () => {
       expect(mgrmodules.getBreadcrumbText()).toEqual('Manager modules');
     });
   });
+
+  describe('verifies editing functionality for manager modules', () => {
+    beforeAll(() => {
+      mgrmodules.navigateTo();
+    });
+
+    it('should test editing on ansible module', () => {
+      const ansibleArr = [['rq', 'ca_bundle'], ['colts', 'server_location']];
+      mgrmodules.editMgrModule('ansible', ansibleArr);
+    });
+
+    it('should test editing on deepsea module', () => {
+      const deepseaArr = [
+        ['rq', 'salt_api_eauth'],
+        ['alm', 'salt_api_password'],
+        ['bu', 'salt_api_url'],
+        ['sox', 'salt_api_username']
+      ];
+      mgrmodules.editMgrModule('deepsea', deepseaArr);
+    });
+
+    it('should test editing on diskprediction_local module', () => {
+      const diskpredLocalArr = [['11', 'predict_interval'], ['0122', 'sleep_interval']];
+      mgrmodules.editMgrModule('diskprediction_local', diskpredLocalArr);
+    });
+
+    it('should test editing on balancer module', () => {
+      const balancerArr = [['rq', 'pool_ids']];
+      mgrmodules.editMgrModule('balancer', balancerArr);
+    });
+
+    it('should test editing on dashboard module', () => {
+      const dashboardArr = [['rq', 'AUDIT_API_ENABLED'], ['rafa', 'GRAFANA_API_PASSWORD']];
+      mgrmodules.editMgrModule('dashboard', dashboardArr);
+    });
+
+    it('should test editing on devicehealth module', () => {
+      mgrmodules.editDevicehealth('1987', 'sox', '1999', '2020', '456', '567');
+    });
+  });
 });
index 63306c3e214080c33ab585822f6492727e9db629..4d6bd91825edcd050a7a3f8525df8d2ab98a3456 100644 (file)
@@ -1,5 +1,212 @@
+import { $$, browser, by, element } from 'protractor';
+import { Helper } from '../helper.po';
 import { PageHelper } from '../page-helper.po';
 
 export class ManagerModulesPageHelper extends PageHelper {
-  pages = { index: '/#/mgr-modules' };
+  pages = {
+    index: '/#/mgr-modules'
+  };
+
+  // NOTABLE ISSUES: .clear() does not work on most text boxes, therefore using sendKeys
+  // a Ctrl + 'a' BACK_SPACE is used.
+  // The need to click the module repeatedly in the table is to ensure
+  // that the values in the details tab updated. This fixed a bug I experienced.
+
+  editMgrModule(name: string, tuple: string[][]) {
+    // Selects the Manager Module and then fills in the desired fields.
+    // Doesn't check/uncheck boxes because it is not reflected in the details table.
+    // DOES NOT WORK FOR ALL MGR MODULES, for example, Device health
+    this.navigateTo();
+    browser.wait(Helper.EC.elementToBeClickable(this.getTableCell(name)), Helper.TIMEOUT);
+    this.getTableCell(name).click();
+    element(by.cssContainingText('button', 'Edit')).click();
+
+    for (const entry of tuple) {
+      // Clears fields and adds edits
+      this.inputClear(element(by.id(entry[1])));
+      element(by.id(entry[1])).sendKeys(entry[0]);
+    }
+
+    element(by.cssContainingText('button', 'Update'))
+      .click()
+      .then(() => {
+        // Checks if edits appear
+        this.navigateTo();
+        browser.wait(Helper.EC.visibilityOf(this.getTableCell(name)), Helper.TIMEOUT).then(() => {
+          this.getTableCell(name)
+            .click()
+            .then(() => {
+              for (const entry of tuple) {
+                browser.wait(
+                  Helper.EC.textToBePresentInElement($$('.datatable-body').last(), entry[0]),
+                  Helper.TIMEOUT
+                );
+              }
+            });
+        });
+      });
+
+    // Clear mgr module of all edits made to it
+    this.navigateTo();
+    browser.wait(Helper.EC.elementToBeClickable(this.getTableCell(name)), Helper.TIMEOUT);
+    this.getTableCell(name).click();
+    element(by.cssContainingText('button', 'Edit')).click();
+
+    // Clears the editable fields
+    for (const entry of tuple) {
+      this.inputClear(element(by.id(entry[1])));
+    }
+
+    // Checks that clearing represents in details tab of module
+    element(by.cssContainingText('button', 'Update'))
+      .click()
+      .then(() => {
+        this.navigateTo();
+        browser.wait(Helper.EC.visibilityOf(this.getTableCell(name)), Helper.TIMEOUT).then(() => {
+          this.getTableCell(name)
+            .click()
+            .then(() => {
+              for (const entry of tuple) {
+                browser.wait(
+                  Helper.EC.not(
+                    Helper.EC.textToBePresentInElement($$('.datatable-body').last(), entry[0])
+                  ),
+                  Helper.TIMEOUT
+                );
+              }
+            });
+        });
+      });
+  }
+
+  editDevicehealth(
+    threshhold?: string,
+    pooln?: string,
+    retention?: string,
+    scrape?: string,
+    sleep?: string,
+    warn?: string
+  ) {
+    // Isn't called by editMgrModule since clearing doesn't work.
+    // Selects the Devicehealth manager module, then fills in the desired fields, including all fields except
+    // checkboxes. Clicking checkboxes has been a notable issue in Protractor, therefore they were omitted in this
+    // version of the tests. Could be added in a future PR. Then checks if these edits appear in the details table.
+    this.navigateTo();
+    let devHealthArray: [string, string][];
+    devHealthArray = [
+      [threshhold, 'mark_out_threshold'],
+      [pooln, 'pool_name'],
+      [retention, 'retention_period'],
+      [scrape, 'scrape_frequency'],
+      [sleep, 'sleep_interval'],
+      [warn, 'warn_threshold']
+    ];
+
+    browser.wait(Helper.EC.elementToBeClickable(this.getTableCell('devicehealth')), Helper.TIMEOUT);
+    this.getTableCell('devicehealth').click();
+    element(by.cssContainingText('button', 'Edit'))
+      .click()
+      .then(() => {
+        for (let i = 0, devHealthTuple; (devHealthTuple = devHealthArray[i]); i++) {
+          if (devHealthTuple[0] !== undefined) {
+            // Clears and inputs edits
+            this.inputClear(element(by.id(devHealthTuple[1])));
+            element(by.id(devHealthTuple[1])).sendKeys(devHealthTuple[0]);
+          }
+        }
+      });
+
+    element(by.cssContainingText('button', 'Update'))
+      .click()
+      .then(() => {
+        this.navigateTo();
+        browser
+          .wait(Helper.EC.visibilityOf(this.getTableCell('devicehealth')), Helper.TIMEOUT)
+          .then(() => {
+            // Checks for visibility of devicehealth in table
+            this.getTableCell('devicehealth')
+              .click()
+              .then(() => {
+                for (let i = 0, devHealthTuple; (devHealthTuple = devHealthArray[i]); i++) {
+                  if (devHealthTuple[0] !== undefined) {
+                    browser.wait(function() {
+                      // Repeatedly reclicks the module to check if edits has been done
+                      element(
+                        by.cssContainingText('.datatable-body-cell-label', 'devicehealth')
+                      ).click();
+                      return Helper.EC.textToBePresentInElement(
+                        $$('.datatable-body').last(),
+                        devHealthTuple[0]
+                      );
+                    }, Helper.TIMEOUT);
+                  }
+                }
+              });
+          });
+      });
+
+    // Inputs old values into devicehealth fields. This manager module doesnt allow for updates
+    // to be made when the values are cleared. Therefore, I restored them to their original values
+    // (on my local run of ceph-dev, this is subject to change i would assume). I'd imagine there is a
+    // better way of doing this.
+    this.navigateTo();
+    browser.wait(Helper.EC.elementToBeClickable(this.getTableCell('devicehealth')), Helper.TIMEOUT); // checks ansible
+    this.getTableCell('devicehealth').click();
+    element(by.cssContainingText('button', 'Edit'))
+      .click()
+      .then(() => {
+        this.inputClear(element(by.id('mark_out_threshold')));
+        element(by.id('mark_out_threshold')).sendKeys('2419200');
+
+        this.inputClear(element(by.id('pool_name')));
+        element(by.id('pool_name')).sendKeys('device_health_metrics');
+
+        this.inputClear(element(by.id('retention_period')));
+        element(by.id('retention_period')).sendKeys('15552000');
+
+        this.inputClear(element(by.id('scrape_frequency')));
+        element(by.id('scrape_frequency')).sendKeys('86400');
+
+        this.inputClear(element(by.id('sleep_interval')));
+        element(by.id('sleep_interval')).sendKeys('600');
+
+        this.inputClear(element(by.id('warn_threshold')));
+        element(by.id('warn_threshold')).sendKeys('7257600');
+      });
+
+    // Checks that clearing represents in details tab of ansible
+    browser
+      .wait(Helper.EC.elementToBeClickable(element(by.cssContainingText('button', 'Update'))))
+      .then(() => {
+        element(by.cssContainingText('button', 'Update'))
+          .click()
+          .then(() => {
+            this.navigateTo();
+            browser
+              .wait(Helper.EC.visibilityOf(this.getTableCell('devicehealth')), Helper.TIMEOUT)
+              .then(() => {
+                this.getTableCell('devicehealth')
+                  .click()
+                  .then(() => {
+                    for (let i = 0, devHealthTuple; (devHealthTuple = devHealthArray[i]); i++) {
+                      if (devHealthTuple[0] !== undefined) {
+                        browser.wait(function() {
+                          // Repeatedly reclicks the module to check if clearing has been done
+                          element(
+                            by.cssContainingText('.datatable-body-cell-label', 'devicehealth')
+                          ).click();
+                          return Helper.EC.not(
+                            Helper.EC.textToBePresentInElement(
+                              $$('.datatable-body').last(),
+                              devHealthTuple[0]
+                            )
+                          );
+                        }, Helper.TIMEOUT);
+                      }
+                    }
+                  });
+              });
+          });
+      });
+  }
 }
index 37dbc9668cd113970a13dd58d77e282e6aafbdda..3c4f417e22a5205dd19398dd97847e419126de26 100644 (file)
@@ -1,4 +1,4 @@
-import { $, $$, browser, by, element, ElementFinder, promise } from 'protractor';
+import { $, $$, browser, by, element, ElementFinder, promise, protractor } from 'protractor';
 
 interface Pages {
   index: string;
@@ -116,6 +116,12 @@ export abstract class PageHelper {
     });
   }
 
+  // used when .clear() does not work on a text box, sends a Ctrl + a, BACKSPACE
+  inputClear(elem) {
+    elem.sendKeys(protractor.Key.chord(protractor.Key.CONTROL, 'a'));
+    elem.sendKeys(protractor.Key.BACK_SPACE);
+  }
+
   navigateTo(page = null) {
     page = page || 'index';
     const url = this.pages[page];