Skip to content

Commit

Permalink
Merge branch '7.x' into backport/7.x/pr-66512
Browse files Browse the repository at this point in the history
  • Loading branch information
elasticmachine committed May 19, 2020
2 parents 5d417cc + 5885791 commit fddb3df
Show file tree
Hide file tree
Showing 40 changed files with 998 additions and 225 deletions.
3 changes: 1 addition & 2 deletions test/functional/page_objects/home_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ export function HomePageProvider({ getService, getPageObjects }: FtrProviderCont

async removeSampleDataSet(id: string) {
// looks like overkill but we're hitting flaky cases where we click but it doesn't remove
await testSubjects.isDisplayed(`removeSampleDataSet${id}`);
await testSubjects.isEnabled(`removeSampleDataSet${id}`);
await testSubjects.waitForEnabled(`removeSampleDataSet${id}`);
await testSubjects.click(`removeSampleDataSet${id}`);
await this._waitForSampleDataLoadingAction(id);
}
Expand Down
59 changes: 27 additions & 32 deletions test/functional/services/common/test_subjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,10 @@ export function TestSubjectsProvider({ getService }: FtrProviderContext) {
}

public async append(selector: string, text: string): Promise<void> {
return await retry.try(async () => {
log.debug(`TestSubjects.append(${selector}, ${text})`);
const input = await this.find(selector);
await input.click();
await input.type(text);
});
log.debug(`TestSubjects.append(${selector}, ${text})`);
const input = await this.find(selector);
await input.click();
await input.type(text);
}

public async clickWhenNotDisabled(
Expand All @@ -119,12 +117,10 @@ export function TestSubjectsProvider({ getService }: FtrProviderContext) {
}

public async doubleClick(selector: string, timeout: number = FIND_TIME): Promise<void> {
return await retry.try(async () => {
log.debug(`TestSubjects.doubleClick(${selector})`);
const element = await this.find(selector, timeout);
await element.moveMouseTo();
await element.doubleClick();
});
log.debug(`TestSubjects.doubleClick(${selector})`);
const element = await this.find(selector, timeout);
await element.moveMouseTo();
await element.doubleClick();
}

async descendantExists(selector: string, parentElement: WebElementWrapper): Promise<boolean> {
Expand Down Expand Up @@ -206,27 +202,21 @@ export function TestSubjectsProvider({ getService }: FtrProviderContext) {
}

public async isEnabled(selector: string): Promise<boolean> {
return await retry.try(async () => {
log.debug(`TestSubjects.isEnabled(${selector})`);
const element = await this.find(selector);
return await element.isEnabled();
});
log.debug(`TestSubjects.isEnabled(${selector})`);
const element = await this.find(selector);
return await element.isEnabled();
}

public async isDisplayed(selector: string): Promise<boolean> {
return await retry.try(async () => {
log.debug(`TestSubjects.isDisplayed(${selector})`);
const element = await this.find(selector);
return await element.isDisplayed();
});
log.debug(`TestSubjects.isDisplayed(${selector})`);
const element = await this.find(selector);
return await element.isDisplayed();
}

public async isSelected(selector: string): Promise<boolean> {
return await retry.try(async () => {
log.debug(`TestSubjects.isSelected(${selector})`);
const element = await this.find(selector);
return await element.isSelected();
});
log.debug(`TestSubjects.isSelected(${selector})`);
const element = await this.find(selector);
return await element.isSelected();
}

public async isSelectedAll(selectorAll: string): Promise<boolean[]> {
Expand All @@ -237,11 +227,9 @@ export function TestSubjectsProvider({ getService }: FtrProviderContext) {
}

public async getVisibleText(selector: string): Promise<string> {
return await retry.try(async () => {
log.debug(`TestSubjects.getVisibleText(${selector})`);
const element = await this.find(selector);
return await element.getVisibleText();
});
log.debug(`TestSubjects.getVisibleText(${selector})`);
const element = await this.find(selector);
return await element.getVisibleText();
}

async getVisibleTextAll(selectorAll: string): Promise<string[]> {
Expand Down Expand Up @@ -294,6 +282,13 @@ export function TestSubjectsProvider({ getService }: FtrProviderContext) {
await find.waitForElementHidden(element, timeout);
}

public async waitForEnabled(selector: string, timeout: number = TRY_TIME): Promise<void> {
await retry.tryForTime(timeout, async () => {
const element = await this.find(selector);
return (await element.isDisplayed()) && (await element.isEnabled());
});
}

public getCssSelector(selector: string): string {
return testSubjSelector(selector);
}
Expand Down
4 changes: 0 additions & 4 deletions x-pack/plugins/endpoint/common/alert_constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ export class AlertConstants {
* The path for the Alert's Index Pattern API.
*/
static INDEX_PATTERN_ROUTE = `${AlertConstants.BASE_API_URL}/index_pattern`;
/**
* Alert's Index pattern
*/
static ALERT_INDEX_NAME = 'events-endpoint-1';
/**
* A paramter passed to Alert's Index Pattern.
*/
Expand Down
21 changes: 20 additions & 1 deletion x-pack/plugins/endpoint/common/models/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { LegacyEndpointEvent, ResolverEvent } from '../types';

export function isLegacyEvent(event: ResolverEvent): event is LegacyEndpointEvent {
Expand Down Expand Up @@ -46,3 +45,23 @@ export function parentEntityId(event: ResolverEvent): string | undefined {
}
return event.process.parent?.entity_id;
}

export function eventType(event: ResolverEvent): string {
// Returning "Process" as a catch-all here because it seems pretty general
let eventCategoryToReturn: string = 'Process';
if (isLegacyEvent(event)) {
const legacyFullType = event.endgame.event_type_full;
if (legacyFullType) {
return legacyFullType;
}
} else {
const eventCategories = event.event.category;
const eventCategory =
typeof eventCategories === 'string' ? eventCategories : eventCategories[0] || '';

if (eventCategory) {
eventCategoryToReturn = eventCategory;
}
}
return eventCategoryToReturn;
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ interface AppRequestedResolverData {
readonly type: 'appRequestedResolverData';
}

/**
* The action dispatched when the app requests related event data for one or more
* subjects (whose ids should be included as an array @ `payload`)
*/
interface UserRequestedRelatedEventData {
readonly type: 'userRequestedRelatedEventData';
readonly payload: ResolverEvent;
}

/**
* When the user switches the "active descendant" of the Resolver.
* The "active descendant" (from the point of view of the parent element)
Expand Down Expand Up @@ -77,11 +86,36 @@ interface UserSelectedResolverNode {
};
}

/**
* This action should dispatch to indicate that the user chose to
* focus on examining the related events of a particular ResolverEvent.
* Optionally, this can be bound by a category of related events (e.g. 'file' or 'dns')
*/
interface UserSelectedRelatedEventCategory {
readonly type: 'userSelectedRelatedEventCategory';
readonly payload: {
subject: ResolverEvent;
category?: string;
};
}

/**
* This action should dispatch to indicate that the user chose to focus
* on examining alerts related to a particular ResolverEvent
*/
interface UserSelectedRelatedAlerts {
readonly type: 'userSelectedRelatedAlerts';
readonly payload: ResolverEvent;
}

export type ResolverAction =
| CameraAction
| DataAction
| UserBroughtProcessIntoView
| UserChangedSelectedEvent
| AppRequestedResolverData
| UserFocusedOnResolverNode
| UserSelectedResolverNode;
| UserSelectedResolverNode
| UserRequestedRelatedEventData
| UserSelectedRelatedEventCategory
| UserSelectedRelatedAlerts;
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/

import { ResolverEvent } from '../../../../../common/types';
import { RelatedEventDataEntry } from '../../types';

interface ServerReturnedResolverData {
readonly type: 'serverReturnedResolverData';
Expand All @@ -15,4 +16,24 @@ interface ServerFailedToReturnResolverData {
readonly type: 'serverFailedToReturnResolverData';
}

export type DataAction = ServerReturnedResolverData | ServerFailedToReturnResolverData;
/**
* Will occur when a request for related event data is fulfilled by the API.
*/
interface ServerReturnedRelatedEventData {
readonly type: 'serverReturnedRelatedEventData';
readonly payload: Map<ResolverEvent, RelatedEventDataEntry>;
}

/**
* Will occur when a request for related event data is unsuccessful.
*/
interface ServerFailedToReturnRelatedEventData {
readonly type: 'serverFailedToReturnRelatedEventData';
readonly payload: ResolverEvent;
}

export type DataAction =
| ServerReturnedResolverData
| ServerFailedToReturnResolverData
| ServerReturnedRelatedEventData
| ServerFailedToReturnRelatedEventData;
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ function initialState(): DataState {
results: [],
isLoading: false,
hasError: false,
resultsEnrichedWithRelatedEventInfo: new Map(),
};
}

Expand All @@ -23,6 +24,26 @@ export const dataReducer: Reducer<DataState, ResolverAction> = (state = initialS
isLoading: false,
hasError: false,
};
} else if (action.type === 'userRequestedRelatedEventData') {
const resolverEvent = action.payload;
const currentStatsMap = new Map(state.resultsEnrichedWithRelatedEventInfo);
/**
* Set the waiting indicator for this event to indicate that related event results are pending.
* It will be replaced by the actual results from the API when they are returned.
*/
currentStatsMap.set(resolverEvent, 'waitingForRelatedEventData');
return { ...state, resultsEnrichedWithRelatedEventInfo: currentStatsMap };
} else if (action.type === 'serverFailedToReturnRelatedEventData') {
const currentStatsMap = new Map(state.resultsEnrichedWithRelatedEventInfo);
const resolverEvent = action.payload;
currentStatsMap.set(resolverEvent, 'error');
return { ...state, resultsEnrichedWithRelatedEventInfo: currentStatsMap };
} else if (action.type === 'serverReturnedRelatedEventData') {
const relatedDataEntries = new Map([
...state.resultsEnrichedWithRelatedEventInfo,
...action.payload,
]);
return { ...state, resultsEnrichedWithRelatedEventInfo: relatedDataEntries };
} else if (action.type === 'appRequestedResolverData') {
return {
...state,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

import { Store, createStore } from 'redux';
import { DataAction } from './action';
import { dataReducer } from './reducer';
import {
DataState,
RelatedEventDataEntry,
RelatedEventDataEntryWithStats,
RelatedEventData,
} from '../../types';
import { ResolverEvent } from '../../../../../common/types';
import { relatedEventStats, relatedEvents } from './selectors';

describe('resolver data selectors', () => {
const store: Store<DataState, DataAction> = createStore(dataReducer, undefined);
describe('when related event data is reduced into state with no results', () => {
let relatedEventInfoBeforeAction: RelatedEventData;
beforeEach(() => {
relatedEventInfoBeforeAction = new Map(relatedEvents(store.getState()) || []);
const payload: Map<ResolverEvent, RelatedEventDataEntry> = new Map();
const action: DataAction = { type: 'serverReturnedRelatedEventData', payload };
store.dispatch(action);
});
it('should have the same related info as before the action', () => {
const relatedInfoAfterAction = relatedEvents(store.getState());
expect(relatedInfoAfterAction).toEqual(relatedEventInfoBeforeAction);
});
});
describe('when related event data is reduced into state with 2 dns results', () => {
let mockBaseEvent: ResolverEvent;
beforeEach(() => {
mockBaseEvent = {} as ResolverEvent;
function dnsRelatedEventEntry() {
const fakeEvent = {} as ResolverEvent;
return { relatedEvent: fakeEvent, relatedEventType: 'dns' };
}
const payload: Map<ResolverEvent, RelatedEventDataEntry> = new Map([
[
mockBaseEvent,
{
relatedEvents: [dnsRelatedEventEntry(), dnsRelatedEventEntry()],
},
],
]);
const action: DataAction = { type: 'serverReturnedRelatedEventData', payload };
store.dispatch(action);
});
it('should compile stats reflecting a count of 2 for dns', () => {
const actualStats = relatedEventStats(store.getState());
const statsForFakeEvent = actualStats.get(mockBaseEvent)! as RelatedEventDataEntryWithStats;
expect(statsForFakeEvent.stats).toEqual({ dns: 2 });
});
});
});
Loading

0 comments on commit fddb3df

Please sign in to comment.