]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: add Services e2e tests 41196/head
authorAvan Thakkar <athakkar@localhost.localdomain>
Thu, 6 May 2021 11:05:38 +0000 (16:35 +0530)
committerAvan Thakkar <athakkar@localhost.localdomain>
Tue, 11 May 2021 16:36:03 +0000 (22:06 +0530)
Fixes: https://tracker.ceph.com/issues/50567
Signed-off-by: Avan Thakkar <athakkar@redhat.com>
Introducing e2e tests for service creation for Ingress and RGW service types.

src/pybind/mgr/dashboard/frontend/cypress/integration/cluster/services.po.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/cypress/integration/orchestrator/05-services.e2e-spec.ts [new file with mode: 0644]
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/service-form/service-form.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/services/services.component.ts

diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/cluster/services.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/cluster/services.po.ts
new file mode 100644 (file)
index 0000000..18b17c2
--- /dev/null
@@ -0,0 +1,86 @@
+import { PageHelper } from '../page-helper.po';
+
+const pages = {
+  index: { url: '#/services', id: 'cd-services' },
+  create: { url: '#/services/create', id: 'cd-service-form' }
+};
+
+export class ServicesPageHelper extends PageHelper {
+  pages = pages;
+
+  columnIndex = {
+    service_name: 2,
+    container_image_name: 3,
+    container_image_id: 4,
+    placement: 5,
+    running: 6,
+    size: 7,
+    last_refresh: 8
+  };
+
+  check_for_service() {
+    this.getTableCount('total').should('not.be.eq', 0);
+  }
+
+  private selectServiceType(serviceType: string) {
+    return this.selectOption('service_type', serviceType);
+  }
+
+  @PageHelper.restrictTo(pages.create.url)
+  addService(serviceType: string, exist?: boolean) {
+    cy.get(`${this.pages.create.id}`).within(() => {
+      this.selectServiceType(serviceType);
+      if (serviceType === 'rgw') {
+        cy.get('#service_id').type('rgw.foo');
+        cy.get('#count').type('1');
+      } else if (serviceType === 'ingress') {
+        this.selectOption('backend_service', 'rgw.rgw.foo');
+        cy.get('#service_id').type('rgw.rgw.foo');
+        cy.get('#virtual_ip').type('192.168.20.1/24');
+        cy.get('#frontend_port').type('8081');
+        cy.get('#monitor_port').type('8082');
+      }
+
+      cy.get('cd-submit-button').click();
+    });
+    if (exist) {
+      cy.get('#service_id').should('have.class', 'ng-invalid');
+    } else {
+      // back to service list
+      cy.get(`${this.pages.index.id}`);
+    }
+  }
+
+  @PageHelper.restrictTo(pages.index.url)
+  checkExist(serviceName: string, exist: boolean) {
+    this.getTableCell(this.columnIndex.service_name, serviceName).should(($elements) => {
+      const services = $elements.map((_, el) => el.textContent).get();
+      if (exist) {
+        expect(services).to.include(serviceName);
+      } else {
+        expect(services).to.not.include(serviceName);
+      }
+    });
+  }
+
+  @PageHelper.restrictTo(pages.index.url)
+  deleteService(serviceName: string, wait: number) {
+    const getRow = this.getTableCell.bind(this, this.columnIndex.service_name);
+    getRow(serviceName).click();
+
+    // Clicks on table Delete button
+    this.clickActionButton('delete');
+
+    // Confirms deletion
+    cy.get('cd-modal .custom-control-label').click();
+    cy.contains('cd-modal button', 'Delete').click();
+
+    // Wait for modal to close
+    cy.get('cd-modal').should('not.exist');
+
+    // wait for delete operation to complete: tearing down the service daemons
+    cy.wait(wait);
+
+    this.checkExist(serviceName, false);
+  }
+}
diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/orchestrator/05-services.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/orchestrator/05-services.e2e-spec.ts
new file mode 100644 (file)
index 0000000..dec84d7
--- /dev/null
@@ -0,0 +1,29 @@
+import { ServicesPageHelper } from '../cluster/services.po';
+
+describe('Services page', () => {
+  const services = new ServicesPageHelper();
+
+  beforeEach(() => {
+    cy.login();
+    Cypress.Cookies.preserveOnce('token');
+    services.navigateTo();
+  });
+
+  describe('when Orchestrator is available', () => {
+    it('should create an rgw service', () => {
+      services.navigateTo('create');
+      services.addService('rgw');
+
+      services.checkExist('rgw.rgw.foo', true);
+    });
+
+    it('should create and delete an ingress service', () => {
+      services.navigateTo('create');
+      services.addService('ingress');
+
+      services.checkExist('ingress.rgw.rgw.foo', true);
+
+      services.deleteService('ingress.rgw.rgw.foo', 5000);
+    });
+  });
+});
index 4774299b78d93a54aa8937bee945314b4f96a341..a0df3a5d4b0a752b2233523ca87ebeabdd62d249 100644 (file)
@@ -14,6 +14,7 @@
                  i18n>Type</label>
           <div class="cd-col-form-input">
             <select id="service_type"
+                    name="service_type"
                     class="form-control custom-select"
                     formControlName="service_type">
               <option i18n
index 75ddd1c46175350c164f8264628daf3379b688cf..94b47f4f56d1bfabd3dacb3f0e8ac9c32c4bd560 100644 (file)
@@ -1,6 +1,6 @@
 import { Component, Input, OnChanges, OnInit, ViewChild } from '@angular/core';
 
-import { delay, finalize } from 'rxjs/operators';
+import { delay } from 'rxjs/operators';
 
 import { CephServiceService } from '~/app/shared/api/ceph-service.service';
 import { OrchestratorService } from '~/app/shared/api/orchestrator.service';
@@ -201,15 +201,10 @@ export class ServicesComponent extends ListWithDetails implements OnChanges, OnI
           })
           .pipe(
             // Delay closing the dialog, otherwise the datatable still
-            // shows the deleted service after forcing a reload.
+            // shows the deleted service after an auto-reload.
             // Showing the dialog while delaying is done to increase
             // the user experience.
-            delay(2000),
-            finalize(() => {
-              // Force reloading the data table content because it is
-              // auto-reloaded only every 60s.
-              this.table.refreshBtn();
-            })
+            delay(5000)
           )
     });
   }