Skip to content

Commit

Permalink
[Security Solution][Endpoint] Additional Endpoint Activity log tests (e…
Browse files Browse the repository at this point in the history
…lastic#109776)

* move activity log paging method close to call api method

refs 417d093

* add middleware additional activity log tests

* add a more specific server side test for activity log actions and responses

refs elastic/pull/101032

* remove obsolete server side audit log index mock method

refs elastic/pull/101032

Co-authored-by: Kibana Machine <[email protected]>
  • Loading branch information
ashokaditya and kibanamachine committed Aug 25, 2021
1 parent 25b575b commit b54d730
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
HostResultList,
HostIsolationResponse,
ISOLATION_ACTIONS,
ActivityLog,
} from '../../../../../common/endpoint/types';
import { AppAction } from '../../../../common/store/actions';
import { mockEndpointResultList } from './mock_endpoint_result_list';
Expand Down Expand Up @@ -244,6 +245,29 @@ describe('endpoint list middleware', () => {
});
};

const dispatchGetActivityLogPaging = ({ page = 1 }: { page: number }) => {
dispatch({
type: 'endpointDetailsActivityLogUpdatePaging',
payload: {
page,
pageSize: 50,
},
});
};

const dispatchGetActivityLogUpdateInvalidDateRange = ({
isInvalidDateRange = false,
}: {
isInvalidDateRange: boolean;
}) => {
dispatch({
type: 'endpointDetailsActivityLogUpdateIsInvalidDateRange',
payload: {
isInvalidDateRange,
},
});
};

it('should set ActivityLog state to loading', async () => {
dispatchUserChangedUrl();
dispatchGetActivityLogLoading();
Expand Down Expand Up @@ -284,6 +308,69 @@ describe('endpoint list middleware', () => {
});
expect(activityLogResponse.payload.type).toEqual('LoadedResourceState');
});

it('should set ActivityLog to Failed if API call fails', async () => {
dispatchUserChangedUrl();

const apiError = new Error('oh oh');
const failedDispatched = waitForAction('endpointDetailsActivityLogChanged', {
validate(action) {
return isFailedResourceState(action.payload);
},
});

mockedApis.responseProvider.activityLogResponse.mockImplementation(() => {
throw apiError;
});

const failedAction = (await failedDispatched).payload as FailedResourceState<ActivityLog>;
expect(failedAction.error).toBe(apiError);
});

it('should not fetch Activity Log with invalid date ranges', async () => {
dispatchUserChangedUrl();

const updateInvalidDateRangeDispatched = waitForAction(
'endpointDetailsActivityLogUpdateIsInvalidDateRange'
);
dispatchGetActivityLogUpdateInvalidDateRange({ isInvalidDateRange: true });
await updateInvalidDateRangeDispatched;

expect(mockedApis.responseProvider.activityLogResponse).not.toHaveBeenCalled();
});

it('should call get Activity Log API with valid date ranges', async () => {
dispatchUserChangedUrl();

const updatePagingDispatched = waitForAction('endpointDetailsActivityLogUpdatePaging');
dispatchGetActivityLogPaging({ page: 1 });

const updateInvalidDateRangeDispatched = waitForAction(
'endpointDetailsActivityLogUpdateIsInvalidDateRange'
);
dispatchGetActivityLogUpdateInvalidDateRange({ isInvalidDateRange: false });
await updateInvalidDateRangeDispatched;
await updatePagingDispatched;

expect(mockedApis.responseProvider.activityLogResponse).toHaveBeenCalled();
});

it('should call get Activity Log API with correct paging options', async () => {
dispatchUserChangedUrl();

const updatePagingDispatched = waitForAction('endpointDetailsActivityLogUpdatePaging');
dispatchGetActivityLogPaging({ page: 3 });

await updatePagingDispatched;

expect(mockedApis.responseProvider.activityLogResponse).toHaveBeenCalledWith({
path: expect.any(String),
query: {
page: 3,
page_size: 50,
},
});
});
});

describe('handle Endpoint Pending Actions state actions', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ export const endpointMiddlewareFactory: ImmutableMiddlewareFactory<EndpointState
await loadEndpointDetails({ store, coreStart, selectedEndpoint: action.payload.endpointId });
}

// get activity log API
if (
action.type === 'userChangedUrl' &&
hasSelectedEndpoint(getState()) === true &&
Expand Down Expand Up @@ -502,99 +503,6 @@ async function endpointDetailsListMiddleware({
}
}

async function endpointDetailsActivityLogPagingMiddleware({
store,
coreStart,
}: {
store: ImmutableMiddlewareAPI<EndpointState, AppAction>;
coreStart: CoreStart;
}) {
const { getState, dispatch } = store;
try {
const { disabled, page, pageSize, startDate, endDate } = getActivityLogDataPaging(getState());
// don't page when paging is disabled or when date ranges are invalid
if (disabled) {
return;
}
if (getIsInvalidDateRange({ startDate, endDate })) {
dispatch({
type: 'endpointDetailsActivityLogUpdateIsInvalidDateRange',
payload: {
isInvalidDateRange: true,
},
});
return;
}

dispatch({
type: 'endpointDetailsActivityLogUpdateIsInvalidDateRange',
payload: {
isInvalidDateRange: false,
},
});
dispatch({
type: 'endpointDetailsActivityLogChanged',
// ts error to be fixed when AsyncResourceState is refactored (#830)
// @ts-expect-error
payload: createLoadingResourceState<ActivityLog>(getActivityLogData(getState())),
});
const route = resolvePathVariables(ENDPOINT_ACTION_LOG_ROUTE, {
agent_id: selectedAgent(getState()),
});
const activityLog = await coreStart.http.get<ActivityLog>(route, {
query: {
page,
page_size: pageSize,
start_date: startDate,
end_date: endDate,
},
});

const lastLoadedLogData = getLastLoadedActivityLogData(getState());
if (lastLoadedLogData !== undefined) {
const updatedLogDataItems = ([
...new Set([...lastLoadedLogData.data, ...activityLog.data]),
] as ActivityLog['data']).sort((a, b) =>
new Date(b.item.data['@timestamp']) > new Date(a.item.data['@timestamp']) ? 1 : -1
);

const updatedLogData = {
page: activityLog.page,
pageSize: activityLog.pageSize,
startDate: activityLog.startDate,
endDate: activityLog.endDate,
data: activityLog.page === 1 ? activityLog.data : updatedLogDataItems,
};
dispatch({
type: 'endpointDetailsActivityLogChanged',
payload: createLoadedResourceState<ActivityLog>(updatedLogData),
});
if (!activityLog.data.length) {
dispatch({
type: 'endpointDetailsActivityLogUpdatePaging',
payload: {
disabled: true,
page: activityLog.page > 1 ? activityLog.page - 1 : 1,
pageSize: activityLog.pageSize,
startDate: activityLog.startDate,
endDate: activityLog.endDate,
},
});
}
} else {
dispatch({
type: 'endpointDetailsActivityLogChanged',
payload: createLoadedResourceState<ActivityLog>(activityLog),
});
}
} catch (error) {
dispatch({
type: 'endpointDetailsActivityLogChanged',
payload: createFailedResourceState<ActivityLog>(error.body ?? error),
});
}
}

async function loadEndpointDetails({
selectedEndpoint,
store,
Expand Down Expand Up @@ -720,7 +628,6 @@ async function endpointDetailsActivityLogChangedMiddleware({
coreStart: CoreStart;
}) {
const { getState, dispatch } = store;
// call the activity log api
dispatch({
type: 'endpointDetailsActivityLogChanged',
// ts error to be fixed when AsyncResourceState is refactored (#830)
Expand Down Expand Up @@ -748,6 +655,99 @@ async function endpointDetailsActivityLogChangedMiddleware({
}
}

async function endpointDetailsActivityLogPagingMiddleware({
store,
coreStart,
}: {
store: ImmutableMiddlewareAPI<EndpointState, AppAction>;
coreStart: CoreStart;
}) {
const { getState, dispatch } = store;
try {
const { disabled, page, pageSize, startDate, endDate } = getActivityLogDataPaging(getState());
// don't page when paging is disabled or when date ranges are invalid
if (disabled) {
return;
}
if (getIsInvalidDateRange({ startDate, endDate })) {
dispatch({
type: 'endpointDetailsActivityLogUpdateIsInvalidDateRange',
payload: {
isInvalidDateRange: true,
},
});
return;
}

dispatch({
type: 'endpointDetailsActivityLogUpdateIsInvalidDateRange',
payload: {
isInvalidDateRange: false,
},
});
dispatch({
type: 'endpointDetailsActivityLogChanged',
// ts error to be fixed when AsyncResourceState is refactored (#830)
// @ts-expect-error
payload: createLoadingResourceState<ActivityLog>(getActivityLogData(getState())),
});
const route = resolvePathVariables(ENDPOINT_ACTION_LOG_ROUTE, {
agent_id: selectedAgent(getState()),
});
const activityLog = await coreStart.http.get<ActivityLog>(route, {
query: {
page,
page_size: pageSize,
start_date: startDate,
end_date: endDate,
},
});

const lastLoadedLogData = getLastLoadedActivityLogData(getState());
if (lastLoadedLogData !== undefined) {
const updatedLogDataItems = ([
...new Set([...lastLoadedLogData.data, ...activityLog.data]),
] as ActivityLog['data']).sort((a, b) =>
new Date(b.item.data['@timestamp']) > new Date(a.item.data['@timestamp']) ? 1 : -1
);

const updatedLogData = {
page: activityLog.page,
pageSize: activityLog.pageSize,
startDate: activityLog.startDate,
endDate: activityLog.endDate,
data: activityLog.page === 1 ? activityLog.data : updatedLogDataItems,
};
dispatch({
type: 'endpointDetailsActivityLogChanged',
payload: createLoadedResourceState<ActivityLog>(updatedLogData),
});
if (!activityLog.data.length) {
dispatch({
type: 'endpointDetailsActivityLogUpdatePaging',
payload: {
disabled: true,
page: activityLog.page > 1 ? activityLog.page - 1 : 1,
pageSize: activityLog.pageSize,
startDate: activityLog.startDate,
endDate: activityLog.endDate,
},
});
}
} else {
dispatch({
type: 'endpointDetailsActivityLogChanged',
payload: createLoadedResourceState<ActivityLog>(activityLog),
});
}
} catch (error) {
dispatch({
type: 'endpointDetailsActivityLogChanged',
payload: createFailedResourceState<ActivityLog>(error.body ?? error),
});
}
}

export async function handleLoadMetadataTransformStats(http: HttpStart, store: EndpointPageStore) {
const { getState, dispatch } = store;

Expand Down
Loading

0 comments on commit b54d730

Please sign in to comment.