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

[Security Solution][Endpoint] Suppress some of the jest console.error noise created by endpoint list middelware #102535

Merged
merged 5 commits into from
Jun 17, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ import { SUB_PLUGINS_REDUCER, mockGlobalState, createSecuritySolutionStorageMock
import { ExperimentalFeatures } from '../../../../common/experimental_features';
import { PLUGIN_ID } from '../../../../../fleet/common';
import { APP_ID } from '../../../../common/constants';
import { KibanaContextProvider } from '../../lib/kibana';
import { KibanaContextProvider, KibanaServices } from '../../lib/kibana';
import { MANAGEMENT_APP_ID } from '../../../management/common/constants';
import { fleetGetPackageListHttpMock } from '../../../management/pages/endpoint_hosts/mocks';

type UiRender = (ui: React.ReactElement, options?: RenderOptions) => RenderResult;

Expand Down Expand Up @@ -120,6 +121,7 @@ export const createAppRootMockRenderer = (): AppContextTestRender => {
</AppRootProvider>
</KibanaContextProvider>
);

const render: UiRender = (ui, options) => {
return reactRender(ui, {
wrapper: AppWrapper as React.ComponentType,
Expand All @@ -134,6 +136,23 @@ export const createAppRootMockRenderer = (): AppContextTestRender => {
});
};

// Initialize the singleton `KibanaServices` with global services created for this test instance.
// The module (`../../lib/kibana`) could have been mocked at the test level via `jest.mock()`,
// and if so, then we set the return value of `KibanaServices.get` instead of calling `KibanaServices.init()`
const globalKibanaServicesParams = {
...startServices,
kibanaVersion: '8.0.0',
};

if (jest.isMockFunction(KibanaServices.get)) {
(KibanaServices.get as jest.Mock).mockReturnValue(globalKibanaServicesParams);
} else {
KibanaServices.init(globalKibanaServicesParams);
}

// Some APIs need to be mocked right from the start because they are called as soon as the store is initialized
applyDefaultCoreHttpMocks(coreStart.http);

return {
store,
history,
Expand Down Expand Up @@ -166,3 +185,10 @@ const createCoreStartMock = (): ReturnType<typeof coreMock.createStart> => {

return coreStart;
};

const applyDefaultCoreHttpMocks = (http: AppContextTestRender['coreStart']['http']) => {
// Need to mock getting the endpoint package from the fleet API because it is used as soon
// as the store middleware for Endpoint list is initialized, thus mocking it here would avoid
// unnecessary errors being output to the console
fleetGetPackageListHttpMock(http, { ignoreUnMockedApiRouteErrors: true });
};
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ type HttpMethods = keyof Pick<
const HTTP_METHODS: HttpMethods[] = ['delete', 'fetch', 'get', 'post', 'put', 'head', 'patch'];

export type ApiHandlerMock<R extends ResponseProvidersInterface = ResponseProvidersInterface> = (
http: jest.Mocked<HttpStart>
http: jest.Mocked<HttpStart>,
options?: { ignoreUnMockedApiRouteErrors?: boolean }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although I added this here, we probably don't want to use it often. Having the errors come out on the console when working on specific test cases is likely desired so that you are aware of what is not mocked from an API standpoint

) => MockedApi<R>;

interface RouteMock<R extends ResponseProvidersInterface = ResponseProvidersInterface> {
Expand Down Expand Up @@ -132,8 +133,9 @@ export type ApiHandlerMockFactoryProps<
export const httpHandlerMockFactory = <R extends ResponseProvidersInterface = {}>(
mocks: ApiHandlerMockFactoryProps<R>
): ApiHandlerMock<R> => {
return (http) => {
return (http, options) => {
let inflightApiCalls = 0;
const { ignoreUnMockedApiRouteErrors = false } = options ?? {};
const apiDoneListeners: Array<() => void> = [];
const markApiCallAsHandled = async (delay?: RouteMock['delay']) => {
inflightApiCalls++;
Expand Down Expand Up @@ -221,6 +223,10 @@ export const httpHandlerMockFactory = <R extends ResponseProvidersInterface = {}
return priorMockedFunction(...args);
}

if (ignoreUnMockedApiRouteErrors) {
return;
}

const err = new ApiRouteNotMocked(`API [${method.toUpperCase()} ${path}] is not MOCKED!`);
// Append additional stack calling data from when this API mock was applied
err.stack += `\n${testContextStackTrace}`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,11 +99,30 @@ export const endpointPolicyResponseHttpMock = httpHandlerMockFactory<EndpointPol
]
);

type FleetApisHttpMockInterface = ResponseProvidersInterface<{
agentPolicy: () => GetAgentPoliciesResponse;
export type FleetGetPackageListHttpMockInterface = ResponseProvidersInterface<{
packageList: () => GetPackagesResponse;
}>;
export const fleetApisHttpMock = httpHandlerMockFactory<FleetApisHttpMockInterface>([
export const fleetGetPackageListHttpMock = httpHandlerMockFactory<FleetGetPackageListHttpMockInterface>(
[
{
id: 'packageList',
method: 'get',
path: EPM_API_ROUTES.LIST_PATTERN,
handler() {
const generator = new EndpointDocGenerator('seed');

return {
response: [generator.generateEpmPackage()],
};
},
},
]
);

export type FleetGetAgentPolicyListHttpMockInterface = ResponseProvidersInterface<{
agentPolicy: () => GetAgentPoliciesResponse;
}>;
export const fleetGetAgentPolicyListHttpMock = httpHandlerMockFactory([
{
id: 'agentPolicy',
path: AGENT_POLICY_API_ROUTES.LIST_PATTERN,
Expand All @@ -127,18 +146,13 @@ export const fleetApisHttpMock = httpHandlerMockFactory<FleetApisHttpMockInterfa
};
},
},
{
id: 'packageList',
method: 'get',
path: EPM_API_ROUTES.LIST_PATTERN,
handler() {
const generator = new EndpointDocGenerator('seed');
]);

return {
response: [generator.generateEpmPackage()],
};
},
},
type FleetApisHttpMockInterface = FleetGetPackageListHttpMockInterface &
FleetGetAgentPolicyListHttpMockInterface;
export const fleetApisHttpMock = composeHttpHandlerMocks<FleetApisHttpMockInterface>([
fleetGetPackageListHttpMock,
fleetGetAgentPolicyListHttpMock,
]);

type EndpointPageHttpMockInterface = EndpointMetadataHttpMocksInterface &
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
HostResultList,
HostStatus,
MetadataQueryStrategyVersions,
PendingActionsResponse,
} from '../../../../../common/endpoint/types';
import { EndpointDocGenerator } from '../../../../../common/endpoint/generate_data';
import {
Expand All @@ -28,6 +29,8 @@ import {
GetAgentsResponse,
} from '../../../../../../fleet/common/types/rest_spec';
import { GetPolicyListResponse } from '../../policy/types';
import { pendingActionsResponseMock } from '../../../../common/lib/endpoint_pending_actions/mocks';
import { ACTION_STATUS_ROUTE } from '../../../../../common/endpoint/constants';

const generator = new EndpointDocGenerator('seed');

Expand Down Expand Up @@ -159,6 +162,11 @@ const endpointListApiPathHandlerMocks = ({
perPage: 10,
};
},

// Pending Actions
[ACTION_STATUS_ROUTE]: (): PendingActionsResponse => {
return pendingActionsResponseMock();
},
};

// Build a GET route handler for each endpoint details based on the list of Endpoints passed on input
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ describe('when on the endpoint list page', () => {
afterAll(() => {
abortSpy.mockRestore();
});

beforeEach(() => {
const mockedContext = createAppRootMockRenderer();
({ history, store, coreStart, middlewareSpy } = mockedContext);
Expand Down Expand Up @@ -910,7 +911,10 @@ describe('when on the endpoint list page', () => {
history.push('/endpoints?selected_endpoint=1&show=isolate');
});
renderResult = await renderAndWaitForData();
// Need to reset `http.post` and adjust it so that the mock for http host
// isolation api does not output error noise to the console
coreStart.http.post.mockReset();
coreStart.http.post.mockImplementation(async () => null);
isolateApiMock = hostIsolationHttpMocks(coreStart.http);
});

Expand Down