mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
* add middleware for handling refetch * add unit test for error links * add unit test
This commit is contained in:
parent
8aa6b14867
commit
aa28b84e7f
5 changed files with 200 additions and 22 deletions
108
x-pack/plugins/siem/public/containers/errors/index.test.tsx
Normal file
108
x-pack/plugins/siem/public/containers/errors/index.test.tsx
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* 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 { reTryOneTimeOnErrorHandler, errorLinkHandler } from '.';
|
||||
import { ServerError } from 'apollo-link-http-common';
|
||||
import { Operation } from 'apollo-link';
|
||||
import { GraphQLError } from 'graphql';
|
||||
import * as store from '../../store';
|
||||
import { onError } from 'apollo-link-error';
|
||||
|
||||
const mockDispatch = jest.fn();
|
||||
jest.mock('apollo-link-error');
|
||||
jest.mock('../../store');
|
||||
// @ts-ignore
|
||||
store.getStore.mockReturnValue({ dispatch: mockDispatch });
|
||||
|
||||
describe('errorLinkHandler', () => {
|
||||
const mockGraphQLErrors: GraphQLError = {
|
||||
message: 'GraphQLError',
|
||||
} as GraphQLError;
|
||||
const mockNetworkError: ServerError = {
|
||||
result: {},
|
||||
statusCode: 503,
|
||||
name: '',
|
||||
message: 'error',
|
||||
response: {
|
||||
ok: false,
|
||||
} as Response,
|
||||
};
|
||||
const mockOperation: Operation = {} as Operation;
|
||||
const mockForward = jest.fn();
|
||||
|
||||
afterEach(() => {
|
||||
mockDispatch.mockClear();
|
||||
});
|
||||
|
||||
test('it should display error if graphQLErrors exist', () => {
|
||||
errorLinkHandler({
|
||||
graphQLErrors: [mockGraphQLErrors],
|
||||
operation: mockOperation,
|
||||
forward: mockForward,
|
||||
});
|
||||
|
||||
expect(store.getStore).toBeCalled();
|
||||
expect(mockDispatch.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
test('it should display error if networkError exist', () => {
|
||||
errorLinkHandler({
|
||||
networkError: mockNetworkError,
|
||||
operation: mockOperation,
|
||||
forward: mockForward,
|
||||
});
|
||||
|
||||
expect(store.getStore).toBeCalled();
|
||||
expect(mockDispatch.mock.calls.length).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('errorLink', () => {
|
||||
test('onError should be called with errorLinkHandler', () => {
|
||||
expect(onError).toHaveBeenCalledWith(errorLinkHandler);
|
||||
});
|
||||
});
|
||||
|
||||
describe('reTryOneTimeOnErrorHandler', () => {
|
||||
const mockNetworkError: ServerError = {
|
||||
result: {},
|
||||
statusCode: 503,
|
||||
name: '',
|
||||
message: 'error',
|
||||
response: {
|
||||
ok: false,
|
||||
} as Response,
|
||||
};
|
||||
const mockOperation: Operation = {} as Operation;
|
||||
const mockForward = jest.fn();
|
||||
|
||||
afterEach(() => {
|
||||
mockForward.mockClear();
|
||||
});
|
||||
test('it should retry only if network status code is 503', () => {
|
||||
reTryOneTimeOnErrorHandler({
|
||||
networkError: mockNetworkError,
|
||||
operation: mockOperation,
|
||||
forward: mockForward,
|
||||
});
|
||||
expect(mockForward).toBeCalledWith(mockOperation);
|
||||
});
|
||||
|
||||
test('it should not retry if other error happens', () => {
|
||||
reTryOneTimeOnErrorHandler({
|
||||
networkError: { ...mockNetworkError, statusCode: 500 },
|
||||
operation: mockOperation,
|
||||
forward: mockForward,
|
||||
});
|
||||
expect(mockForward).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('reTryOneTimeOnErrorLink', () => {
|
||||
test('onError should be called with reTryOneTimeOnErrorHandler', () => {
|
||||
expect(onError).toHaveBeenCalledWith(reTryOneTimeOnErrorHandler);
|
||||
});
|
||||
});
|
|
@ -4,16 +4,18 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { onError } from 'apollo-link-error';
|
||||
import { onError, ErrorLink } from 'apollo-link-error';
|
||||
import { get } from 'lodash/fp';
|
||||
|
||||
import uuid from 'uuid';
|
||||
import * as i18n from './translations';
|
||||
|
||||
import { getStore } from '../../store';
|
||||
import { appActions } from '../../store/actions';
|
||||
|
||||
import * as i18n from './translations';
|
||||
|
||||
export const errorLink = onError(({ graphQLErrors, networkError }) => {
|
||||
export const errorLinkHandler: ErrorLink.ErrorHandler = ({ graphQLErrors, networkError }) => {
|
||||
const store = getStore();
|
||||
|
||||
if (graphQLErrors != null && store != null) {
|
||||
graphQLErrors.forEach(({ message }) =>
|
||||
store.dispatch(
|
||||
|
@ -31,4 +33,20 @@ export const errorLink = onError(({ graphQLErrors, networkError }) => {
|
|||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
export const errorLink = onError(errorLinkHandler);
|
||||
|
||||
export const reTryOneTimeOnErrorHandler: ErrorLink.ErrorHandler = ({
|
||||
networkError,
|
||||
operation,
|
||||
forward,
|
||||
}) => {
|
||||
if (networkError != null) {
|
||||
const statusCode = get('statusCode', networkError);
|
||||
if (statusCode != null && statusCode === 503) {
|
||||
return forward(operation);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const reTryOneTimeOnErrorLink = onError(reTryOneTimeOnErrorHandler);
|
||||
|
|
40
x-pack/plugins/siem/public/lib/compose/helpers.test.ts
Normal file
40
x-pack/plugins/siem/public/lib/compose/helpers.test.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* 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 { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
|
||||
import { errorLink, reTryOneTimeOnErrorLink } from '../../containers/errors';
|
||||
import { getLinks } from './helpers';
|
||||
import { withClientState } from 'apollo-link-state';
|
||||
import * as apolloLinkHttp from 'apollo-link-http';
|
||||
import introspectionQueryResultData from '../../graphql/introspection.json';
|
||||
|
||||
jest.mock('apollo-cache-inmemory');
|
||||
jest.mock('apollo-link-http');
|
||||
jest.mock('apollo-link-state');
|
||||
jest.mock('../../containers/errors');
|
||||
const mockWithClientState = 'mockWithClientState';
|
||||
const mockHttpLink = { mockHttpLink: 'mockHttpLink' };
|
||||
|
||||
// @ts-ignore
|
||||
withClientState.mockReturnValue(mockWithClientState);
|
||||
// @ts-ignore
|
||||
apolloLinkHttp.HttpLink.mockImplementation(() => mockHttpLink);
|
||||
|
||||
describe('getLinks helper', () => {
|
||||
test('It should return links in correct order', () => {
|
||||
const mockCache = new InMemoryCache({
|
||||
dataIdFromObject: () => null,
|
||||
fragmentMatcher: new IntrospectionFragmentMatcher({
|
||||
introspectionQueryResultData,
|
||||
}),
|
||||
});
|
||||
const links = getLinks(mockCache);
|
||||
expect(links[0]).toEqual(errorLink);
|
||||
expect(links[1]).toEqual(reTryOneTimeOnErrorLink);
|
||||
expect(links[2]).toEqual(mockWithClientState);
|
||||
expect(links[3]).toEqual(mockHttpLink);
|
||||
});
|
||||
});
|
27
x-pack/plugins/siem/public/lib/compose/helpers.ts
Normal file
27
x-pack/plugins/siem/public/lib/compose/helpers.ts
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* 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 { HttpLink } from 'apollo-link-http';
|
||||
import { withClientState } from 'apollo-link-state';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
import chrome from 'ui/chrome';
|
||||
import { errorLink, reTryOneTimeOnErrorLink } from '../../containers/errors';
|
||||
|
||||
export const getLinks = (cache: InMemoryCache) => [
|
||||
errorLink,
|
||||
reTryOneTimeOnErrorLink,
|
||||
withClientState({
|
||||
cache,
|
||||
resolvers: {},
|
||||
}),
|
||||
new HttpLink({
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
},
|
||||
uri: `${chrome.getBasePath()}/api/siem/graphql`,
|
||||
}),
|
||||
];
|
|
@ -7,8 +7,6 @@
|
|||
import { InMemoryCache, IntrospectionFragmentMatcher } from 'apollo-cache-inmemory';
|
||||
import ApolloClient from 'apollo-client';
|
||||
import { ApolloLink } from 'apollo-link';
|
||||
import { HttpLink } from 'apollo-link-http';
|
||||
import { withClientState } from 'apollo-link-state';
|
||||
import 'ui/autoload/all';
|
||||
// @ts-ignore: path dynamic for kibana
|
||||
import chrome from 'ui/chrome';
|
||||
|
@ -18,11 +16,11 @@ import uiRoutes from 'ui/routes';
|
|||
// @ts-ignore: path dynamic for kibana
|
||||
import { timezoneProvider } from 'ui/vis/lib/timezone';
|
||||
|
||||
import { errorLink } from '../../containers/errors';
|
||||
import introspectionQueryResultData from '../../graphql/introspection.json';
|
||||
import { AppKibanaFrameworkAdapter } from '../adapters/framework/kibana_framework_adapter';
|
||||
import { AppKibanaObservableApiAdapter } from '../adapters/observable_api/kibana_observable_api';
|
||||
import { AppFrontendLibs } from '../lib';
|
||||
import { getLinks } from './helpers';
|
||||
|
||||
export function compose(): AppFrontendLibs {
|
||||
const cache = new InMemoryCache({
|
||||
|
@ -40,20 +38,7 @@ export function compose(): AppFrontendLibs {
|
|||
const graphQLOptions = {
|
||||
connectToDevTools: process.env.NODE_ENV !== 'production',
|
||||
cache,
|
||||
link: ApolloLink.from([
|
||||
errorLink,
|
||||
withClientState({
|
||||
cache,
|
||||
resolvers: {},
|
||||
}),
|
||||
new HttpLink({
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'kbn-xsrf': chrome.getXsrfToken(),
|
||||
},
|
||||
uri: `${chrome.getBasePath()}/api/siem/graphql`,
|
||||
}),
|
||||
]),
|
||||
link: ApolloLink.from(getLinks(cache)),
|
||||
};
|
||||
|
||||
const apolloClient = new ApolloClient(graphQLOptions);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue