diff --git a/.github/workflows/release-e2e-workflow-template.yml b/.github/workflows/release-e2e-workflow-template.yml index db83faab6..95c5fca93 100644 --- a/.github/workflows/release-e2e-workflow-template.yml +++ b/.github/workflows/release-e2e-workflow-template.yml @@ -121,6 +121,26 @@ jobs: timeout 300 bash -c 'while [[ "$(curl -u admin:${{ env.OPENSEARCH_INITIAL_ADMIN_PASSWORD }} -k http://localhost:5601/api/status | jq -r '.status.overall.state')" != "green" ]]; do sleep 5; done' curl http://localhost:5601/api/status -u admin:${{ env.OPENSEARCH_INITIAL_ADMIN_PASSWORD }} --insecure fi + - name: Enable WLM mode (cluster setting) + run: | + if [ "$SECURITY_ENABLED" = 'false' ]; then + OS="http://localhost:9200" + AUTH="" + TLS="" + else + OS="https://localhost:9200" + AUTH="-u admin:${OPENSEARCH_INITIAL_ADMIN_PASSWORD}" + TLS="--insecure" + fi + + echo -e "\nEnabling WLM mode on ${OS}:" + curl -sS $AUTH $TLS -X PUT "$OS/_cluster/settings" \ + -H 'Content-Type: application/json' \ + -d '{"persistent":{"wlm.workload_group.mode":"enabled"}}' | jq '.' + + echo -e "\nVerify WLM mode:" + curl -sS $AUTH $TLS "$OS/_cluster/settings?include_defaults=true&flat_settings=true" \ + | jq -r '.persistent["wlm.workload_group.mode"] // .transient["wlm.workload_group.mode"] // "not set"' - name: Get Cypress version id: cypress_version run: | diff --git a/cypress/integration/plugins/query-insights-dashboards/6_WLM_main.cy.js b/cypress/integration/plugins/query-insights-dashboards/6_WLM_main.cy.js new file mode 100644 index 000000000..7f2bb5fde --- /dev/null +++ b/cypress/integration/plugins/query-insights-dashboards/6_WLM_main.cy.js @@ -0,0 +1,80 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +describe('WLM Main Page', () => { + beforeEach(() => { + cy.visit('/app/workload-management#/workloadManagement'); + cy.get('.euiBasicTable .euiTableRow').should('have.length.greaterThan', 0); + }); + + it('should display the WLM page with the workload group table', () => { + cy.contains('Workload groups').should('be.visible'); + cy.get('.euiBasicTable').should('exist'); + cy.get('.euiTableRow').should('have.length.greaterThan', 0); + }); + + it('should filter workload groups with the search bar', () => { + cy.get('.euiFieldSearch').type('DEFAULT_QUERY_GROUP'); + cy.get('.euiTableRow').should('have.length.at.least', 1); + cy.get('.euiFieldSearch').clear(); + cy.get('.euiTableRow').should('have.length.greaterThan', 0); + }); + + it('should refresh stats on clicking the refresh button', () => { + return cy.get('.euiTableRow').then(() => { + cy.get('button').contains('Refresh').click(); + + cy.get('.euiTableRow', { timeout: 10000 }).should(($newRows) => { + expect($newRows.length).to.be.greaterThan(0); + }); + }); + }); + + it('should display the WLM main page with workload group table and summary stats', () => { + // Confirm table exists + cy.get('.euiBasicTable').should('be.visible'); + cy.get('.euiTableRow').should('have.length.greaterThan', 0); + + // Confirm stat cards exist + const titles = ['Total workload groups', 'Total groups exceeding limits']; + + titles.forEach((title) => { + cy.contains(title).should('be.visible'); + }); + }); + + it('should filter workload groups by name in search', () => { + cy.get('.euiFieldSearch').type('DEFAULT_WORKLOAD_GROUP'); + cy.get('.euiTableRow').should('contain.text', 'DEFAULT_WORKLOAD_GROUP'); + + cy.get('.euiFieldSearch').clear().type('nonexistent_group_12345'); + cy.get('.euiTableRow').should('contain.text', 'No items found'); + }); + + it('should route to workload group detail page when clicking a group name', () => { + cy.get('.euiTableRow') + .first() + .within(() => { + cy.get('a').first().click({ force: true }); + }); + + cy.contains('Workload group name', { timeout: 10000 }).should('exist'); + }); + + it('should route to the Create Workload Group page when clicking the Create button', () => { + // Click the "Create workload group" button + cy.contains('Create workload group').click(); + + // Confirm we are on the create page + cy.url().should('include', '/wlm-create'); + + // Validate that the form elements exist + cy.contains('Resiliency mode').should('be.visible'); + cy.get('[data-testid="indexInput"]').should('exist'); + cy.get('button').contains('+ Add another rule').should('exist'); + cy.get('input[data-testid="cpu-threshold-input"]').should('exist'); + cy.get('input[data-testid="memory-threshold-input"]').should('exist'); + }); +}); diff --git a/cypress/integration/plugins/query-insights-dashboards/7_WLM_details.cy.js b/cypress/integration/plugins/query-insights-dashboards/7_WLM_details.cy.js new file mode 100644 index 000000000..bf0370ecd --- /dev/null +++ b/cypress/integration/plugins/query-insights-dashboards/7_WLM_details.cy.js @@ -0,0 +1,104 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +describe('WLM Details Page', () => { + const groupName = `test_group_${Date.now()}`; + + before(() => { + Cypress.env('groupName', groupName); + + // Clean up existing non-default groups + cy.request({ + method: 'GET', + url: '/api/_wlm/workload_group', + headers: { 'osd-xsrf': 'true' }, + }).then((res) => { + const groups = + res.body && res.body.workload_groups ? res.body.workload_groups : []; + groups.forEach((g) => { + if (g.name !== 'DEFAULT_WORKLOAD_GROUP') { + cy.request({ + method: 'DELETE', + url: `/api/_wlm/workload_group/${g.name}`, + headers: { 'osd-xsrf': 'true' }, + failOnStatusCode: false, + }); + } + }); + }); + + cy.request({ + method: 'PUT', + url: '/api/_wlm/workload_group', + headers: { 'osd-xsrf': 'true' }, + body: { + name: groupName, + resiliency_mode: 'soft', + resource_limits: { + cpu: 0.01, + memory: 0.01, + }, + }, + }); + }); + + beforeEach(() => { + cy.visit(`/app/workload-management#/wlm-details?name=${groupName}`); + // Wait until rows render + cy.get('.euiBasicTable .euiTableRow').should('have.length.greaterThan', 0); + }); + + it('should display workload group summary panel', () => { + cy.contains('Workload group name').should('exist'); + cy.contains('Resiliency mode').should('exist'); + cy.contains('CPU usage limit').should('exist'); + cy.contains('Memory usage limit').should('exist'); + cy.contains(groupName).should('exist'); + }); + + it('should switch between tabs', () => { + // Switch to Settings tab + cy.get('[data-testid="wlm-tab-settings"]').click(); + cy.contains('Workload group settings').should('exist'); + + // Switch to Resources tab + cy.get('[data-testid="wlm-tab-resources"]').click(); + cy.contains('Node ID').should('exist'); + }); + + it('should display node resource usage table', () => { + cy.contains('Node ID').should('exist'); + cy.get('.euiTableRow').should('have.length.greaterThan', 0); + }); + + it('should show delete modal', () => { + cy.contains('Delete').click(); + cy.contains('Delete workload group').should('exist'); + }); + + it('should delete the workload group successfully', () => { + cy.contains('Delete').click(); // opens modal + cy.get('input[placeholder="delete"]').type('delete'); + cy.get('.euiModalFooter button').contains('Delete').click(); + + // Confirm redirected back to WLM main page + cy.url().should('include', '/workloadManagement'); + + // Confirm toast appears + cy.contains(`Deleted workload group "${groupName}"`).should('exist'); + }); +}); + +describe('WLM Details – DEFAULT_WORKLOAD_GROUP', () => { + it('should disable settings tab for DEFAULT_WORKLOAD_GROUP', () => { + cy.visit( + '/app/workload-management#/wlm-details?name=DEFAULT_WORKLOAD_GROUP' + ); + cy.get('[data-testid="wlm-tab-settings"]').click(); + cy.contains( + 'Settings are not available for the DEFAULT_WORKLOAD_GROUP' + ).should('exist'); + }); +}); diff --git a/cypress/integration/plugins/query-insights-dashboards/8_WLM_create.cy.js b/cypress/integration/plugins/query-insights-dashboards/8_WLM_create.cy.js new file mode 100644 index 000000000..ae97d6048 --- /dev/null +++ b/cypress/integration/plugins/query-insights-dashboards/8_WLM_create.cy.js @@ -0,0 +1,75 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +describe('WLM Create Page', () => { + beforeEach(() => { + cy.visit('/app/workload-management#/wlm-create'); + }); + + it('renders the full create form with required fields', () => { + cy.contains('h1', 'Create workload group').should('exist'); + cy.contains('h2', 'Overview').should('exist'); + + // Form labels and fields + [ + 'Name', + 'Description – Optional', + 'Resiliency mode', + 'Index wildcard', + 'Reject queries when CPU usage exceeds', + 'Reject queries when memory usage exceeds', + ].forEach((label) => { + cy.contains(label).should('exist'); + }); + + cy.contains('Soft').should('exist'); + cy.contains('Enforced').should('exist'); + cy.contains('+ Add another rule').should('exist'); + cy.get('button').contains('Create workload group').should('exist'); + }); + + it('shows validation errors for CPU and memory thresholds', () => { + cy.get('[data-testid="cpu-threshold-input"]').clear().type('150'); + cy.contains('Value must be between 0 and 100').should('exist'); + + cy.get('[data-testid="cpu-threshold-input"]').clear().type('0'); + cy.contains('Value must be between 0 and 100').should('exist'); + + cy.get('[data-testid="memory-threshold-input"]').clear().type('101'); + cy.contains('Value must be between 0 and 100').should('exist'); + + cy.get('[data-testid="memory-threshold-input"]').clear().type('0'); + cy.contains('Value must be between 0 and 100').should('exist'); + }); + + it('creates a workload group successfully with valid inputs', () => { + const groupName = `wlm_test_${Date.now()}`; + + cy.get('[data-testid="name-input"]').type(groupName); + cy.contains('Soft').click(); + cy.get('[data-testid="indexInput"]').type('test-index'); + cy.get('[data-testid="cpu-threshold-input"]').type('10'); + cy.get('[data-testid="memory-threshold-input"]').type('20'); + + cy.intercept('PUT', '/api/_wlm/workload_group').as('createRequest'); + cy.get('button').contains('Create workload group').click(); + + cy.url().should('include', '/workloadManagement'); + cy.contains(groupName).should('exist'); + }); + + it('adds and deletes a rule block', () => { + cy.contains('+ Add another rule').click(); + cy.get('[data-testid="indexInput"]').should('have.length', 2); + + cy.get('[aria-label="Delete rule"]').first().click(); + cy.get('[data-testid="indexInput"]').should('have.length', 1); + }); + + it('navigates back to main page on Cancel', () => { + cy.get('button').contains('Cancel').click(); + cy.url().should('include', '/workloadManagement'); + }); +}); diff --git a/site/js/dashboard.js b/site/js/dashboard.js index ae9b63abe..31bb20b73 100644 --- a/site/js/dashboard.js +++ b/site/js/dashboard.js @@ -183,6 +183,9 @@ const plugins = { '2_query_details.cy.js', '3_configurations.cy.js', '4_group_details.cy.js', + '6_WLM_main.cy.js', + '7_WLM_details.cy.js', + '8_WLM_create.cy.js', ], }, },