From 19fcec84d8d7d21e796c7624e521b60d28ee21ed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:45:59 +0200 Subject: Adding upstream version 16.2.11+ds. Signed-off-by: Daniel Baumann --- .../cypress/integration/rgw/buckets.e2e-spec.ts | 62 +++++++ .../frontend/cypress/integration/rgw/buckets.po.ts | 193 +++++++++++++++++++++ .../cypress/integration/rgw/daemons.e2e-spec.ts | 35 ++++ .../frontend/cypress/integration/rgw/daemons.po.ts | 34 ++++ .../cypress/integration/rgw/users.e2e-spec.ts | 46 +++++ .../frontend/cypress/integration/rgw/users.po.ts | 139 +++++++++++++++ 6 files changed, 509 insertions(+) create mode 100644 src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/buckets.e2e-spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/buckets.po.ts create mode 100644 src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/daemons.e2e-spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/daemons.po.ts create mode 100644 src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/users.e2e-spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/users.po.ts (limited to 'src/pybind/mgr/dashboard/frontend/cypress/integration/rgw') diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/buckets.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/buckets.e2e-spec.ts new file mode 100644 index 000000000..e5ffdeee9 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/buckets.e2e-spec.ts @@ -0,0 +1,62 @@ +import { BucketsPageHelper } from './buckets.po'; + +describe('RGW buckets page', () => { + const buckets = new BucketsPageHelper(); + const bucket_name = 'e2ebucket'; + + beforeEach(() => { + cy.login(); + Cypress.Cookies.preserveOnce('token'); + buckets.navigateTo(); + }); + + describe('breadcrumb tests', () => { + it('should open and show breadcrumb', () => { + buckets.expectBreadcrumbText('Buckets'); + }); + }); + + describe('create, edit & delete bucket tests', () => { + it('should create bucket', () => { + buckets.navigateTo('create'); + buckets.create(bucket_name, BucketsPageHelper.USERS[0], 'default-placement'); + buckets.getFirstTableCell(bucket_name).should('exist'); + }); + + it('should edit bucket', () => { + buckets.edit(bucket_name, BucketsPageHelper.USERS[1]); + buckets.getDataTables().should('contain.text', BucketsPageHelper.USERS[1]); + }); + + it('should delete bucket', () => { + buckets.delete(bucket_name); + }); + + it('should create bucket with object locking enabled', () => { + buckets.navigateTo('create'); + buckets.create(bucket_name, BucketsPageHelper.USERS[0], 'default-placement', true); + buckets.getFirstTableCell(bucket_name).should('exist'); + }); + + it('should not allow to edit versioning if object locking is enabled', () => { + buckets.edit(bucket_name, BucketsPageHelper.USERS[1], true); + buckets.getDataTables().should('contain.text', BucketsPageHelper.USERS[1]); + + buckets.delete(bucket_name); + }); + }); + + describe('Invalid Input in Create and Edit tests', () => { + it('should test invalid inputs in create fields', () => { + buckets.testInvalidCreate(); + }); + + it('should test invalid input in edit owner field', () => { + buckets.navigateTo('create'); + buckets.create(bucket_name, BucketsPageHelper.USERS[0], 'default-placement'); + buckets.testInvalidEdit(bucket_name); + buckets.navigateTo(); + buckets.delete(bucket_name); + }); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/buckets.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/buckets.po.ts new file mode 100644 index 000000000..4804753d1 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/buckets.po.ts @@ -0,0 +1,193 @@ +import { PageHelper } from '../page-helper.po'; + +const pages = { + index: { url: '#/rgw/bucket', id: 'cd-rgw-bucket-list' }, + create: { url: '#/rgw/bucket/create', id: 'cd-rgw-bucket-form' } +}; + +export class BucketsPageHelper extends PageHelper { + static readonly USERS = ['dashboard', 'testid']; + + pages = pages; + + versioningStateEnabled = 'Enabled'; + versioningStateSuspended = 'Suspended'; + + private selectOwner(owner: string) { + return this.selectOption('owner', owner); + } + + private selectPlacementTarget(placementTarget: string) { + return this.selectOption('placement-target', placementTarget); + } + + private selectLockMode(lockMode: string) { + return this.selectOption('lock_mode', lockMode); + } + + @PageHelper.restrictTo(pages.create.url) + create(name: string, owner: string, placementTarget: string, isLocking = false) { + // Enter in bucket name + cy.get('#bid').type(name); + + // Select bucket owner + this.selectOwner(owner); + cy.get('#owner').should('have.class', 'ng-valid'); + + // Select bucket placement target: + this.selectPlacementTarget(placementTarget); + cy.get('#placement-target').should('have.class', 'ng-valid'); + + if (isLocking) { + cy.get('#lock_enabled').click({ force: true }); + // Select lock mode: + this.selectLockMode('Compliance'); + cy.get('#lock_mode').should('have.class', 'ng-valid'); + cy.get('#lock_retention_period_days').type('3'); + } + + // Click the create button and wait for bucket to be made + cy.contains('button', 'Create Bucket').click(); + + this.getFirstTableCell(name).should('exist'); + } + + @PageHelper.restrictTo(pages.index.url) + edit(name: string, new_owner: string, isLocking = false) { + this.navigateEdit(name); + + cy.get('input[name=placement-target]').should('have.value', 'default-placement'); + this.selectOwner(new_owner); + + // If object locking is enabled versioning shouldn't be visible + if (isLocking) { + cy.get('input[id=versioning]').should('be.disabled'); + cy.contains('button', 'Edit Bucket').click(); + + // wait to be back on buckets page with table visible and click + this.getExpandCollapseElement(name).click(); + + // check its details table for edited owner field + cy.get('.table.table-striped.table-bordered') + .first() + .should('contains.text', new_owner) + .as('bucketDataTable'); + + // Check versioning enabled: + cy.get('@bucketDataTable').find('tr').its(2).find('td').last().should('have.text', new_owner); + cy.get('@bucketDataTable').find('tr').its(11).find('td').last().as('versioningValueCell'); + + return cy.get('@versioningValueCell').should('have.text', this.versioningStateEnabled); + } + // Enable versioning + cy.get('input[id=versioning]').should('not.be.checked'); + cy.get('label[for=versioning]').click(); + cy.get('input[id=versioning]').should('be.checked'); + + cy.contains('button', 'Edit Bucket').click(); + + // wait to be back on buckets page with table visible and click + this.getExpandCollapseElement(name).click(); + + // check its details table for edited owner field + cy.get('.table.table-striped.table-bordered') + .first() + .should('contains.text', new_owner) + .as('bucketDataTable'); + + // Check versioning enabled: + cy.get('@bucketDataTable').find('tr').its(2).find('td').last().should('have.text', new_owner); + cy.get('@bucketDataTable').find('tr').its(11).find('td').last().as('versioningValueCell'); + + cy.get('@versioningValueCell').should('have.text', this.versioningStateEnabled); + + // Disable versioning: + this.navigateEdit(name); + + cy.get('label[for=versioning]').click(); + cy.get('input[id=versioning]').should('not.be.checked'); + cy.contains('button', 'Edit Bucket').click(); + + // Check versioning suspended: + this.getExpandCollapseElement(name).click(); + + return cy.get('@versioningValueCell').should('have.text', this.versioningStateSuspended); + } + + testInvalidCreate() { + this.navigateTo('create'); + cy.get('#bid').as('nameInputField'); // Grabs name box field + + // Gives an invalid name (too short), then waits for dashboard to determine validity + cy.get('@nameInputField').type('rq'); + + cy.contains('button', 'Create Bucket').click(); // To trigger a validation + + // Waiting for website to decide if name is valid or not + // Check that name input field was marked invalid in the css + cy.get('@nameInputField') + .should('not.have.class', 'ng-pending') + .and('have.class', 'ng-invalid'); + + // Check that error message was printed under name input field + cy.get('#bid + .invalid-feedback').should( + 'have.text', + 'Bucket names must be 3 to 63 characters long.' + ); + + // Test invalid owner input + // select some valid option. The owner drop down error message will not appear unless a valid user was selected at + // one point before the invalid placeholder user is selected. + this.selectOwner(BucketsPageHelper.USERS[1]); + + // select the first option, which is invalid because it is a placeholder + this.selectOwner('-- Select a user --'); + + cy.get('@nameInputField').click(); + + // Check that owner drop down field was marked invalid in the css + cy.get('#owner').should('have.class', 'ng-invalid'); + + // Check that error message was printed under owner drop down field + cy.get('#owner + .invalid-feedback').should('have.text', 'This field is required.'); + + // Check invalid placement target input + this.selectOwner(BucketsPageHelper.USERS[1]); + // The drop down error message will not appear unless a valid option is previsously selected. + this.selectPlacementTarget('default-placement'); + this.selectPlacementTarget('-- Select a placement target --'); + cy.get('@nameInputField').click(); // Trigger validation + cy.get('#placement-target').should('have.class', 'ng-invalid'); + cy.get('#placement-target + .invalid-feedback').should('have.text', 'This field is required.'); + + // Clicks the Create Bucket button but the page doesn't move. + // Done by testing for the breadcrumb + cy.contains('button', 'Create Bucket').click(); // Clicks Create Bucket button + this.expectBreadcrumbText('Create'); + // content in fields seems to subsist through tests if not cleared, so it is cleared + cy.get('@nameInputField').clear(); + return cy.contains('button', 'Cancel').click(); + } + + testInvalidEdit(name: string) { + this.navigateEdit(name); + + cy.get('input[id=versioning]').should('exist').and('not.be.checked'); + + // Chooses 'Select a user' rather than a valid owner on Edit Bucket page + // and checks if it's an invalid input + + // select the first option, which is invalid because it is a placeholder + this.selectOwner('-- Select a user --'); + + cy.contains('button', 'Edit Bucket').click(); + + // Check that owner drop down field was marked invalid in the css + cy.get('#owner').should('have.class', 'ng-invalid'); + + // Check that error message was printed under owner drop down field + cy.get('#owner + .invalid-feedback').should('have.text', 'This field is required.'); + + this.expectBreadcrumbText('Edit'); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/daemons.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/daemons.e2e-spec.ts new file mode 100644 index 000000000..4cad786c6 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/daemons.e2e-spec.ts @@ -0,0 +1,35 @@ +import { DaemonsPageHelper } from './daemons.po'; + +describe('RGW daemons page', () => { + const daemons = new DaemonsPageHelper(); + + beforeEach(() => { + cy.login(); + Cypress.Cookies.preserveOnce('token'); + daemons.navigateTo(); + }); + + describe('breadcrumb and tab tests', () => { + it('should open and show breadcrumb', () => { + daemons.expectBreadcrumbText('Daemons'); + }); + + it('should show two tabs', () => { + daemons.getTabsCount().should('eq', 2); + }); + + it('should show daemons list tab at first', () => { + daemons.getTabText(0).should('eq', 'Daemons List'); + }); + + it('should show overall performance as a second tab', () => { + daemons.getTabText(1).should('eq', 'Overall Performance'); + }); + }); + + describe('details and performance counters table tests', () => { + it('should check that details/performance tables are visible when daemon is selected', () => { + daemons.checkTables(); + }); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/daemons.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/daemons.po.ts new file mode 100644 index 000000000..82a179463 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/daemons.po.ts @@ -0,0 +1,34 @@ +import { PageHelper } from '../page-helper.po'; + +export class DaemonsPageHelper extends PageHelper { + pages = { + index: { url: '#/rgw/daemon', id: 'cd-rgw-daemon-list' } + }; + + getTableCell() { + return cy + .get('.tab-content') + .its(1) + .find('cd-table') + .should('have.length', 1) // Only 1 table should be renderer + .find('datatable-body-cell'); + } + + checkTables() { + // click on a daemon so details table appears + cy.get('.datatable-body-cell-label').first().click(); + + // check details table is visible + // check at least one field is present + this.getTableCell().should('be.visible').should('contain.text', 'ceph_version'); + + // click on performance counters tab and check table is loaded + cy.contains('.nav-link', 'Performance Counters').click(); + + // check at least one field is present + this.getTableCell().should('be.visible').should('contain.text', 'objecter.op_r'); + + // click on performance details tab + cy.contains('.nav-link', 'Performance Details').click(); + } +} diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/users.e2e-spec.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/users.e2e-spec.ts new file mode 100644 index 000000000..b5f366a09 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/users.e2e-spec.ts @@ -0,0 +1,46 @@ +import { UsersPageHelper } from './users.po'; + +describe('RGW users page', () => { + const users = new UsersPageHelper(); + const tenant = 'e2e_000tenant'; + const user_id = 'e2e_000user_create_edit_delete'; + const user_name = tenant + '$' + user_id; + + beforeEach(() => { + cy.login(); + Cypress.Cookies.preserveOnce('token'); + users.navigateTo(); + }); + + describe('breadcrumb tests', () => { + it('should open and show breadcrumb', () => { + users.expectBreadcrumbText('Users'); + }); + }); + + describe('create, edit & delete user tests', () => { + it('should create user', () => { + users.navigateTo('create'); + users.create(tenant, user_id, 'Some Name', 'original@website.com', '1200'); + users.getFirstTableCell(user_id).should('exist'); + }); + + it('should edit users full name, email and max buckets', () => { + users.edit(user_name, 'Another Identity', 'changed@othersite.com', '1969'); + }); + + it('should delete user', () => { + users.delete(user_name); + }); + }); + + describe('Invalid input tests', () => { + it('should put invalid input into user creation form and check fields are marked invalid', () => { + users.invalidCreate(); + }); + + it('should put invalid input into user edit form and check fields are marked invalid', () => { + users.invalidEdit(); + }); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/users.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/users.po.ts new file mode 100644 index 000000000..a4266f989 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/cypress/integration/rgw/users.po.ts @@ -0,0 +1,139 @@ +import { PageHelper } from '../page-helper.po'; + +const pages = { + index: { url: '#/rgw/user', id: 'cd-rgw-user-list' }, + create: { url: '#/rgw/user/create', id: 'cd-rgw-user-form' } +}; + +export class UsersPageHelper extends PageHelper { + pages = pages; + + @PageHelper.restrictTo(pages.create.url) + create(tenant: string, user_id: string, fullname: string, email: string, maxbuckets: string) { + // Enter in user_id + cy.get('#user_id').type(user_id); + // Show Tenanat + cy.get('#show_tenant').click({ force: true }); + // Enter in tenant + cy.get('#tenant').type(tenant); + // Enter in full name + cy.get('#display_name').click().type(fullname); + + // Enter in email + cy.get('#email').click().type(email); + + // Enter max buckets + this.selectOption('max_buckets_mode', 'Custom'); + cy.get('#max_buckets').should('exist').should('have.value', '1000'); + cy.get('#max_buckets').click().clear().type(maxbuckets); + + // Click the create button and wait for user to be made + cy.contains('button', 'Create User').click(); + this.getFirstTableCell(tenant + '$' + user_id).should('exist'); + } + + @PageHelper.restrictTo(pages.index.url) + edit(name: string, new_fullname: string, new_email: string, new_maxbuckets: string) { + this.navigateEdit(name); + + // Change the full name field + cy.get('#display_name').click().clear().type(new_fullname); + + // Change the email field + cy.get('#email').click().clear().type(new_email); + + // Change the max buckets field + this.selectOption('max_buckets_mode', 'Custom'); + cy.get('#max_buckets').click().clear().type(new_maxbuckets); + + cy.contains('button', 'Edit User').click(); + + // Click the user and check its details table for updated content + this.getExpandCollapseElement(name).click(); + cy.get('.active.tab-pane') + .should('contain.text', new_fullname) + .and('contain.text', new_email) + .and('contain.text', new_maxbuckets); + } + + invalidCreate() { + const tenant = '000invalid_tenant'; + const uname = '000invalid_create_user'; + // creating this user in order to check that you can't give two users the same name + this.navigateTo('create'); + this.create(tenant, uname, 'xxx', 'xxx@xxx', '1'); + + this.navigateTo('create'); + + // Username + cy.get('#user_id') + // No username had been entered. Field should be invalid + .should('have.class', 'ng-invalid') + // Try to give user already taken name. Should make field invalid. + .type(uname); + cy.get('#show_tenant').click({ force: true }); + cy.get('#tenant').type(tenant).should('have.class', 'ng-invalid'); + cy.contains('#tenant + .invalid-feedback', 'The chosen user ID exists in this tenant.'); + + // check that username field is marked invalid if username has been cleared off + cy.get('#user_id').clear().blur().should('have.class', 'ng-invalid'); + cy.contains('#user_id + .invalid-feedback', 'This field is required.'); + + // Full name + cy.get('#display_name') + // No display name has been given so field should be invalid + .should('have.class', 'ng-invalid') + // display name field should also be marked invalid if given input then emptied + .type('a') + .clear() + .blur() + .should('have.class', 'ng-invalid'); + cy.contains('#display_name + .invalid-feedback', 'This field is required.'); + + // put invalid email to make field invalid + cy.get('#email').type('a').blur().should('have.class', 'ng-invalid'); + cy.contains('#email + .invalid-feedback', 'This is not a valid email address.'); + + // put negative max buckets to make field invalid + this.expectSelectOption('max_buckets_mode', 'Custom'); + cy.get('#max_buckets').clear().type('-5').blur().should('have.class', 'ng-invalid'); + cy.contains('#max_buckets + .invalid-feedback', 'The entered value must be >= 1.'); + + this.navigateTo(); + this.delete(tenant + '$' + uname); + } + + invalidEdit() { + const tenant = '000invalid_tenant'; + const uname = '000invalid_edit_user'; + // creating this user to edit for the test + this.navigateTo('create'); + this.create(tenant, uname, 'xxx', 'xxx@xxx', '50'); + const name = tenant + '$' + uname; + this.navigateEdit(name); + + // put invalid email to make field invalid + cy.get('#email') + .clear() + .type('a') + .blur() + .should('not.have.class', 'ng-pending') + .should('have.class', 'ng-invalid'); + cy.contains('#email + .invalid-feedback', 'This is not a valid email address.'); + + // empty the display name field making it invalid + cy.get('#display_name').clear().blur().should('have.class', 'ng-invalid'); + cy.contains('#display_name + .invalid-feedback', 'This field is required.'); + + // put negative max buckets to make field invalid + this.selectOption('max_buckets_mode', 'Disabled'); + cy.get('#max_buckets').should('not.exist'); + this.selectOption('max_buckets_mode', 'Custom'); + cy.get('#max_buckets').should('exist').should('have.value', '50'); + cy.get('#max_buckets').clear().type('-5').blur().should('have.class', 'ng-invalid'); + cy.contains('#max_buckets + .invalid-feedback', 'The entered value must be >= 1.'); + + this.navigateTo(); + this.delete(tenant + '$' + uname); + } +} -- cgit v1.2.3