diff --git a/README.md b/README.md index 76de71f8b..63fd23bc3 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ Execute command in the Project Root folder (e.g. Data from exporters is displayed at those dashboards) @dbaas DB as a Service functionality tests @grafana-pr Executed in Github Actions for PRs in percona-platform/grafana repository - @ia Integrated Alerting functionality tests + @alerting-fb Integrated Alerting functionality tests @instances Remote Instances addition functionality and checking that data appears from exporters @inventory Inventory functionality, removing nodes, services, etc. diff --git a/docker-compose-clickhouse.yml b/docker-compose-clickhouse.yml index 7ed7a6cbe..f78a5d69d 100644 --- a/docker-compose-clickhouse.yml +++ b/docker-compose-clickhouse.yml @@ -31,7 +31,7 @@ services: condition: service_healthy environment: - PMM_AGENT_SETUP=1 - - PMM_AGENT_SERVER_ADDRESS=pmm-server-external-clickhouse + - PMM_AGENT_SERVER_ADDRESS=pmm-server-external-clickhouse:8443 - PMM_AGENT_SERVER_USERNAME=admin - PMM_AGENT_SERVER_PASSWORD=admin - PMM_AGENT_PORTS_MIN=41000 @@ -43,9 +43,9 @@ services: - PMM_AGENT_SETUP_NODE_TYPE=container restart: on-failure - mysql5.7: - container_name: mysql5.7 - image: mysql:5.7 + ps8: + container_name: ps8 + image: percona:8 command: --default-authentication-plugin=mysql_native_password restart: always environment: diff --git a/docker-compose-disconnect.yml b/docker-compose-disconnect.yml index 6c46666fe..df820fe39 100644 --- a/docker-compose-disconnect.yml +++ b/docker-compose-disconnect.yml @@ -55,9 +55,9 @@ services: - server-network - mysql-network - mysql5.7: - container_name: mysql-disconnect-5.7 - image: mysql:5.7 + ps8: + container_name: ps8 + image: percona:8.0 command: --default-authentication-plugin=mysql_native_password restart: always environment: diff --git a/package.json b/package.json index b18969f13..f3e1d2860 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "scripts": { "lint:tests": "eslint --ext .js --fix tests/", "e2e": "npx codeceptjs run-multiple parallel --debug --steps --reporter mocha-multi -c pr.codecept.js --grep '(?=.*)^(?!.*@not-ui-pipeline)^(?!.*@not-pr-pipeline)'", - "e2e:ia": "npx codeceptjs run -c pr.codecept.js --grep '@ia'", + "e2e:ia": "npx codeceptjs run -c pr.codecept.js --grep '@alerting-fb'", "e2e:stt": "npx codeceptjs run -c pr.codecept.js --grep '@stt'", "e2e:dbaas": "npx codeceptjs run -c pr.codecept.js --grep '@dbaas'", "e2e:grafana-pr": "npx codeceptjs run -c pr.codecept.js --grep '@grafana-pr'" diff --git a/tests/QAN/externalClickhouse_test.js b/tests/QAN/externalClickhouse_test.js index 787b6eed5..47b557858 100644 --- a/tests/QAN/externalClickhouse_test.js +++ b/tests/QAN/externalClickhouse_test.js @@ -5,12 +5,12 @@ Feature('External Clickhouse Tests'); // Address of PMM with external clickhouse created with docker compose. const pmmServerPort = '8081'; const basePmmUrl = `http://127.0.0.1:${pmmServerPort}/`; -const dockerVersion = process.env.DOCKER_VERSION || 'perconalab/pmm-server:dev-latest'; +const dockerVersion = process.env.DOCKER_VERSION || 'perconalab/pmm-server:3-dev-latest'; BeforeSuite(async ({ I }) => { await I.verifyCommand(`PMM_SERVER_IMAGE=${dockerVersion} docker-compose -f docker-compose-clickhouse.yml up -d`); await I.wait(30); - await I.verifyCommand('docker exec pmm-client-clickhouse pmm-admin add mysql --username=root --password=7B*53@lCdflR --query-source=perfschema mysql5.7 mysql5.7:3306'); + await I.verifyCommand('docker exec pmm-client-clickhouse pmm-admin add mysql --username=root --password=7B*53@lCdflR --query-source=perfschema ps8 ps8:3306'); await I.wait(60); }); diff --git a/tests/configuration/verifyPMMServerDisconnect_test.js b/tests/configuration/verifyPMMServerDisconnect_test.js index 5877c64b4..48dacbb64 100644 --- a/tests/configuration/verifyPMMServerDisconnect_test.js +++ b/tests/configuration/verifyPMMServerDisconnect_test.js @@ -4,15 +4,16 @@ Feature('Pmm Server stability'); const pmmServerPort = '8180'; const basePmmUrl = `http://127.0.0.1:${pmmServerPort}/`; let clientServerNetwork = 'pmm-ui-tests_server-network'; +const serverImage = process.env.DOCKER_VERSION || 'perconalab/pmm-server:3-dev-latest'; BeforeSuite(async ({ I }) => { - await I.verifyCommand(`PMM_SERVER_IMAGE=${process.env.DOCKER_VERSION} docker compose -f docker-compose-disconnect.yml up -d pmm-server-disconnect`); - await I.asyncWaitFor(async () => await I.verifyCommand(`echo $(curl -s -o /dev/null -w '%{http_code}' 127.0.0.1:${pmmServerPort}/ping)`) === '200', 100); + await I.verifyCommand(`PMM_SERVER_IMAGE=${serverImage} docker compose -f docker-compose-disconnect.yml up -d pmm-server-disconnect`); + await I.asyncWaitFor(async () => await I.verifyCommand(`echo $(curl -s -o /dev/null -w '%{http_code}' 127.0.0.1:${pmmServerPort}/ping)`) === '200', 60); await I.verifyCommand('docker compose -f docker-compose-disconnect.yml up -d pmm-client'); - await I.verifyCommand('docker compose -f docker-compose-disconnect.yml up -d mysql5.7'); + await I.verifyCommand('docker compose -f docker-compose-disconnect.yml up -d ps8'); clientServerNetwork = await I.verifyCommand('docker inspect pmm-client-disconnect -f \'{{range $k, $v := .NetworkSettings.Networks}}{{printf "%s\\n" $k}}{{end}}\' | grep -o \'.*server-network\''); - await I.asyncWaitFor(async () => await I.verifyCommand('echo $(docker container logs mysql-disconnect-5.7 2>&1 | grep "Server hostname (bind-address)")') !== '', 100); - await I.verifyCommand('docker exec pmm-client-disconnect pmm-admin add mysql --username=root --password=7B*53@lCdflR --host=mysql-disconnect-5.7 --port=3306 --query-source=perfschema mysql-disconnect-5.7'); + I.wait(20); + await I.verifyCommand('docker exec pmm-client-disconnect pmm-admin add mysql --username=root --password=7B*53@lCdflR --host=ps8 --port=3306 --query-source=perfschema ps8'); // wait for the data to be scraped from db I.wait(60); }); @@ -42,7 +43,7 @@ Scenario( await I.amOnPage(withCustomBaseUrl(`${dashboardPage.mySQLInstanceOverview.clearUrl}?orgId=1&from=now-3m&to=now-1m`)); await dashboardPage.waitForDashboardOpened(); await dashboardPage.expandEachDashboardRow(); - await dashboardPage.verifyThereAreNoGraphsWithoutData(1); + await dashboardPage.verifyThereAreNoGraphsWithoutData(2); I.dontSeeElement(dashboardPage.fields.metricPanelNa('Services panel')); }, ); @@ -62,7 +63,7 @@ Scenario( await I.amOnPage(withCustomBaseUrl(`${dashboardPage.mySQLInstanceOverview.clearUrl}?orgId=1&from=now-3m&to=now-1m`)); await dashboardPage.waitForDashboardOpened(); await dashboardPage.expandEachDashboardRow(); - await dashboardPage.verifyThereAreNoGraphsWithoutData(1); + await dashboardPage.verifyThereAreNoGraphsWithoutData(2); I.dontSeeElement(dashboardPage.fields.metricPanelNa('Services panel')); }, ); diff --git a/tests/configuration/verifyPMMSettingsPageFunctionality_test.js b/tests/configuration/verifyPMMSettingsPageFunctionality_test.js index 7669f03cd..ef38a4c18 100644 --- a/tests/configuration/verifyPMMSettingsPageFunctionality_test.js +++ b/tests/configuration/verifyPMMSettingsPageFunctionality_test.js @@ -74,7 +74,7 @@ Scenario.skip( ).retry(2); Scenario( - 'PMM-T532 PMM-T533 PMM-T536 - Verify user can disable/enable IA in Settings @ia @settings', + 'PMM-T532 PMM-T533 PMM-T536 - Verify user can disable/enable IA in Settings @alerting-fb @settings', async ({ I, pmmSettingsPage, settingsAPI, adminPage, }) => { diff --git a/tests/dashboards/verifyGCRemoteInstance_test.js b/tests/dashboards/verifyGCRemoteInstance_test.js index 8e720130c..95bedf4a9 100644 --- a/tests/dashboards/verifyGCRemoteInstance_test.js +++ b/tests/dashboards/verifyGCRemoteInstance_test.js @@ -88,7 +88,7 @@ Data(instances).Scenario( const instanceDetails = getInstance(instance); - I.wait(10); + I.wait(30); if (instanceType === 'mysql') { I.amOnPage(dashboardPage.mySQLInstanceOverview.url); } @@ -98,10 +98,10 @@ Data(instances).Scenario( } dashboardPage.waitForDashboardOpened(); - await adminPage.applyTimeRange('Last 12 hours'); + await adminPage.applyTimeRange('Last 5 minutes'); await dashboardPage.applyFilter('Service Name', instanceDetails.serviceName); await dashboardPage.expandEachDashboardRow(); - await dashboardPage.verifyThereAreNoGraphsWithoutData(1); + await dashboardPage.verifyThereAreNoGraphsWithoutData(6); }, ).retry(2); @@ -136,11 +136,8 @@ Data(instances).Scenario( const instanceDetails = getInstance(instance); - I.wait(10); - const response = await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: instanceDetails.serviceName }); - const result = JSON.stringify(response.data.data.result); - - assert.ok(response.data.data.result.length !== 0, `Metrics ${metric} from ${instanceDetails.serviceName} should be available but got empty ${result}`); + I.wait(30); + await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: instanceDetails.serviceName }); }, ); diff --git a/tests/ia/README.md b/tests/ia/README.md index 06bd56d2c..8ad984b27 100644 --- a/tests/ia/README.md +++ b/tests/ia/README.md @@ -29,10 +29,10 @@ Shut down webhook server command: `docker-compose -f docker-compose-webhook.yml ### Command to execute all Integrated Alerting tests: -`npx codeceptjs run -c pr.codecept.js --grep '@ia'` +`npx codeceptjs run -c pr.codecept.js --grep '@alerting-fb'` ### Execute Integrated Alerting tests in Jenkins * Job name - `pmm2-ui-tests` -* tag - `@ia` +* tag - `@alerting-fb` * run tagged day - `yes` * clients not needed diff --git a/tests/ia/alertRules_test.js b/tests/ia/alertRules_test.js index 2334a0cd4..73d10f2fd 100644 --- a/tests/ia/alertRules_test.js +++ b/tests/ia/alertRules_test.js @@ -21,14 +21,15 @@ Feature('Alerting: Alert rules'); Before(async ({ I }) => { await I.Authorize(); + await rulesAPI.removeAllAlertRules(); }); After(async () => { await rulesAPI.removeAllAlertRules(); }); -Scenario.skip( - 'PMM-T1384 Verify empty alert rules list @ia @grafana-pr', +Scenario( + 'PMM-T1384 Verify empty alert rules list @alerting-fb @grafana-pr', async ({ I, alertRulesPage }) => { alertRulesPage.openAlertRulesTab(); I.waitForText(alertRulesPage.messages.noRulesFound, 10, alertRulesPage.elements.noRules); @@ -40,8 +41,8 @@ Scenario.skip( }, ).retry(0); -Scenario.skip( - 'PMM-T1385 Verify alert rules elements @ia @grafana-pr', +Scenario( + 'PMM-T1385 Verify alert rules elements @alerting-fb @grafana-pr', async ({ I, alertRulesPage, rulesAPI }) => { const ruleName = 'testRule'; const ruleFolder = 'PostgreSQL'; @@ -71,25 +72,25 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T1392 Verify fields dynamically change value when template is changed @ia @grafana-pr', +Scenario( + 'PMM-T1392 Verify fields dynamically change value when template is changed @alerting-fb @grafana-pr', async ({ I, alertRulesPage }) => { // TODO: https://jira.percona.com/browse/PMM-10860 name doesn't change alertRulesPage.openAlertRulesTab(); I.click(alertRulesPage.buttons.newAlertRule); I.waitForElement(alertRulesPage.fields.templatesLoader); - alertRulesPage.searchAndSelectResult('template', 'PostgreSQL down'); + await alertRulesPage.searchAndSelectResult('template', 'PostgreSQL down'); I.waitForValue(alertRulesPage.fields.inputField('duration'), '60s'); I.seeTextEquals('Critical', alertRulesPage.fields.dropdownValue('severity')); - alertRulesPage.searchAndSelectResult('template', 'MySQL restarted'); + await alertRulesPage.searchAndSelectResult('template', 'MySQL restarted'); I.waitForValue(alertRulesPage.fields.inputField('threshold'), 300); I.waitForValue(alertRulesPage.fields.inputField('duration'), '60s'); I.seeTextEquals('Warning', alertRulesPage.fields.dropdownValue('severity')); }, ); -Scenario.skip( - 'PMM-T1420 Verify user can create Percona templated alert @ia @alerting-fb', +Scenario( + 'PMM-T1420 Verify user can create Percona templated alert @alerting-fb', async ({ I, alertRulesPage, rulesAPI }) => { const rule = page.rules[15]; const newRule = page.rules[0]; @@ -110,7 +111,7 @@ Scenario.skip( // TODO: unskip in scope of https://perconadev.atlassian.net/browse/PMM-12938 Scenario.skip( - 'PMM-T2282 Verfied Alerting is able to monitor for "PMM Agent Down" @ia @alerting-fb', + 'PMM-T2282 Verfied Alerting is able to monitor for "PMM Agent Down" @alerting-fb', async ({ I, alertRulesPage, rulesAPI }) => { const rule = page.rules[29]; const newRule = page.rules[30]; @@ -137,8 +138,8 @@ Scenario.skip( ); // TODO: check ovf failure -Scenario.skip( - 'PMM-T1430 Verify user can edit Percona templated alert @ia @not-ovf @alerting-fb', +Scenario( + 'PMM-T1430 Verify user can edit Percona templated alert @alerting-fb @not-ovf', async ({ I, alertRulesPage, rulesAPI, }) => { @@ -163,8 +164,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T1433 Verify user can delete Percona templated alert @ia @alerting-fb', +Scenario( + 'PMM-T1433 Verify user can delete Percona templated alert @alerting-fb', async ({ I, alertRulesPage, rulesAPI, iaCommon, }) => { @@ -190,7 +191,7 @@ Scenario.skip( // nightly candidate // FIXME: flaky test fix and unskip Scenario.skip( - 'PMM-T1434 Verify validation errors when creating new alert rule @ia @grafana-pr', + 'PMM-T1434 Verify validation errors when creating new alert rule @alerting-fb @grafana-pr', async ({ I, alertRulesPage, }) => { diff --git a/tests/ia/alerts_test.js b/tests/ia/alerts_test.js index 35d6d3d6a..3d53d33f7 100644 --- a/tests/ia/alerts_test.js +++ b/tests/ia/alerts_test.js @@ -33,16 +33,16 @@ BeforeSuite(async ({ I, rulesAPI }) => { await rulesAPI.createAlertRule({ ruleName }, ruleFolder); // Preparation steps for checking Alert via webhook server - await I.verifyCommand('docker-compose -f docker-compose-webhook.yml up -d'); + await I.verifyCommand('docker compose -f docker-compose-webhook.yml up -d'); }); AfterSuite(async ({ rulesAPI, I }) => { await rulesAPI.removeAllAlertRules(); - await I.verifyCommand('docker-compose -f docker-compose-webhook.yml stop'); + await I.verifyCommand('docker compose -f docker-compose-webhook.yml stop'); }); Scenario.skip( - 'PMM-T1482 Verify fired alert @ia', + 'PMM-T1482 Verify fired alert @alerting-fb', async ({ I, alertsPage, alertsAPI }) => { await alertsAPI.waitForAlerts(24, 1); await I.amOnPage(alertsPage.url); @@ -60,7 +60,7 @@ Scenario.skip( ); Scenario.skip( - 'PMM-T1494 PMM-T1495 Verify fired alert in Pager Duty and Webhook @ia', + 'PMM-T1494 PMM-T1495 Verify fired alert in Pager Duty and Webhook @alerting-fb', async ({ I, alertsAPI, rulesAPI }) => { const file = './testdata/ia/scripts/alert.txt'; const alertUID = await rulesAPI.getAlertUID(ruleName, ruleFolder); @@ -76,7 +76,7 @@ Scenario.skip( ); Scenario.skip( - 'PMM-T1496 PMM-T1497 Verify it is possible to silence and unsilence alert @ia', + 'PMM-T1496 PMM-T1497 Verify it is possible to silence and unsilence alert @alerting-fb', async ({ I, alertsPage, alertmanagerAPI, }) => { @@ -94,7 +94,7 @@ Scenario.skip( ); Scenario.skip( - 'PMM-T1498 Verify firing alerts dissappear when the condition is fixed @ia', + 'PMM-T1498 Verify firing alerts dissappear when the condition is fixed @alerting-fb', async ({ I, alertsPage, alertRulesPage, }) => { @@ -113,7 +113,7 @@ Scenario.skip( // FIXME: Skip until https://jira.percona.com/browse/PMM-11130 is fixed Scenario.skip( - 'PMM-T659 Verify alerts are deleted after deleting rules @ia', + 'PMM-T659 Verify alerts are deleted after deleting rules @alerting-fb', async ({ I, alertsPage, rulesAPI }) => { // Deleting rules await rulesAPI.removeAllAlertRules(); @@ -124,7 +124,7 @@ Scenario.skip( ); Scenario.skip( - 'PMM-T1499 Verify an alert with non-existing filter (label) does not show up in list @ia', + 'PMM-T1499 Verify an alert with non-existing filter (label) does not show up in list @alerting-fb', async ({ I, alertsPage, rulesAPI }) => { await rulesAPI.removeAllAlertRules(); const wrongFilterRule = { @@ -146,7 +146,7 @@ Scenario.skip( ); Scenario.skip( - 'PMM-T564 Verify fired alert severity colors @ia', + 'PMM-T564 Verify fired alert severity colors @alerting-fb', async ({ I, alertsPage, rulesAPI, alertsAPI, }) => { @@ -172,7 +172,7 @@ Scenario.skip( ); Scenario.skip( - 'PMM-T1467 Verify empty Fired alerts list @ia', + 'PMM-T1467 Verify empty Fired alerts list @alerting-fb', async ({ I, alertsPage, rulesAPI }) => { await rulesAPI.removeAllAlertRules(); I.amOnPage(alertsPage.url); diff --git a/tests/ia/common_test.js b/tests/ia/common_test.js index 76c12db9b..2d156f4cb 100644 --- a/tests/ia/common_test.js +++ b/tests/ia/common_test.js @@ -7,8 +7,8 @@ Before(async ({ I, rulesAPI }) => { await rulesAPI.removeAllAlertRules(); }); -Scenario.skip( - 'PMM-T643 Verify message about disabled IA @ia @alerting-fb', +Scenario( + 'PMM-T643 Verify message about disabled IA @alerting-fb', async ({ I, pmmSettingsPage, codeceptjsConfig, }) => { @@ -23,10 +23,10 @@ Scenario.skip( }, ); -Scenario.skip( +Scenario( 'PMM-T481 Verify IA tab bar, ' + 'PMM-T620 Verify after reloading the page user is on the same IA tab, ' - + 'PMM-T776 Verify that user is able to see valid HTML Title on alerts page @ia @alerting-fb', + + 'PMM-T776 Verify that user is able to see valid HTML Title on alerts page @alerting-fb', async ({ I, alertRulesPage, ruleTemplatesPage, contactPointsPage, nPoliciesPage, silencesPage, alertGroupsPage, aiAdminPage, }) => { @@ -44,18 +44,17 @@ Scenario.skip( }; verifyTitle('Fired alerts'); - await iaCommon.openAndVerifyTab( + iaCommon.openAndVerifyTab( iaCommon.tabNames.ruleTemplates, ruleTemplatesPage.buttons.openAddTemplateModal, ruleTemplatesPage.url, ); verifyTitle('Alert rule templates'); - await iaCommon.openAndVerifyTab(iaCommon.tabNames.alertRules, alertRulesPage.buttons.newAlertRule, alertRulesPage.url); + iaCommon.openAndVerifyTab(iaCommon.tabNames.alertRules, alertRulesPage.buttons.newAlertRule, alertRulesPage.url); verifyTitle('Alert rules'); - await iaCommon - .openAndVerifyTab(iaCommon.tabNames.contactPoints, contactPointsPage.buttons.newContactPoint, contactPointsPage.url); + iaCommon.openAndVerifyTab(iaCommon.tabNames.contactPoints, contactPointsPage.buttons.newContactPoint, contactPointsPage.url); verifyTitle('Contact points'); - await iaCommon.openAndVerifyTab(iaCommon.tabNames.notificationPolicies, nPoliciesPage.buttons.newPolicy, nPoliciesPage.url); + iaCommon.openAndVerifyTab(iaCommon.tabNames.notificationPolicies, nPoliciesPage.buttons.newPolicy, nPoliciesPage.url); verifyTitle('Notification policies'); // PMM-T620 @@ -64,8 +63,7 @@ Scenario.skip( await iaCommon.openAndVerifyTab(iaCommon.tabNames.silences, silencesPage.buttons.newSilence, silencesPage.url); verifyTitle('Silences'); - await iaCommon - .openAndVerifyTab(iaCommon.tabNames.alertGroups, alertGroupsPage.elements.groupByContainer, alertGroupsPage.url); + await iaCommon.openAndVerifyTab(iaCommon.tabNames.alertGroups, alertGroupsPage.elements.groupByContainer, alertGroupsPage.url); verifyTitle('Alert groups'); await iaCommon.openAndVerifyTab(iaCommon.tabNames.admin, aiAdminPage.elements.configTextarea, aiAdminPage.url); verifyTitle('Admin'); diff --git a/tests/ia/contactPoints_test.js b/tests/ia/contactPoints_test.js index d74bff8d7..ba6ed0572 100644 --- a/tests/ia/contactPoints_test.js +++ b/tests/ia/contactPoints_test.js @@ -12,60 +12,58 @@ Before(async ({ I }) => { await I.Authorize(); }); -// Data(contactPoints).Scenario( -// 'PMM-T1703 Verify Slack contact point can be created, ' -// + 'PMM-T1709 Verify Webhook contact point can be created @ia', -// async ({ I, current }) => { -// await contactPointsPage.openContactPointsTab(); -// await contactPointsPage.createCP(current.name, current.type); -// I.click(contactPointsPage.buttons.saveCP); -// I.verifyPopUpMessage(contactPointsPage.messages.cPCreatedSuccess); -// await contactPointsPage.verifyCPInTable(current.name); -// }, -// ); -// -// Data(contactPoints).Scenario( -// 'PMM-T1707 Verify Slack contact point can be edited @ia', -// async ({ I, current }) => { -// await contactPointsPage.openContactPointsTab(); -// await contactPointsPage.editCP(current.name); -// I.appendField(contactPointsPage.fields.cPName, editedCPName); -// I.click(contactPointsPage.buttons.saveCP); -// I.verifyPopUpMessage(contactPointsPage.messages.cPEditedSuccess); -// await contactPointsPage.verifyCPInTable(current.name + editedCPName); -// }, -// ); -// -// Scenario.skip( -// 'PMM-T1706 Verify default contact point cannot be deleted @ia', -// async ({ I }) => { -// await contactPointsPage.openContactPointsTab(); -// await contactPointsPage.deleteCP('default'); -// I.waitForVisible(contactPointsPage.elements.cannotdeleteCPDialogHeader, 10); -// I.see(contactPointsPage.messages.cPCannotDelete); -// I.click(contactPointsPage.buttons.closeModal); -// I.see('default', contactPointsPage.elements.cPTable); -// }, -// ); -// -// Data(contactPoints).Scenario( -// 'PMM-T1704 Verify Slack contact point can be deleted @ia', -// async ({ I, current }) => { -// const name = current.name + editedCPName; -// -// await contactPointsPage.openContactPointsTab(); -// await contactPointsPage.deleteCP(name); -// I.waitForVisible(contactPointsPage.elements.deleteCPDialogHeader, 10); -// I.see(contactPointsPage.messages.deleteCPConfirm(name)); -// I.click(contactPointsPage.buttons.confirmDeleteCP); -// I.verifyPopUpMessage(contactPointsPage.messages.cPDeletedSuccess); -// I.dontSee(name, contactPointsPage.elements.cPTable); -// }, -// ); +Data(contactPoints).Scenario( + 'PMM-T1703 Verify Slack contact point can be created, ' + + 'PMM-T1709 Verify Webhook contact point can be created @alerting-fb', + async ({ I, current }) => { + await contactPointsPage.openContactPointsTab(); + await contactPointsPage.createCP(current.name, current.type); + I.click(contactPointsPage.buttons.saveCP); + I.verifyPopUpMessage(contactPointsPage.messages.cPCreatedSuccess); + await contactPointsPage.verifyCPInTable(current.name); + }, +); + +Data(contactPoints).Scenario( + 'PMM-T1707 Verify Slack contact point can be edited @alerting-fb', + async ({ I, current }) => { + await contactPointsPage.openContactPointsTab(); + await contactPointsPage.editCP(current.name); + I.appendField(contactPointsPage.fields.cPName, editedCPName); + I.click(contactPointsPage.buttons.saveCP); + I.verifyPopUpMessage(contactPointsPage.messages.cPEditedSuccess); + await contactPointsPage.verifyCPInTable(current.name + editedCPName); + }, +); + +Scenario( + 'PMM-T1706 Verify default contact point cannot be deleted @alerting-fb', + async ({ I }) => { + await contactPointsPage.openContactPointsTab(); + await contactPointsPage.openMoreMenu('default'); + I.waitForVisible(contactPointsPage.buttons.deleteCP, 10); + I.seeAttributesOnElements(contactPointsPage.buttons.deleteCP, { disabled: 'true' }); + }, +); + +Data(contactPoints).Scenario( + 'PMM-T1704 Verify Slack contact point can be deleted @alerting-fb', + async ({ I, current }) => { + const name = current.name + editedCPName; + + await contactPointsPage.openContactPointsTab(); + await contactPointsPage.deleteCP(name); + I.waitForVisible(contactPointsPage.elements.deleteCPDialogHeader, 10); + I.see(contactPointsPage.messages.deleteCPConfirm(name)); + I.click(contactPointsPage.buttons.confirmDeleteCP); + I.verifyPopUpMessage(contactPointsPage.messages.cPDeletedSuccess); + I.dontSee(name, contactPointsPage.elements.cPTable); + }, +); -Scenario.skip( +Scenario( 'PMM-T1710 Verify saving a contact point when required info is missing, ' - + 'PMM-T1711 Verify contact point test @ia', + + 'PMM-T1711 Verify contact point test @alerting-fb', async ({ I, iaCommon }) => { await contactPointsPage.openContactPointsTab(); I.waitForVisible(contactPointsPage.buttons.newContactPoint, 10); diff --git a/tests/ia/pages/alertRulesPage.js b/tests/ia/pages/alertRulesPage.js index 4d44d6d56..bdb9395ca 100644 --- a/tests/ia/pages/alertRulesPage.js +++ b/tests/ia/pages/alertRulesPage.js @@ -29,29 +29,34 @@ module.exports = { }, buttons: { newAlertRule: '//a[contains(.,\'New alert rule\')]', - saveAndExit: locate('button').withText('Save and exit'), + saveAndExit: locate('button').withText('Save rule and exit'), editAlertRule: '//a[contains(@href, \'edit?returnTo=%2Falerting%2Flist\')]', editRuleOnView: '//span[text()="Edit"]', deleteAlertRule: locate('span').withText('Delete').inside('button'), - groupCollapseButton: (folderText) => `//button[@data-testid='group-collapse-toggle'][following::h6[contains(., '${folderText}')]]`, + groupCollapseButton: (folderText) => `//button[@data-testid='data-testid group-collapse-toggle'][following::div/h3[contains(., '${folderText}')]]`, ruleCollapseButton: 'button[aria-label=\'Expand row\']', goToFolderButton: (folderID, folderText) => locate('[aria-label="go to folder"]').withAttr({ href: `/graph/dashboards/f/${folderID}/${folderText}` }), managePermissionsButton: (folderID, folderText) => locate('[aria-label="manage permissions"]').withAttr({ href: `/graph/dashboards/f/${folderID}/${folderText}/permissions` }), confirmModal: 'button[aria-label=\'Confirm Modal Danger Button\']', cancelModal: locate('button').withText('Cancel'), + newEvaluationGroup: I.useDataQA('data-testid alert-rule new-evaluation-group-button'), + evaluationGroupCreate: I.useDataQA('data-testid alert-rule new-evaluation-group-create-button'), }, fields: { // searchDropdown returns a locator of a search input for a given label - searchDropdown: (option) => `//div[@id='${option}']`, - folderLocator: I.useDataQA('data-testid Folder picker select container'), + searchDropdown: (option) => `$${option}-select-input`, + folderLocator: I.useDataQA('data-testid folder-picker-input'), dropdownValue: (option) => `//*[@id='${option}']/div/div[1]/div[1]`, // resultsLocator returns item locator in a search dropdown based on a text - resultsLocator: (name) => `//div[@aria-label="Select option"]//div//span[text()="${name}"]`, + resultsLocator: (name) => locate('[class*="grafana-select-menu"]') + // resultsLocator: (name) => locate('//div[@aria-label="Select options menu"]') + .find(I.useDataQA(`${name}-select-option`)), inputField: (input) => `input[name='${input}']`, editRuleThreshold: 'input[name=\'evaluateFor\']', editRuleEvaluate: 'input[name=\'evaluateEvery\']', editRuleSeverity: I.useDataQA('label-value-1'), templatesLoader: locate('//div[@id=\'template\']').find('div').withText('Choose'), + evaluationGroupName: I.useDataQA('data-testid alert-rule new-evaluation-group-name'), }, messages: { noRulesFound: 'You haven`t created any alert rules yet', @@ -89,6 +94,9 @@ module.exports = { I.see(severity, this.fields.searchDropdown('severity')); this.searchAndSelectResult('severity', editedRule.severity); this.selectFolder(editedRule.folder); + I.click(this.buttons.newEvaluationGroup); + I.fillField(this.fields.evaluationGroupName, '1m'); + I.click(this.buttons.evaluationGroupCreate); }, async editPerconaAlert(ruleObj) { diff --git a/tests/ia/pages/api/rulesAPI.js b/tests/ia/pages/api/rulesAPI.js index caa817dee..1780dabda 100644 --- a/tests/ia/pages/api/rulesAPI.js +++ b/tests/ia/pages/api/rulesAPI.js @@ -18,7 +18,7 @@ module.exports = { { label: 'service_name', regexp: 'pmm-server-postgresql', - type: 'MATCH', + type: 'FILTER_TYPE_MATCH', }, ], for: `${(duration || 60)}s`, @@ -28,7 +28,7 @@ module.exports = { params: params || [ { name: 'threshold', - type: 'FLOAT', + type: 'PARAM_TYPE_FLOAT', float: 1, }, ], @@ -82,26 +82,30 @@ module.exports = { ); }, - async removeAllAlertRules() { + async removeAlertRule(folderId, name) { const headers = { Authorization: `Basic ${await I.getAuth()}` }; - const resp = await I.sendGetRequest('graph/api/prometheus/grafana/api/v1/rules', headers); - const allRules = resp.data.data.groups; + const resp = await I.sendDeleteRequest(`graph/api/ruler/grafana/api/v1/rules/${folderId}/${name}?subtype=cortex`, headers); - if (allRules.length > 0) { - for (const i in allRules) { - await this.removeAlertRule(allRules[i].file); - } - } + // assert.ok( + // resp.status === 202, + // `Failed to remove alert rule. Response message is "${resp.data.message}"`, + // ); }, - async removeAlertRule(folder) { + async removeAllAlertRules() { const headers = { Authorization: `Basic ${await I.getAuth()}` }; - const resp = await I.sendDeleteRequest(`/graph/api/ruler/grafana/api/v1/rules/${folder}/default-alert-group?subtype=cortex`, headers); + const resp = await I.sendGetRequest('graph/api/ruler/grafana/api/v1/rules?subtype=cortex', headers); + const rules = Object.values(resp.data).flat(Infinity); + const allRules = rules.map((r) => { + const { name } = r; + const folderId = r.rules[0].grafana_alert.namespace_uid; - assert.ok( - resp.status === 202, - `Failed to remove alert rule. Response message is "${resp.data.message}"`, - ); + return { name, folderId }; + }); + + for (const rule of allRules) { + await this.removeAlertRule(rule.folderId, rule.name); + } }, async createAlertRules(numberOfRulesToCreate) { diff --git a/tests/ia/pages/api/templatesAPI.js b/tests/ia/pages/api/templatesAPI.js index 1ffca8301..78b25ee49 100644 --- a/tests/ia/pages/api/templatesAPI.js +++ b/tests/ia/pages/api/templatesAPI.js @@ -31,7 +31,7 @@ module.exports = { } for (const { source, name } of templates) { - if (source === 'USER_API') { await this.removeTemplate(name); } + if (source === 'TEMPLATE_SOURCE_USER_API') { await this.removeTemplate(name); } } }, diff --git a/tests/ia/pages/contactPointsPage.js b/tests/ia/pages/contactPointsPage.js index e5c5d9440..cb75018f7 100644 --- a/tests/ia/pages/contactPointsPage.js +++ b/tests/ia/pages/contactPointsPage.js @@ -29,7 +29,7 @@ module.exports = { }, }, elements: { - cPHeader: locate('h4').withText('Contact points'), + cPHeader: locate('h1').withText('Contact points'), cPTable: '$dynamic-table', deleteCPDialogHeader: locate('h2').withText('Delete contact point'), cannotdeleteCPDialogHeader: locate('h2').withText('Cannot delete contact point'), @@ -39,7 +39,8 @@ module.exports = { buttons: { newContactPoint: locate('button').find('span').withText('New contact point'), saveCP: locate('button').find('span').withText('Save contact point'), - deleteCP: (name) => `//*[@data-testid="row"][contains(., '${name}')]//button[@aria-label = 'Delete contact point']`, + deleteCP: locate('button').withText('Delete'), + moreMenu: (name) => locate(`//*[@data-testid="contact-point"][contains(., '${name}')]//button[@aria-label = 'More']`), confirmDeleteCP: locate('button').find('span').withText('Yes, delete'), editCP: (name) => `//*[@data-testid="row"][contains(., '${name}')]//a[@aria-label = 'Edit contact point']`, closeModal: locate('button').find('span').withText('Close'), @@ -80,8 +81,13 @@ module.exports = { await this.fillFields(name, type); }, + async openMoreMenu(name) { + I.waitForVisible(this.buttons.moreMenu(name), 10); + I.click(this.buttons.moreMenu(name)); + }, + async deleteCP(name) { - I.waitForVisible(this.buttons.deleteCP(name), 10); + await this.openMoreMenu(name); I.click(this.buttons.deleteCP(name)); }, diff --git a/tests/ia/pages/ruleTemplatesPage.js b/tests/ia/pages/ruleTemplatesPage.js index 2d3ce4e5c..b92466add 100644 --- a/tests/ia/pages/ruleTemplatesPage.js +++ b/tests/ia/pages/ruleTemplatesPage.js @@ -14,6 +14,8 @@ module.exports = { templateName: '//tr/td[1]', modalHeader: '$modal-header', modalWarning: '$alert-rule-name-warning', + templateRowByName: (name) => templateRow(name), + templateRowBySource: (source) => `//tr[descendant::div[contains(text(), "${source}")]]`, columnHeaderLocator: (columnHeaderText) => `//th[text()="${columnHeaderText}"]`, }, buttons: { diff --git a/tests/ia/pagination_test.js b/tests/ia/pagination_test.js index 51ca49fc7..5e1ede83f 100644 --- a/tests/ia/pagination_test.js +++ b/tests/ia/pagination_test.js @@ -12,8 +12,8 @@ After(async ({ templatesAPI }) => { await templatesAPI.clearAllTemplates(); }); -Scenario.skip( - 'PMM-T632 PMM-T697 PMM-T701 PMM-T1251 Verify Pagination navigation @ia @grafana-pr', +Scenario( + 'PMM-T632 PMM-T697 PMM-T701 PMM-T1251 Verify Pagination navigation @alerting-fb @grafana-pr', async ({ I, iaCommon, }) => { @@ -143,8 +143,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T662 PMM-T698 PMM-T702 PMM-T631 PMM-T1251 Pagination rows per page persistence @ia', +Scenario( + 'PMM-T662 PMM-T698 PMM-T702 PMM-T631 PMM-T1251 Pagination rows per page persistence @alerting-fb', async ({ I, iaCommon, }) => { @@ -218,8 +218,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T631 PMM-T633 PMM-T1251 Changing rows per page resets view to 1 page @ia', +Scenario( + 'PMM-T631 PMM-T633 PMM-T1251 Changing rows per page resets view to 1 page @alerting-fb', async ({ I, iaCommon, templatesAPI, }) => { diff --git a/tests/ia/ruleTemplates_test.js b/tests/ia/ruleTemplates_test.js index b9950f4bf..544ae872a 100644 --- a/tests/ia/ruleTemplates_test.js +++ b/tests/ia/ruleTemplates_test.js @@ -38,7 +38,7 @@ Before(async ({ templatesAPI }) => { // TODO: Unskip after we bring back built-in templates Scenario.skip( - 'PMM-T510 Verify built-in rule templates are non-editable @ia @grafana-pr', + 'PMM-T510 Verify built-in rule templates are non-editable @alerting-fb @grafana-pr', async ({ I, ruleTemplatesPage }) => { const editButton = ruleTemplatesPage.buttons .editButtonBySource(ruleTemplatesPage.templateSources.builtin); @@ -52,8 +52,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'Verify rule templates list elements @ia @grafana-pr', +Scenario( + 'Verify rule templates list elements @alerting-fb @grafana-pr', async ({ I, ruleTemplatesPage, templatesAPI }) => { const path = ruleTemplatesPage.ruleTemplate.paths.yaml; @@ -78,8 +78,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'Add rule template modal elements @ia @grafana-pr', +Scenario( + 'Add rule template modal elements @alerting-fb @grafana-pr', async ({ I, ruleTemplatesPage }) => { ruleTemplatesPage.openRuleTemplatesTab(); I.click(ruleTemplatesPage.buttons.openAddTemplateModal); @@ -92,70 +92,72 @@ Scenario.skip( ); // nightly candidate -// Data(units).Scenario( -// 'PMM-T500 PMM-T595 PMM-T596 Add rule templates with different units, empty range @ia', -// async ({ -// I, ruleTemplatesPage, templatesAPI, current, -// }) => { -// const [templateName, fileContent, id] = await ruleTemplatesPage.ruleTemplate -// .templateNameAndContent(ruleTemplatesPage.ruleTemplate.inputFilePath); -// const editButton = ruleTemplatesPage.buttons -// .editButtonByName(templateName); -// const deleteButton = ruleTemplatesPage.buttons -// .deleteButtonByName(templateName); -// -// const newFileContent = fileContent -// .replace('unit: \'%\'', `unit: '${current.unit}'`) -// .replace('range: [0, 100]', `range: ${current.range}`); -// -// ruleTemplatesPage.openRuleTemplatesTab(); -// -// I.click(ruleTemplatesPage.buttons.openAddTemplateModal); -// I.fillField(ruleTemplatesPage.fields.templateInput, newFileContent); -// I.click(ruleTemplatesPage.buttons.addTemplate); -// if (current.unit !== '*') { -// I.verifyPopUpMessage(ruleTemplatesPage.messages.successfullyAdded); -// -// // Check that Edit and Delete buttons are enabled -// I.waitForEnabled(editButton); -// I.waitForEnabled(deleteButton); -// -// await templatesAPI.removeTemplate(id); -// } else { -// I.verifyPopUpMessage(ruleTemplatesPage.messages.failedToParse); -// } -// }, -// ); - -// Data(templates).Scenario( -// 'PMM-T482 PMM-T499 PMM-T766 PMM-T758 PMM-T766 PMM-T767 PMM-T931 Upload rule templates @ia', -// async ({ I, ruleTemplatesPage, current }) => { -// const { path } = current; -// const validFile = !current.error; -// const [templateName] = await ruleTemplatesPage.ruleTemplate.templateNameAndContent(path); -// const expectedSourceLocator = ruleTemplatesPage -// .getSourceLocator(templateName, ruleTemplatesPage.templateSources.ui); -// const editButton = ruleTemplatesPage.buttons -// .editButtonBySource(ruleTemplatesPage.templateSources.ui); -// -// ruleTemplatesPage.openRuleTemplatesTab(); -// I.click(ruleTemplatesPage.buttons.openAddTemplateModal); -// I.attachFile(ruleTemplatesPage.fields.fileInput, path); -// await ruleTemplatesPage.verifyInputContent(path); -// I.click(ruleTemplatesPage.buttons.addTemplate); -// -// if (validFile) { -// I.verifyPopUpMessage(ruleTemplatesPage.messages.successfullyAdded); -// I.waitForVisible(expectedSourceLocator, 30); -// I.waitForEnabled(editButton); -// } else { -// I.verifyPopUpMessage(current.error); -// } -// }, -// ); +Data(units) + .Scenario( + 'PMM-T500 PMM-T595 PMM-T596 Add rule templates with different units, empty range @alerting-fb', + async ({ + I, ruleTemplatesPage, templatesAPI, current, + }) => { + const [templateName, fileContent, id] = await ruleTemplatesPage.ruleTemplate + .templateNameAndContent(ruleTemplatesPage.ruleTemplate.inputFilePath); + const editButton = ruleTemplatesPage.buttons + .editButtonByName(templateName); + const deleteButton = ruleTemplatesPage.buttons + .deleteButtonByName(templateName); -Scenario.skip( - '@PMM-T1785 Bulk rule templates upload @ia', + const newFileContent = fileContent + .replace('unit: \'%\'', `unit: '${current.unit}'`) + .replace('range: [0, 100]', `range: ${current.range}`); + + ruleTemplatesPage.openRuleTemplatesTab(); + + I.click(ruleTemplatesPage.buttons.openAddTemplateModal); + I.fillField(ruleTemplatesPage.fields.templateInput, newFileContent); + I.click(ruleTemplatesPage.buttons.addTemplate); + if (current.unit !== '*') { + I.verifyPopUpMessage(ruleTemplatesPage.messages.successfullyAdded); + + // Check that Edit and Delete buttons are enabled + I.waitForEnabled(editButton); + I.waitForEnabled(deleteButton); + + await templatesAPI.removeTemplate(id); + } else { + I.verifyPopUpMessage(ruleTemplatesPage.messages.failedToParse); + } + }, + ); + +Data(templates) + .Scenario( + 'PMM-T482 PMM-T499 PMM-T766 PMM-T758 PMM-T766 PMM-T767 PMM-T931 Upload rule templates @alerting-fb', + async ({ I, ruleTemplatesPage, current }) => { + const { path } = current; + const validFile = !current.error; + const [templateName] = await ruleTemplatesPage.ruleTemplate.templateNameAndContent(path); + const expectedSourceLocator = ruleTemplatesPage + .getSourceLocator(templateName, ruleTemplatesPage.templateSources.ui); + const editButton = ruleTemplatesPage.buttons + .editButtonBySource(ruleTemplatesPage.templateSources.ui); + + ruleTemplatesPage.openRuleTemplatesTab(); + I.click(ruleTemplatesPage.buttons.openAddTemplateModal); + I.attachFile(ruleTemplatesPage.fields.fileInput, path); + await ruleTemplatesPage.verifyInputContent(path); + I.click(ruleTemplatesPage.buttons.addTemplate); + + if (validFile) { + I.verifyPopUpMessage(ruleTemplatesPage.messages.successfullyAdded); + I.waitForVisible(expectedSourceLocator, 30); + I.waitForEnabled(editButton); + } else { + I.verifyPopUpMessage(current.error); + } + }, + ); + +Scenario( + '@PMM-T1785 Bulk rule templates upload @alerting-fb', async ({ I, ruleTemplatesPage }) => { const path = 'tests/ia/templates/multiple-templates.yml'; const templates = await ruleTemplatesPage.ruleTemplate.parseTemplates(path); @@ -174,13 +176,13 @@ Scenario.skip( .editButtonBySource(ruleTemplatesPage.templateSources.ui); I.waitForVisible(expectedSourceLocator, 30); - I.seeElementsEnabled(editButton); + I.waitForEnabled(editButton); } }, ); -Scenario.skip( - '@PMM-T1786 Edit bulk uploaded rule template @ia', +Scenario( + '@PMM-T1786 Edit bulk uploaded rule template @alerting-fb', async ({ I, ruleTemplatesPage, templatesAPI }) => { const path = 'tests/ia/templates/multiple-templates.yml'; const templates = await ruleTemplatesPage.ruleTemplate.parseTemplates(path); @@ -216,8 +218,8 @@ Scenario.skip( }, ); -Scenario.skip( - '@PMM-T1787 Delete bulk uploaded rule template @ia', +Scenario( + '@PMM-T1787 Delete bulk uploaded rule template @alerting-fb', async ({ I, ruleTemplatesPage, templatesAPI }) => { const path = 'tests/ia/templates/multiple-templates.yml'; const templates = await ruleTemplatesPage.ruleTemplate.parseTemplates(path); @@ -248,8 +250,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T501 Upload duplicate rule template @ia @grafana-pr', +Scenario( + 'PMM-T501 Upload duplicate rule template @alerting-fb @grafana-pr', async ({ I, ruleTemplatesPage, templatesAPI }) => { const path = ruleTemplatesPage.ruleTemplate.paths.yaml; const [, , id] = await ruleTemplatesPage.ruleTemplate.templateNameAndContent(path); @@ -266,8 +268,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T483 PMM-T699 Verify user can edit UI-created IA rule template @ia @grafana-pr @alerting-fb', +Scenario( + 'PMM-T483 PMM-T699 Verify user can edit UI-created IA rule template @grafana-pr @alerting-fb', async ({ I, ruleTemplatesPage, templatesAPI }) => { const path = ruleTemplatesPage.ruleTemplate.paths.yaml; const [templateName, fileContent, id] = await ruleTemplatesPage.ruleTemplate @@ -297,8 +299,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T562 Verify user can delete User-defined (UI) rule templates @ia @grafana-pr @alerting-fb', +Scenario( + 'PMM-T562 Verify user can delete User-defined (UI) rule templates @grafana-pr @alerting-fb', async ({ I, ruleTemplatesPage, templatesAPI }) => { const path = ruleTemplatesPage.ruleTemplate.paths.yaml; const [templateName] = await ruleTemplatesPage.ruleTemplate @@ -326,8 +328,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T884 Verify templates from Percona (SAAS) cannot be deleted or edited @ia', +Scenario( + 'PMM-T884 Verify templates from Percona (SAAS) cannot be deleted or edited @alerting-fb', async ({ I, ruleTemplatesPage }) => { const saasDeleteButton = ruleTemplatesPage.buttons .deleteButtonBySource(ruleTemplatesPage.templateSources.saas); @@ -341,13 +343,13 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T553 Verify rule template can be deleted if there is a rule based on it @ia', +Scenario( + 'PMM-T553 Verify rule template can be deleted if there is a rule based on it @alerting-fb', async ({ I, ruleTemplatesPage, templatesAPI, rulesAPI, }) => { const path = ruleTemplatesPage.ruleTemplate.paths.yaml; - const [templateName] = await ruleTemplatesPage.ruleTemplate + const [templateName, , id] = await ruleTemplatesPage.ruleTemplate .templateNameAndContent(path); const deleteButton = ruleTemplatesPage.buttons .deleteButtonByName(templateName); @@ -363,8 +365,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T825 PMM-T821 Verify User can add Alert rule template in the file system @not-ovf @ia', +Scenario( + 'PMM-T825 PMM-T821 Verify User can add Alert rule template in the file system @not-ovf @alerting-fb', async ({ I, ruleTemplatesPage }) => { const editButton = ruleTemplatesPage.buttons .editButtonBySource(ruleTemplatesPage.templateSources.file); @@ -385,8 +387,8 @@ Scenario.skip( }, ); -Scenario.skip( - 'PMM-T1126 - Verify there are no Templates from Percona if Telemetry is disabled @ia', +Scenario( + 'PMM-T1126 - Verify there are no Templates from Percona if Telemetry is disabled @alerting-fb', async ({ I, settingsAPI, ruleTemplatesPage }) => { const editButton = ruleTemplatesPage.buttons .editButtonBySource(ruleTemplatesPage.templateSources.saas); @@ -405,8 +407,8 @@ Scenario.skip( }, ); -Scenario.skip( - '@PMM-T1514 Verify that alert rule templates has only 1 exit button @ia', +Scenario( + '@PMM-T1514 Verify that alert rule templates has only 1 exit button @alerting-fb', async ({ I, ruleTemplatesPage, alertRulesPage }) => { ruleTemplatesPage.openRuleTemplatesTab(); ruleTemplatesPage.openAddDialog(await I.grabTextFrom(ruleTemplatesPage.elements.templateName)); diff --git a/tests/pages/adminPage.js b/tests/pages/adminPage.js index 0b14f0e03..e099278fc 100644 --- a/tests/pages/adminPage.js +++ b/tests/pages/adminPage.js @@ -1,12 +1,12 @@ const { I } = inject(); const assert = require('assert'); -const pathToPmmQaRepo = process.env.PATH_TO_PMM_QA || '/srv/pmm-qa'; +const pathToPmmQaRepo = process.env.PATH_TO_PMM_QA || '/srv/qa-integration'; module.exports = { url: 'graph/d/pmm-home/home-dashboard?orgId=1', pathToFramework: `${pathToPmmQaRepo}/pmm_qa/pmm-framework.py`, - pathToPMMTests: `${pathToPmmQaRepo}/pmm_qa/pmm-tests/`, + pathToPMMTests: `${pathToPmmQaRepo}/pmm_qa/`, sideMenu: { integratedAlerting: 'li > a[href="/graph/integrated-alerting"]', alertingBellIcon: locate('$navbar-section').at(2).find('li a[aria-label="Alerting"]'), diff --git a/tests/pages/api/grafanaAPI.js b/tests/pages/api/grafanaAPI.js index 40faa1b3f..0e3fa0161 100644 --- a/tests/pages/api/grafanaAPI.js +++ b/tests/pages/api/grafanaAPI.js @@ -206,10 +206,12 @@ module.exports = { const headers = { Authorization: `Basic ${await I.getAuth()}` }; const resp = await I.sendGetRequest(`graph/api/dashboards/uid/${uid}`, headers); + assert.ok( - resp.status === 200, - `Failed to find dashboard with id '${uid}' . Response message is ${resp.data.message}`, + resp.status === 200, + `Failed to find dashboard with id '${uid}' . Response message is ${resp.data.message}`, ); + return resp.data; }, @@ -342,45 +344,41 @@ module.exports = { ); }, - // Should be refactored - async getMetric(metricName, refineBy) { - const timeStamp = Date.now(); - const bodyFormData = new FormData(); - - const body = { - query: metricName, - start: Math.floor((timeStamp - 15000) / 1000), - end: Math.floor((timeStamp) / 1000), - step: 1, + async getDataSourceUidByName(name = 'Metrics') { + const headers = { + Authorization: `Basic ${await I.getAuth()}`, }; - if (refineBy) { - // ideally would need to refactor existing metric check to implement it this way - if (Array.isArray(refineBy)) { - let metricLabels = ''; - - for (let i = 0; i < refineBy.length; i++) { - const { type, value } = refineBy[i]; - const filter = `${type}="${value}", `; + const r = await I.sendGetRequest( + 'graph/api/datasources', + headers, + ); - metricLabels = metricLabels.concat(filter); - } + return (r.data.find((d) => d.name === name)).uid; + }, - body.query = `${metricName}{${metricLabels}}`; - } else { - body.query = `${metricName}{${refineBy.type}=~"(${refineBy.value})"}`; - } - } + // Should be refactored + async getMetric(metricName, refineBy) { + const uid = await this.getDataSourceUidByName(); + const body = { + queries: [ + { + datasource: { + uid, + }, + expr: refineBy ? `${metricName}{${refineBy.type}=\"${refineBy.value}\"}` : metricName, + }, + ], + from: 'now-15m', + }; - Object.keys(body).forEach((key) => bodyFormData.append(key, body[key])); const headers = { Authorization: `Basic ${await I.getAuth()}`, - ...bodyFormData.getHeaders(), }; return await I.sendPostRequest( - 'graph/api/datasources/proxy/1/api/v1/query_range', - bodyFormData, + 'graph/api/ds/query?ds_type=prometheus&requestId=explore_vmt', + body, headers, ); }, @@ -406,8 +404,8 @@ module.exports = { // Main condition check: metric body is not empty const response = await this.getMetric(metricName, queryBy); - if (response.data.data.result.length !== 0) { - return response; + if (response.data.results.A.frames[0].data.values !== 0) { + return response.data; } // Check the timeout after evaluating main condition @@ -459,10 +457,11 @@ module.exports = { async checkMetricExist(metricName, refineBy) { const response = await this.getMetric(metricName, refineBy); - const result = JSON.stringify(response.data.data.result); + + const result = JSON.stringify(response.data.results); I.assertTrue( - response.data.data.result.length !== 0, + response.data.results.A.frames[0].data.values.length !== 0, `Metrics '${metricName}' ${refineBy === null ? '' : `with filters as ${JSON.stringify(refineBy)} `}should be available but got empty ${result}`, ); diff --git a/tests/pages/api/inventoryAPI.js b/tests/pages/api/inventoryAPI.js index 8de1857ac..91f40a09f 100644 --- a/tests/pages/api/inventoryAPI.js +++ b/tests/pages/api/inventoryAPI.js @@ -13,8 +13,9 @@ module.exports = { // 60 sec ping for getting created service name for (let i = 0; i < 60; i++) { const resp = await this.apiGetServices(service.serviceType); + const services = Object.values(resp.data).flat(Infinity); - responseService = resp.data.services.find((service) => service.service_name === serviceName); + responseService = services.find((service) => service.service_name === serviceName); if (responseService !== undefined) break; I.wait(1); @@ -51,7 +52,6 @@ module.exports = { const resp = await this.apiGetServices(serviceType); const data = Object.values(resp.data).flat() - .filter((entry) => entry) .filter(({ service_name }) => service_name.includes(serviceName)); if (data.length === 0) await I.say(`Service "${serviceName}" of "${serviceType}" type is not found!`); diff --git a/tests/pages/api/settingsAPI.js b/tests/pages/api/settingsAPI.js index ee27e14c6..9e97c58c5 100644 --- a/tests/pages/api/settingsAPI.js +++ b/tests/pages/api/settingsAPI.js @@ -68,35 +68,15 @@ module.exports = { }, async apiEnableIA() { - const body = { - enable_alerting: true, - }; - const headers = { Authorization: `Basic ${await I.getAuth()}` }; - - const resp = await I.sendPostRequest(endpoint, body, headers); - - assert.ok( - resp.status === 200, - `Failed to enable Integrated alerting. ${resp.data.message}`, - ); + await this.changeSettings({ alerting: true }); }, async enableAzure() { - const body = { - enable_azurediscover: true, - }; - const headers = { Authorization: `Basic ${await I.getAuth()}` }; - - await I.sendPostRequest(endpoint, body, headers); + await this.changeSettings({ azureDiscover: true }); }, async disableAzure() { - const body = { - disable_azurediscover: true, - }; - const headers = { Authorization: `Basic ${await I.getAuth()}` }; - - await I.sendPostRequest(endpoint, body, headers); + await this.changeSettings({ azureDiscover: false }); }, async restoreSettingsDefaults() { @@ -113,7 +93,7 @@ module.exports = { }; const headers = { Authorization: `Basic ${await I.getAuth()}` }; - await I.sendPostRequest(endpoint, body, headers); + await I.sendPutRequest(endpoint, body, headers); }, async setCheckIntervals(intervals = defaultCheckIntervals) { @@ -122,7 +102,7 @@ module.exports = { }; const headers = { Authorization: `Basic ${await I.getAuth()}` }; - await I.sendPostRequest(endpoint, body, headers); + await I.sendPutRequest(endpoint, body, headers); }, async setEmailAlertingSettings(settings) { diff --git a/tests/pages/components/queryAnalytics/queryAnalyticsFilters.js b/tests/pages/components/queryAnalytics/queryAnalyticsFilters.js index 06291f45c..a618a91d8 100644 --- a/tests/pages/components/queryAnalytics/queryAnalyticsFilters.js +++ b/tests/pages/components/queryAnalytics/queryAnalyticsFilters.js @@ -56,7 +56,7 @@ class QueryAnalyticsFilters { selectFilter(filterName, timeout = 30000) { I.waitForVisible(this.fields.filterBy, 30); I.usePlaywrightTo('Search and select QAN Filter', async ({ page }) => { - const locator = await page.locator(this.fields.filterByExactName(filterName).value); + const locator = page.locator(this.fields.filterByExactName(filterName).value).first(); await page.locator(this.fields.filterBy.value).fill(filterName); diff --git a/tests/pages/remoteInstancesPage.js b/tests/pages/remoteInstancesPage.js index 8b65af76d..1d9e85aaf 100644 --- a/tests/pages/remoteInstancesPage.js +++ b/tests/pages/remoteInstancesPage.js @@ -164,6 +164,7 @@ module.exports = { pgStatMonitorRadioInput: locate('#radio-btn-3'), customAutoDiscoveryButton: locate('//div[input[@data-testid="autoDiscoveryOptions-radio-button"]]').find('label').withText('Custom'), customAutoDiscoveryfield: '$autoDiscoveryLimit-number-input', + dropdownOption: (text) => locate('div[class$="-select-option-body"]').find('span').withText(text), }, async getFileContent(filePath) { @@ -237,8 +238,16 @@ module.exports = { return this; }, + selectDropdownOption(dropdownLocator, text) { + I.click(dropdownLocator); + I.waitForVisible(this.fields.dropdownOption(text), 30); + I.click(this.fields.dropdownOption(text)); + I.dontSeeElement(this.fields.dropdownOption(text)); + }, + async addRemoteDetails(details, skipUserNamePassword = false) { I.waitForElement(this.fields.hostName, 30); + this.selectDropdownOption('$nodes-selectbox', 'pmm-server'); I.fillField(this.fields.hostName, details.host); if (!skipUserNamePassword) { I.fillField(this.fields.userName, details.username); @@ -265,15 +274,11 @@ module.exports = { I.dontSeeElement(this.fields.tlsCertificateInput); I.click(this.fields.useTLS); I.waitForElement(this.fields.tlscaInput, 30); - I.usePlaywrightTo('Fill TLS ca field', async ({ page }) => { - await page.fill(this.fields.tlscaInput.toXPath(), details.tlsCA); - }); - I.usePlaywrightTo('Fill TLS certificate field', async ({ page }) => { - await page.fill(this.fields.tlsCertificateInput.toXPath(), details.tlsCert); - }); - I.usePlaywrightTo('Fill TLS certificate key field', async ({ page }) => { - await page.fill(this.fields.tlsCertificateKeyInput.toXPath(), details.tlsKey); - }); + + await this.fillFileContent(this.fields.tlscaInput, details.tlsCAFile); + await this.fillFileContent(this.fields.tlsCertificateInput, details.tlsCertFile); + await this.fillFileContent(this.fields.tlsCertificateKeyInput, details.tlsKeyFile); + if (details.serviceType === 'postgres_ssl') I.click(this.fields.usePgStatStatements); if (details.serviceType === 'mysql_ssl') I.click(this.fields.skipTLSL); diff --git a/tests/verifyRemoteInstances_test.js b/tests/verifyRemoteInstances_test.js index ab0ce038e..5414a44b0 100644 --- a/tests/verifyRemoteInstances_test.js +++ b/tests/verifyRemoteInstances_test.js @@ -340,9 +340,6 @@ Scenario( pmmInventoryPage.verifyRemoteServiceIsDisplayed(remoteServiceName); await pmmInventoryPage.verifyAgentHasStatusRunning(remoteServiceName); // verify metric for client container node instance - const response = await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: remoteServiceName }); - const result = JSON.stringify(response.data.data.result); - - assert.ok(response.data.data.result.length !== 0, `Metrics ${metric} from ${remoteServiceName} should be available but got empty ${result}`); + await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: remoteServiceName }); }, ); diff --git a/tests/verifyTLSMongoDBRemoteInstance_test.js b/tests/verifyTLSMongoDBRemoteInstance_test.js index c52e53f4b..8c0b57c39 100644 --- a/tests/verifyTLSMongoDBRemoteInstance_test.js +++ b/tests/verifyTLSMongoDBRemoteInstance_test.js @@ -9,24 +9,19 @@ Feature('Monitoring SSL/TLS MongoDB instances'); const instances = new DataTable(['serviceName', 'version', 'container', 'serviceType', 'metric', 'maxQueryLength']); -instances.add(['mongodb_4.4_ssl_service', '4.4', 'mongodb_4.4', 'mongodb_ssl', 'mongodb_connections', '7']); +// instances.add(['mongodb_4.4_ssl_service', '4.4', 'mongodb_4.4', 'mongodb_ssl', 'mongodb_connections', '7']); // instances.add(['mongodb_4.2_ssl_service', '4.2', 'mongodb_4.2', 'mongodb_ssl', 'mongodb_connections']); -instances.add(['mongodb_5.0_ssl_service', '5.0', 'mongodb_5.0', 'mongodb_ssl', 'mongodb_connections', '7']); +// instances.add(['mongodb_5.0_ssl_service', '5.0', 'mongodb_5.0', 'mongodb_ssl', 'mongodb_connections', '7']); +instances.add(['mongodb_ssl_service', '6.0', 'psmdb-server', 'mongodb_ssl', 'mongodb_connections', '7']); -BeforeSuite(async ({ I, codeceptjsConfig }) => { - // await I.verifyCommand(`${pmmFrameworkLoader} --mo-version=4.2 --setup-mongodb-ssl --pmm2`); - await I.verifyCommand(`${pmmFrameworkLoader} --mo-version=4.4 --setup-mongodb-ssl --pmm2`); - await I.verifyCommand(`${pmmFrameworkLoader} --mo-version=5.0 --setup-mongodb-ssl --pmm2`); -}); - -AfterSuite(async ({ I }) => { - await I.verifyCommand('docker stop mongodb_4.4 || docker rm mongodb_4.4'); - // await I.verifyCommand('docker stop mongodb_4.2 || docker rm mongodb_4.2'); - await I.verifyCommand('docker stop mongodb_5.0 || docker rm mongodb_5.0'); -}); +let serviceName; -Before(async ({ I, settingsAPI }) => { +Before(async ({ I, inventoryAPI }) => { await I.Authorize(); + + const { service_name } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MONGODB, 'mongodb_ssl_service'); + + serviceName = service_name; }); Data(instances).Scenario( @@ -48,9 +43,9 @@ Data(instances).Scenario( host: container, cluster: 'mongodb_remote_cluster', environment: 'mongodb_remote_cluster', - tlsCAFile: `${pathToPMMFramework}tls-ssl-setup/mongodb/${version}/ca.crt`, - tlsCertificateFilePasswordInput: `${pathToPMMFramework}tls-ssl-setup/mongodb/${version}/client.key`, - tlsCertificateKeyFile: `${pathToPMMFramework}tls-ssl-setup/mongodb/${version}/client.pem`, + tlsCAFile: `${pathToPMMFramework}../pmm_psmdb_diffauth_setup/certs/ca-certs.pem`, + tlsCertificateFilePasswordInput: `${pathToPMMFramework}../pmm_psmdb_diffauth_setup/certs/certificate.crt`, + tlsCertificateKeyFile: `${pathToPMMFramework}../pmm_psmdb_diffauth_setup/certs/client.pem`, }; } @@ -64,7 +59,7 @@ Data(instances).Scenario( serviceType: SERVICE_TYPE.MONGODB, service: 'mongodb', }, - serviceName, + remoteServiceName, ); // Check Remote Instance also added and have running status @@ -90,16 +85,9 @@ Data(instances).Scenario( I.wait(10); // verify metric for client container node instance - response = await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: serviceName }); - result = JSON.stringify(response.data.data.result); - - assert.ok(response.data.data.result.length !== 0, `Metrics ${metric} from ${serviceName} should be available but got empty ${result}`); - + await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: serviceName }); // verify metric for remote instance - response = await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: remoteServiceName }); - result = JSON.stringify(response.data.data.result); - - assert.ok(response.data.data.result.length !== 0, `Metrics ${metric} from ${remoteServiceName} should be available but got empty ${result}`); + await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: remoteServiceName }); }, ).retry(1); @@ -149,7 +137,7 @@ Data(instances).Scenario( adminPage.performPageDown(5); await dashboardPage.expandEachDashboardRow(); adminPage.performPageUp(5); - await dashboardPage.verifyThereAreNoGraphsWithNA(); + await dashboardPage.verifyThereAreNoGraphsWithoutData(); await dashboardPage.verifyThereAreNoGraphsWithoutData(3); } }, @@ -193,14 +181,14 @@ Data(instances).Scenario( const agent_id = await I.verifyCommand(`docker exec ${container} pmm-admin list | grep mongodb_exporter | awk -F" " '{print $4}' | awk -F"/" '{print $3}'`); - await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm2/tmp/mongodb_exporter/agent_id/${agent_id}/ | grep caFile`); - await I.verifyCommand(`docker exec ${container} rm -r /usr/local/percona/pmm2/tmp/mongodb_exporter/`); - await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm2/tmp/mongodb_exporter/`, 'ls: cannot access \'/usr/local/percona/pmm2/tmp/mongodb_exporter\': No such file or directory', 'fail'); + await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm/tmp/mongodb_exporter/agent_id/${agent_id}/ | grep caFile`); + await I.verifyCommand(`docker exec ${container} rm -r /usr/local/percona/pmm/tmp/mongodb_exporter/`); + await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm/tmp/mongodb_exporter/`, 'ls: cannot access \'/usr/local/percona/pmm/tmp/mongodb_exporter\': No such file or directory', 'fail'); await I.verifyCommand(`docker exec ${container} pmm-admin list | grep mongodb_exporter | grep Running`); await I.verifyCommand(`docker exec ${container} pkill -f mongodb_exporter`); I.wait(10); await I.verifyCommand(`docker exec ${container} pmm-admin list | grep mongodb_exporter | grep Running`); - await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm2/tmp/mongodb_exporter/agent_id/${agent_id}/ | grep caFile`); + await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm/tmp/mongodb_exporter/agent_id/${agent_id}/ | grep caFile`); }, ).retry(1); @@ -223,9 +211,9 @@ Data(instances).Scenario( host: container, cluster: 'mongodb_remote_cluster', environment: 'mongodb_remote_cluster', - tlsCAFile: `${pathToPMMFramework}tls-ssl-setup/mongodb/${version}/ca.crt`, - tlsCertificateFilePasswordInput: `${pathToPMMFramework}tls-ssl-setup/mongodb/${version}/client.key`, - tlsCertificateKeyFile: `${pathToPMMFramework}tls-ssl-setup/mongodb/${version}/client.pem`, + tlsCAFile: `${pathToPMMFramework}../pmm_psmdb_diffauth_setup/certs/ca-certs.pem`, + tlsCertificateFilePasswordInput: `${pathToPMMFramework}../pmm_psmdb_diffauth_setup/certs/certificate.crt`, + tlsCertificateKeyFile: `${pathToPMMFramework}../pmm_psmdb_diffauth_setup/certs/client.pem`, }; } @@ -243,7 +231,7 @@ Data(instances).Scenario( serviceType: SERVICE_TYPE.MONGODB, service: 'mongodb', }, - serviceName, + remoteServiceName, ); const { service_id } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MONGODB, remoteServiceName); diff --git a/tests/verifyTLSMySQLRemoteInstance_test.js b/tests/verifyTLSMySQLRemoteInstance_test.js index 911668798..1bf3a07ce 100644 --- a/tests/verifyTLSMySQLRemoteInstance_test.js +++ b/tests/verifyTLSMySQLRemoteInstance_test.js @@ -17,23 +17,23 @@ maxQueryLengthTestData.add(['^']); maxQueryLengthTestData.add(['`']); maxQueryLengthTestData.add(['"']); -instances.add(['mysql_5.7_ssl_service', '5.7', 'mysql_5.7', 'mysql_ssl', 'mysql_global_status_max_used_connections']); -instances.add(['mysql_8.0_ssl_service', '8.0', 'mysql_8.0', 'mysql_ssl', 'mysql_global_status_max_used_connections']); - -maxQueryLengthInstances.add(['mysql_5.7_ssl_service', '5.7', 'mysql_5.7', 'mysql_ssl', 'mysql_global_status_max_used_connections', '10']); -maxQueryLengthInstances.add(['mysql_5.7_ssl_service', '5.7', 'mysql_5.7', 'mysql_ssl', 'mysql_global_status_max_used_connections', '-1']); -maxQueryLengthInstances.add(['mysql_5.7_ssl_service', '5.7', 'mysql_5.7', 'mysql_ssl', 'mysql_global_status_max_used_connections', '']); -maxQueryLengthInstances.add(['mysql_8.0_ssl_service', '8.0', 'mysql_8.0', 'mysql_ssl', 'mysql_global_status_max_used_connections', '10']); -maxQueryLengthInstances.add(['mysql_8.0_ssl_service', '8.0', 'mysql_8.0', 'mysql_ssl', 'mysql_global_status_max_used_connections', '-1']); -maxQueryLengthInstances.add(['mysql_8.0_ssl_service', '8.0', 'mysql_8.0', 'mysql_ssl', 'mysql_global_status_max_used_connections', '']); - -AfterSuite(async ({ I }) => { - await I.verifyCommand('docker stop mysql_5.7 || docker rm mysql_5.7'); - await I.verifyCommand('docker stop mysql_8.0 || docker rm mysql_8.0'); -}); +// instances.add(['mysql_5.7_ssl_service', '5.7', 'mysql_5.7', 'mysql_ssl', 'mysql_global_status_max_used_connections']); +instances.add(['mysql_8.0_ssl_service', '8.0', 'mysql_ssl_8.0', 'mysql_ssl', 'mysql_global_status_max_used_connections']); + +// maxQueryLengthInstances.add(['mysql_5.7_ssl_service', '5.7', 'mysql_5.7', 'mysql_ssl', 'mysql_global_status_max_used_connections', '10']); +// maxQueryLengthInstances.add(['mysql_5.7_ssl_service', '5.7', 'mysql_5.7', 'mysql_ssl', 'mysql_global_status_max_used_connections', '-1']); +// maxQueryLengthInstances.add(['mysql_5.7_ssl_service', '5.7', 'mysql_5.7', 'mysql_ssl', 'mysql_global_status_max_used_connections', '']); +maxQueryLengthInstances.add(['mysql_8.0_ssl_service', '8.0', 'mysql_ssl_8.0', 'mysql_ssl', 'mysql_global_status_max_used_connections', '10']); +maxQueryLengthInstances.add(['mysql_8.0_ssl_service', '8.0', 'mysql_ssl_8.0', 'mysql_ssl', 'mysql_global_status_max_used_connections', '-1']); +maxQueryLengthInstances.add(['mysql_8.0_ssl_service', '8.0', 'mysql_ssl_8.0', 'mysql_ssl', 'mysql_global_status_max_used_connections', '']); + +let serviceName; -Before(async ({ I, settingsAPI }) => { +Before(async ({ I, inventoryAPI }) => { await I.Authorize(); + const { service_name } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MYSQL, 'mysql_ssl_8.0_ssl_service'); + + serviceName = service_name; }); Data(instances).Scenario( @@ -42,12 +42,11 @@ Data(instances).Scenario( I, remoteInstancesPage, pmmInventoryPage, current, inventoryAPI, }) => { const { - serviceName, serviceType, version, container, + serviceType, version, container, } = current; let details; const remoteServiceName = `remote_${serviceName}_faker`; - await I.verifyCommand(`${pmmFrameworkLoader} --ps-version=${version} --setup-mysql-ssl --pmm2`); await I.say(await I.verifyCommand(`docker exec ${container} bash -c 'source ~/.bash_profile || true; pmm-admin list'`)); if (serviceType === 'mysql_ssl') { @@ -78,7 +77,7 @@ Data(instances).Scenario( serviceType: SERVICE_TYPE.MYSQL, service: 'mysql', }, - serviceName, + remoteServiceName, ); // Check Remote Instance also added and have running status @@ -93,25 +92,17 @@ Data(instances).Scenario( I, remoteInstancesPage, pmmInventoryPage, current, grafanaAPI, }) => { const { - serviceName, metric, + metric, } = current; - let response; let result; const remoteServiceName = `remote_${serviceName}_faker`; // Waiting for metrics to start hitting for remotely added services - I.wait(10); + I.wait(60); // verify metric for client container node instance - response = await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: serviceName }); - result = JSON.stringify(response.data.data.result); - - assert.ok(response.data.data.result.length !== 0, `Metrics ${metric} from ${serviceName} should be available but got empty ${result}`); - + await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: serviceName }); // verify metric for remote instance - response = await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: remoteServiceName }); - result = JSON.stringify(response.data.data.result); - - assert.ok(response.data.data.result.length !== 0, `Metrics ${metric} from ${remoteServiceName} should be available but got empty ${result}`); + await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: remoteServiceName }); }, ).retry(1); @@ -142,16 +133,11 @@ Data(instances).Scenario( }, ).retry(1); - -Data(instances).Scenario( +Scenario( 'Verify dashboard after MySQL SSL Instances are added @ssl @ssl-mysql @ssl-remote @not-ui-pipeline', async ({ - I, dashboardPage, adminPage, current, + I, dashboardPage, adminPage, }) => { - const { - serviceName, - } = current; - const serviceList = [serviceName, `remote_${serviceName}`]; for (const service of serviceList) { @@ -162,28 +148,21 @@ Data(instances).Scenario( adminPage.performPageDown(5); await dashboardPage.expandEachDashboardRow(); adminPage.performPageUp(5); - await dashboardPage.verifyThereAreNoGraphsWithNA(); await dashboardPage.verifyThereAreNoGraphsWithoutData(1); } }, ).retry(2); -Data(instances).Scenario( +Scenario( 'Verify QAN after MySQL SSL Instances is added @ssl @ssl-mysql @ssl-remote @not-ui-pipeline', async ({ - I, queryAnalyticsPage, current, adminPage, + I, queryAnalyticsPage, }) => { - const { - serviceName, - } = current; - const serviceList = [serviceName, `remote_${serviceName}_faker`]; for (const service of serviceList) { I.amOnPage(I.buildUrlWithParams(queryAnalyticsPage.url, { from: 'now-5m' })); queryAnalyticsPage.waitForLoaded(); - await adminPage.applyTimeRange('Last 12 hours'); - queryAnalyticsPage.waitForLoaded(); await queryAnalyticsPage.filters.selectFilter(service); queryAnalyticsPage.waitForLoaded(); const count = await queryAnalyticsPage.data.getCountOfItems(); @@ -206,14 +185,14 @@ Data(instances).Scenario( const agent_id = await I.verifyCommand(`docker exec ${container} pmm-admin list | grep mysqld_exporter | awk -F" " '{print $4}' | awk -F"/" '{print $3}'`); - await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm2/tmp/mysqld_exporter/agent_id/${agent_id}/ | grep tls`); - await I.verifyCommand(`docker exec ${container} rm -r /usr/local/percona/pmm2/tmp/mysqld_exporter/`); - await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm2/tmp/mysqld_exporter/`, 'ls: cannot access \'/usr/local/percona/pmm2/tmp/mysqld_exporter\': No such file or directory', 'fail'); + await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm/tmp/mysqld_exporter/${agent_id} | grep tls`); + await I.verifyCommand(`docker exec ${container} rm -r /usr/local/percona/pmm/tmp/mysqld_exporter/`); + await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm/tmp/mysqld_exporter/`, 'ls: cannot access \'/usr/local/percona/pmm/tmp/mysqld_exporter\': No such file or directory', 'fail'); await I.verifyCommand(`docker exec ${container} pmm-admin list | grep mysqld_exporter | grep Running`); await I.verifyCommand(`docker exec ${container} pkill -f mysqld_exporter`); I.wait(10); await I.verifyCommand(`docker exec ${container} pmm-admin list | grep mysqld_exporter | grep Running`); - await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm2/tmp/mysqld_exporter/agent_id/${agent_id}/ | grep tls`); + await I.verifyCommand(`docker exec ${container} ls -la /usr/local/percona/pmm/tmp/mysqld_exporter/${agent_id} | grep tls`); }, ).retry(1); @@ -241,7 +220,7 @@ Data(maxQueryLengthInstances).Scenario( I, remoteInstancesPage, pmmInventoryPage, inventoryAPI, current, queryAnalyticsPage, }) => { const { - serviceName, serviceType, version, container, maxQueryLength, + serviceType, version, container, maxQueryLength, } = current; let details; const remoteServiceName = `MaxQueryLength_remote_${serviceName}_${faker.random.alphaNumeric(3)}`; @@ -277,7 +256,7 @@ Data(maxQueryLengthInstances).Scenario( serviceType: SERVICE_TYPE.MYSQL, service: 'mysql', }, - serviceName, + remoteServiceName, ); const { service_id } = await inventoryAPI.apiGetNodeInfoByServiceName(SERVICE_TYPE.MYSQL, remoteServiceName); diff --git a/tests/verifyTLSPostgresRemoteInstance_test.js b/tests/verifyTLSPostgresRemoteInstance_test.js index 36d321bc5..96c9cb3fc 100644 --- a/tests/verifyTLSPostgresRemoteInstance_test.js +++ b/tests/verifyTLSPostgresRemoteInstance_test.js @@ -88,8 +88,6 @@ Data(instances).Scenario( const { serviceName, metric, container, } = current; - let response; - let result; const remoteServiceName = `remote_${serviceName}`; // Waiting for metrics to start hitting for remotely added services @@ -98,17 +96,9 @@ Data(instances).Scenario( // verify metric for client container node instance const localServiceName = await I.verifyCommand(`docker exec ${container} pmm-admin list | grep "PostgreSQL" | grep "ssl_service" | awk -F " " '{print $2}'`); - response = await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: localServiceName }); - - result = JSON.stringify(response.data.data.result); - - assert.ok(response.data.data.result.length !== 0, `Metrics ${metric} from ${serviceName} should be available but got empty ${result}`); - + await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: localServiceName }); // verify metric for remote instance - response = await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: remoteServiceName }); - result = JSON.stringify(response.data.data.result); - - assert.ok(response.data.data.result.length !== 0, `Metrics ${metric} from ${remoteServiceName} should be available but got empty ${result}`); + await grafanaAPI.checkMetricExist(metric, { type: 'service_name', value: remoteServiceName }); }, ).retry(1);