Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PMM-9637 new failed checks view #229

Merged
merged 14 commits into from
Mar 29, 2022
Merged
7 changes: 4 additions & 3 deletions tests/advisers/stt/allChecks_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ const { perconaServerDB } = inject();
const connection = perconaServerDB.defaultConnection;
const psServiceName = 'allChecks-ps-5.7.30';
let nodeId;
let serviceId;

Feature('Security Checks: All Checks');

BeforeSuite(async ({ addInstanceAPI }) => {
nodeId = await addInstanceAPI.addInstanceForSTT(connection, psServiceName);
[nodeId, serviceId] = await addInstanceAPI.addInstanceForSTT(connection, psServiceName);
});
AfterSuite(async ({ inventoryAPI }) => {
if (nodeId) await inventoryAPI.deleteNode(nodeId, true);
Expand Down Expand Up @@ -83,7 +84,7 @@ Scenario(
await securityChecksAPI.waitForFailedCheckExistance(detailsText, psServiceName);

// Verify failed check on UI
databaseChecksPage.verifyFailedCheckExists(detailsText);
databaseChecksPage.verifyFailedCheckExists(detailsText, serviceId);

// Disable MySQL Version check
I.amOnPage(allChecksPage.url);
Expand All @@ -101,7 +102,7 @@ Scenario(
await securityChecksAPI.waitForFailedCheckNonExistance(detailsText, psServiceName);

// Verify there is no MySQL Version failed check
databaseChecksPage.verifyFailedCheckNotExists(detailsText);
databaseChecksPage.verifyFailedCheckNotExists(detailsText, serviceId);
},
);

Expand Down
40 changes: 25 additions & 15 deletions tests/advisers/stt/checksExecution_test.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const assert = require('assert');

const {
settingsAPI, perconaServerDB, securityChecksAPI, databaseChecksPage,
} = inject();
Expand All @@ -7,6 +9,8 @@ const intervals = settingsAPI.defaultCheckIntervals;
const psServiceName = 'stt-mysql-5.7.30';
const failedCheckRowLocator = databaseChecksPage.elements
.failedCheckRowByServiceName(psServiceName);
let nodeId;
let serviceId;

const intervalsTests = new DataTable(['interval', 'intervalValue']);

Expand Down Expand Up @@ -41,13 +45,14 @@ BeforeSuite(async ({ perconaServerDB, addInstanceAPI }) => {
password: connection.password,
};

await addInstanceAPI.addInstanceForSTT(connection, psServiceName);
[nodeId, serviceId] = await addInstanceAPI.addInstanceForSTT(connection, psServiceName);

perconaServerDB.connectToPS(mysqlComposeConnection);
});

AfterSuite(async ({ perconaServerDB }) => {
AfterSuite(async ({ perconaServerDB, inventoryAPI }) => {
await perconaServerDB.disconnectFromPS();
if (nodeId) await inventoryAPI.deleteNode(nodeId, true);
});

Before(async ({
Expand Down Expand Up @@ -75,7 +80,7 @@ Scenario(

await securityChecksAPI.waitForFailedCheckNonExistance(emptyPasswordSummary, psServiceName);
// Verify there is no MySQL user empty password failed check
databaseChecksPage.verifyFailedCheckNotExists(emptyPasswordSummary);
databaseChecksPage.verifyFailedCheckNotExists(emptyPasswordSummary, serviceId);
},
);

Expand All @@ -100,26 +105,31 @@ Scenario(
);

Scenario(
'PMM-T617 Verify Show all toggle for failed checks @stt @not-ovf',
'PMM-T617 Verify user is able to silence failed check @stt @not-ovf',
async ({
I, databaseChecksPage,
}) => {
const failedCheckRowLocator = databaseChecksPage.elements
.failedCheckRowByServiceName(psServiceName);
.failedCheckRowBySummary(emptyPasswordSummary);

await prepareFailedCheck();
I.amOnPage(databaseChecksPage.url);
I.waitForVisible(failedCheckRowLocator, 30);
databaseChecksPage.openFailedChecksListForService(serviceId);

// Silence mysql Empty Password failed check and verify it's not displayed
I.waitForVisible(failedCheckRowLocator, 30);
I.click(failedCheckRowLocator.find('button').first());
I.dontSeeElement(failedCheckRowLocator.find('td').withText(emptyPasswordSummary));

// Toggle Show Silenced and verify mysql Empty Password failed check is present and has state "Silenced"
I.click(databaseChecksPage.buttons.toggleSilenced);
I.seeElement(failedCheckRowLocator.find('td').withText(emptyPasswordSummary));
I.seeElement(failedCheckRowLocator.find('td').withText('Silenced'));
const oldColor = await I.grabCssPropertyFrom(
locate(databaseChecksPage.elements.failedCheckRowBySummary(emptyPasswordSummary))
.find('td'), 'background-color',
);

I.click(failedCheckRowLocator.find('$silence-button'));
const newColor = await I.grabCssPropertyFrom(
locate(databaseChecksPage.elements.failedCheckRowBySummary(emptyPasswordSummary))
.find('td'), 'background-color',
);

assert.ok(oldColor !== newColor);
},
);

Expand All @@ -142,7 +152,7 @@ Data(intervalsTests).Scenario(
await securityChecksAPI.waitForFailedCheckNonExistance(emptyPasswordSummary, psServiceName);

// Verify there is no MySQL user empty password failed check
databaseChecksPage.verifyFailedCheckNotExists(emptyPasswordSummary);
databaseChecksPage.verifyFailedCheckNotExists(emptyPasswordSummary, serviceId);
},
);

Expand All @@ -158,6 +168,6 @@ Scenario.skip(
await securityChecksAPI.waitForFailedCheckNonExistance(emptyPasswordSummary, psServiceName);

// Verify there is no MySQL user empty password failed check
databaseChecksPage.verifyFailedCheckNotExists(emptyPasswordSummary);
databaseChecksPage.verifyFailedCheckNotExists(emptyPasswordSummary, serviceId);
},
);
45 changes: 17 additions & 28 deletions tests/advisers/stt/databaseChecks_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ const {
} = inject();
const config = codeceptjsConfig.config.helpers.Playwright;
const connection = perconaServerDB.defaultConnection;
let nodeID;
let nodeId;
let serviceId;

const urls = new DataTable(['url']);

Expand All @@ -20,11 +21,11 @@ const detailsText = process.env.OVF_TEST === 'yes'
Feature('Database Failed Checks');

BeforeSuite(async ({ addInstanceAPI }) => {
nodeID = await addInstanceAPI.addInstanceForSTT(connection, psServiceName);
[nodeId, serviceId] = await addInstanceAPI.addInstanceForSTT(connection, psServiceName);
});

AfterSuite(async ({ inventoryAPI }) => {
if (nodeID) await inventoryAPI.deleteNode(nodeID, true);
if (nodeId) await inventoryAPI.deleteNode(nodeId, true);
});

Before(async ({ I }) => {
Expand Down Expand Up @@ -84,7 +85,7 @@ xScenario(
);

Scenario(
'PMM-T233 PMM-T354 PMM-T368 open PMM Database Checks page from home dashboard and verify number of failed checks [critical] @stt',
'PMM-T233 PMM-T354 PMM-T368 open PMM Database Checks page from home dashboard [critical] @stt',
async ({
I, homePage, databaseChecksPage, settingsAPI, securityChecksAPI,
}) => {
Expand All @@ -111,39 +112,27 @@ Scenario(
I.seeTextEquals(homePage.failedChecksSinglestatsInfoMessage, homePage.fields.popUp);

I.doubleClick(homePage.fields.sttFailedChecksPanelSelector);
await databaseChecksPage.verifyDatabaseChecksPageOpened();

// Verify count of checks by Severity match number on the home page singlestat
I.seeNumberOfElements(locate('td').withText('Critical'), critical);
I.seeNumberOfElements(locate('td').withText('Major'), major);
I.seeNumberOfElements(locate('td').withText('Trivial'), trivial);
// await databaseChecksPage.verifyDatabaseChecksPageOpened();
I.waitForVisible(databaseChecksPage.elements.failedCheckRowByServiceName(psServiceName), 10);
},
);

Scenario(
'PMM-T236 Verify user is able to hover Failed Checks values and see tooltip [minor] @stt',
'PMM-T241 Verify user can see correct service name for failed checks [critical] @stt',
async ({
I, databaseChecksPage, settingsAPI, securityChecksAPI,
I, databaseChecksPage, settingsAPI, securityChecksAPI, inventoryAPI,
}) => {
const row = 1;

await settingsAPI.apiEnableSTT();
await securityChecksAPI.waitForFailedCheckExistance(detailsText, psServiceName);
I.amOnPage(databaseChecksPage.url);
await databaseChecksPage.verifyDatabaseChecksPageOpened();
databaseChecksPage.mouseOverInfoIcon(row);
await databaseChecksPage.compareTooltipValues(row);
},
);

Scenario(
'PMM-T241 Verify user can see correct service name for failed checks [critical] @stt',
async ({ databaseChecksPage, settingsAPI, securityChecksAPI }) => {
await settingsAPI.apiEnableSTT();
await databaseChecksPage.runDBChecks();
await securityChecksAPI.waitForFailedCheckExistance(detailsText, psServiceName);

// Verify failed check on UI
databaseChecksPage.verifyFailedCheckExists(detailsText);
await databaseChecksPage.verifyServiceNamesExistence(psServiceName);
databaseChecksPage.verifyFailedCheckExists(detailsText, serviceId);
I.see(psServiceName);
await inventoryAPI.verifyServiceExistsAndHasRunningStatus({
serviceType: 'MYSQL_SERVICE',
service: 'mysql',
},
psServiceName);
},
);
2 changes: 1 addition & 1 deletion tests/advisers/stt/pages/allChecksPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const checkRow = (checkName) => `//tr[td[text()="${checkName}"]]`;
const actionButton = (checkName) => locate(checkRow(checkName)).find('td').last().find('button');

module.exports = {
url: 'graph/pmm-database-checks/allChecks',
url: 'graph/pmm-database-checks/all-checks',
elements: {
checkNameCell: (checkName) => locate(checkRow(checkName)).find('td').at(1),
descriptionCellByName: (checkName) => locate(checkRow(checkName)).find('td').at(2),
Expand Down
22 changes: 13 additions & 9 deletions tests/advisers/stt/pages/databaseChecksPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const {
const assert = require('assert');
// xpath used here because locate('th').withText('') method does not work correctly
const locateChecksHeader = (header) => `//th[text()='${header}']`;
const failedCheckRow = (checkSummary) => `//tr[td[contains(., "${checkSummary}")]]`;

module.exports = {
// insert your locators and methods here
Expand All @@ -13,6 +14,7 @@ module.exports = {
oldUrl: 'graph/d/pmm-checks/pmm-database-checks',
elements: {
failedCheckRowByServiceName: (name) => locate('tr').withChild(locate('td').withText(name)),
failedCheckRowBySummary: (summary) => locate('tr').withChild(locate('td').withText(summary)),
},
messages: {
homePagePanelMessage: 'Security Threat Tool is disabled.\nCheck PMM Settings.',
Expand All @@ -31,7 +33,7 @@ module.exports = {
serviceNameSelector: 'tr > td[rowspan]:first-child',
totalFailedChecksTooltipSelector: '.popper > div > div > div:first-of-type',
failedChecksTooltipSelector: '.popper > div > div > div',
serviceNameHeaderSelector: locateChecksHeader('Service name'),
serviceNameHeaderSelector: locateChecksHeader('Service Name'),
detailsHeaderSelector: locateChecksHeader('Details'),
noOfFailedChecksHeaderSelector: locateChecksHeader('Failed Checks'),
disabledSTTMessageLinkSelector: locate('$db-check-panel-settings-link'),
Expand All @@ -55,13 +57,19 @@ module.exports = {
I.waitForVisible(this.buttons.startDBChecks, 30);
},

verifyFailedCheckNotExists(checkSummary) {
this.openDBChecksPage();
openFailedChecksListForService(serviceId) {
I.amOnPage(`${this.url}/service-checks/${serviceId.split('/')[2]}`);
I.waitForVisible('td', 30);
// I.waitForVisible(this.buttons.startDBChecks, 30);
},

verifyFailedCheckNotExists(checkSummary, serviceId) {
this.openFailedChecksListForService(serviceId);
I.dontSee(checkSummary);
},

verifyFailedCheckExists(checkSummary) {
this.openDBChecksPage();
verifyFailedCheckExists(checkSummary, serviceId) {
this.openFailedChecksListForService(serviceId);
I.see(checkSummary);
},
/*
Expand Down Expand Up @@ -141,10 +149,6 @@ module.exports = {
I.seeElement(this.fields.totalFailedChecksTooltipSelector);
},

/*
Method takes service names listed in Database Failed checks
and compares names with existing Service Names in PMM Inventory
*/
async verifyServiceNamesExistence(serviceName) {
I.see(serviceName);

Expand Down
2 changes: 1 addition & 1 deletion tests/ia/pages/alertsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ module.exports = {
},
buttons: {
// silenceActivate returns silence/activate button locator for a given alert name
silenceActivate: (alertName) => `${alertRow(alertName)}[1]/td//button[@data-testid="silence-alert-button"]`,
silenceActivate: (alertName) => `${alertRow(alertName)}[1]/td//button[@data-testid="silence-button"]`,
silenceAllAlerts: locate('span').withText('Silence All'),
unsilenceAllAlerts: locate('span').withText('Unsilence All'),
arrowIcon: (alertName) => locate(`${alertRow(alertName)}`).find('$show-details'),
Expand Down
15 changes: 10 additions & 5 deletions tests/pages/api/addInstanceAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -276,17 +276,22 @@ module.exports = {

async addInstanceForSTT(connection, instanceName = 'stt-mysql-5.7.30') {
let nodeId;
let serviceId;

if (process.env.OVF_TEST === 'yes') {
await inventoryAPI.deleteNodeByServiceName(remoteInstancesHelper.serviceTypes.mysql.serviceType, instanceName);
nodeId = (await this.apiAddInstance(remoteInstancesHelper.instanceTypes.rds, instanceName)).node.node_id;
const instance = await this.apiAddInstance(remoteInstancesHelper.instanceTypes.rds, instanceName);

nodeId = instance.node.node_id;
serviceId = instance.service.service_id;
} else {
await inventoryAPI.deleteNodeByServiceName(remoteInstancesHelper.serviceTypes.mysql.serviceType, instanceName);
nodeId = (await this.apiAddInstance(remoteInstancesHelper.instanceTypes.mysql, instanceName, connection))
.service
.node_id;
const instance = await this.apiAddInstance(remoteInstancesHelper.instanceTypes.mysql, instanceName, connection);

nodeId = instance.service.node_id;
serviceId = instance.service.service_id;
}

return nodeId;
return [nodeId, serviceId];
},
};