[Security Solution][Endpoint] Respond console FTR tests for entry point from Alert List page (#140670)

* additinoal Detections FTR page objects
* Add test case for responder from Alerts list page - alert details
* Deleted test from Permission checking due to un-stability
This commit is contained in:
Paul Tavares 2022-09-14 15:15:02 -04:00 committed by GitHub
parent 96250aeccc
commit afc6fa1f12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 23 deletions

View file

@ -76,20 +76,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
expect(endpointSummary['Policy status']).not.be('—');
expect(endpointSummary['Agent status']).not.to.be('—');
});
// FIXME: this area (detections) is unstable and due to time, skipping it.
// The page does not always (its intermittent) display with the created roles. Sometimes you get a
// "not enought priviliges" and others the data shows up.
it.skip('should display endpoint data on Alert Details', async () => {
await PageObjects.detections.navigateToAlerts();
await PageObjects.detections.openFirstAlertDetailsForHostName(
indexedData.hosts[0].host.name
);
const hostAgentStatus = await testSubjects.getVisibleText('rowHostStatus');
expect(hostAgentStatus).to.eql('Healthy');
});
});
}
});

View file

@ -18,6 +18,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
'endpointPageUtils',
'responder',
'timeline',
'detections',
]);
const testSubjects = getService('testSubjects');
const endpointTestResources = getService('endpointTestResources');
@ -38,7 +39,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
// Close responder
await pageObjects.responder.closeResponder();
};
const getEndpointAlertsQueryForAgentId = (
agentId: string
): object & { $stringify: () => string } => {
@ -87,6 +87,10 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});
endpointAgentId = indexedData.hosts[0].agent.id;
// start/stop the endpoint rule. This should cause the rule to run immediately
// and create the Alerts and avoid us having to wait for the interval (of 5 minutes)
await detectionsTestService.stopStartEndpointRule();
});
after(async () => {
@ -136,10 +140,6 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
timeline.data.persistTimeline.timeline.version
);
// start/stop the endpoint rule. This should cause the rule to run immediately
// and avoid us having to wait for the interval (of 5 minutes)
await detectionsTestService.stopStartEndpointRule();
await detectionsTestService.waitForAlerts(
getEndpointAlertsQueryForAgentId(endpointAgentId),
// The Alerts rules seems to run every 5 minutes, so we wait here a max
@ -181,5 +181,27 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
await pageObjects.timeline.closeTimeline();
});
});
describe('from alerts', () => {
before(async () => {
await detectionsTestService.waitForAlerts(
getEndpointAlertsQueryForAgentId(endpointAgentId),
// The Alerts rules seems to run every 5 minutes, so we wait here a max
// of 6 minutes to ensure it runs and completes and alerts are available.
60_000 * 6
);
});
it('should show Responder from alert details under alerts list page', async () => {
const hostname = indexedData.hosts[0].host.name;
await pageObjects.detections.navigateToAlerts(
`query=(language:kuery,query:'host.hostname: "${hostname}" ')`
);
await pageObjects.detections.waitForListToHaveAlerts();
await pageObjects.detections.openFirstAlertDetailsForHostName(hostname);
await pageObjects.detections.openResponseConsoleFromAlertDetails();
await performResponderSanityChecks();
});
});
});
};

View file

@ -8,18 +8,33 @@
import { FtrService } from '../../../functional/ftr_provider_context';
import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper';
const ALERT_TABLE_ROW_CSS_SELECTOR = '[data-test-subj="events-viewer-panel"] .euiDataGridRow';
export class DetectionsPageObject extends FtrService {
private readonly find = this.ctx.getService('find');
private readonly common = this.ctx.getPageObject('common');
private readonly testSubjects = this.ctx.getService('testSubjects');
private readonly headerPageObjects = this.ctx.getPageObject('header');
private readonly retry = this.ctx.getService('retry');
private readonly defaultTimeoutMs = this.ctx.getService('config').get('timeouts.waitFor');
async navigateHome(): Promise<void> {
await this.navigateToDetectionsPage();
}
async navigateToAlerts(): Promise<void> {
await this.navigateToDetectionsPage('alerts');
/**
* Navigate to the Alerts list page.
* @param searchParams
*
* @example
*
* // filter list by alert only for a given host name
* navigateToAlerts(`query=(language:kuery,query:'host.hostname: "HOST-abc"')`)
*/
async navigateToAlerts(searchParams: string = ''): Promise<void> {
await this.common.navigateToUrlWithBrowserHistory('securitySolution', '/alerts', searchParams, {
ensureCurrentUrl: !Boolean(searchParams),
});
await this.headerPageObjects.waitUntilLoadingHasFinished();
}
@ -149,17 +164,23 @@ export class DetectionsPageObject extends FtrService {
await this.testSubjects.existOrFail('detectionsAlertsPage');
}
/**
* Opens the first alert on the Alerts List page for the given host name
* @param hostName
*/
async openFirstAlertDetailsForHostName(hostName: string): Promise<void> {
await this.ensureOnAlertsPage();
let foundAndHandled = false;
// Get all event rows
const allEvents = await this.testSubjects.findAll('event');
const allEvents = await this.testSubjects.findService.allByCssSelector(
ALERT_TABLE_ROW_CSS_SELECTOR
);
for (const eventRow of allEvents) {
const hostNameButton = await this.testSubjects.findDescendant(
'host-details-button',
'formatted-field-host.name',
eventRow
);
const eventRowHostName = (await hostNameButton.getVisibleText()).trim();
@ -178,6 +199,50 @@ export class DetectionsPageObject extends FtrService {
}
}
/**
* Opens the Response console from the alert Details. Alert details must be already opened/displayed
*/
async openResponseConsoleFromAlertDetails(): Promise<void> {
await this.testSubjects.existOrFail('eventDetails');
await this.testSubjects.click('take-action-dropdown-btn');
await this.testSubjects.clickWhenNotDisabled('endpointResponseActions-action-item');
await this.testSubjects.existOrFail('consolePageOverlay');
}
/**
* Clicks the refresh button on the Alerts page and waits for it to complete
*/
async clickRefresh(): Promise<void> {
await this.ensureOnAlertsPage();
this.testSubjects.click('querySubmitButton');
// wait for refresh to complete
await this.retry.waitFor(
'Alerts pages refresh button to be enabled',
async (): Promise<boolean> => {
const refreshButton = await this.testSubjects.find('querySubmitButton');
return (await refreshButton.isDisplayed()) && (await refreshButton.isEnabled());
}
);
}
async waitForListToHaveAlerts(timeoutMs?: number): Promise<void> {
await this.retry.waitForWithTimeout(
'waiting for alerts to show up on alerts page',
timeoutMs ?? this.defaultTimeoutMs,
async (): Promise<boolean> => {
await this.clickRefresh();
const allEventRows = await this.testSubjects.findService.allByCssSelector(
ALERT_TABLE_ROW_CSS_SELECTOR
);
return Boolean(allEventRows.length);
}
);
}
private async navigateToDetectionsPage(path: string = ''): Promise<void> {
const subUrl = `detections${path ? `/${path}` : ''}`;
await this.common.navigateToUrl('securitySolution', subUrl, {