Skip to content

Commit a022bcd

Browse files
FrankHassanabadandrew-goldstein
authored andcommitted
Added mocks and logging (#24743)
* Added mocks and logging * https://github.com/elastic/ingest-dev/issues/54 * Added test mocks to GraphQL * Added logging * Added unit tests * Removed dead variable causing the build to fail
1 parent 8de4294 commit a022bcd

File tree

8 files changed

+218
-4
lines changed

8 files changed

+218
-4
lines changed

x-pack/plugins/secops/server/graphql/index.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,54 @@
55
*/
66

77
import { rootSchema } from '../../common/graphql/root/schema.gql';
8+
import sourceMock from '../graphql/sources/source.mock';
9+
import sourcesMock from '../graphql/sources/sources.mock';
10+
import { Logger } from '../utils/logger';
811
import { sourcesSchema } from './sources/schema.gql';
912

1013
export const schemas = [rootSchema, sourcesSchema];
14+
15+
// The types from graphql-tools/src/mock.ts 'any' based. I add slightly
16+
// stricter types here, but these should go away when graphql-tools using something
17+
// other than "any" in the future for its types.
18+
// https://github.com/apollographql/graphql-tools/blob/master/src/mock.ts#L406
19+
interface Context {
20+
req: {
21+
payload: {
22+
operationName: string;
23+
};
24+
};
25+
}
26+
27+
export const createMocks = (logger: Logger) => ({
28+
Query: () => ({
29+
allSources: (root: unknown, args: unknown, context: Context) => {
30+
logger.info('Mock allSources');
31+
const operationName = context.req.payload.operationName.toLowerCase();
32+
switch (operationName) {
33+
case 'test': {
34+
logger.info(`Using mock for test ${sourceMock}`);
35+
return sourcesMock;
36+
}
37+
default: {
38+
logger.error(`Could not find a mock for: ${operationName}`);
39+
return [];
40+
}
41+
}
42+
},
43+
source: (root: unknown, args: unknown, context: Context) => {
44+
logger.info('Mock source');
45+
const operationName = context.req.payload.operationName.toLowerCase();
46+
switch (operationName) {
47+
case 'test': {
48+
logger.info(`Using mock for test ${sourceMock}`);
49+
return sourceMock;
50+
}
51+
default: {
52+
logger.error(`Could not find a mock for: ${operationName}`);
53+
return {};
54+
}
55+
}
56+
},
57+
}),
58+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
/* tslint:disable */
8+
9+
export default
10+
{
11+
"id": "default",
12+
"configuration": {
13+
"fields": {
14+
"host": "beat.hostname"
15+
}
16+
}
17+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
/* tslint:disable */
8+
9+
export default
10+
[
11+
{
12+
"id": "default",
13+
"configuration": {
14+
"fields": {
15+
"container": "docker.container.name",
16+
"host": "beat.hostname",
17+
"message": [
18+
"message",
19+
"@message"
20+
]
21+
}
22+
}
23+
}
24+
]

x-pack/plugins/secops/server/init_server.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,29 @@
44
* you may not use this file except in compliance with the Elastic License.
55
*/
66

7-
import { IResolvers, makeExecutableSchema } from 'graphql-tools';
7+
import { addMockFunctionsToSchema, IResolvers, makeExecutableSchema } from 'graphql-tools';
8+
89
import { schemas } from './graphql';
10+
import { createMocks } from './graphql';
911
import { createSourcesResolvers } from './graphql/sources';
1012
import { AppBackendLibs } from './lib/types';
13+
import { Logger } from './utils/logger';
14+
15+
export interface Config {
16+
mocking: boolean;
17+
logger: Logger;
18+
}
1119

12-
export const initServer = (libs: AppBackendLibs) => {
20+
export const initServer = (libs: AppBackendLibs, config: Config) => {
21+
const { logger, mocking } = config;
1322
const schema = makeExecutableSchema({
1423
resolvers: [createSourcesResolvers(libs) as IResolvers],
1524
typeDefs: schemas,
1625
});
1726

27+
if (mocking) {
28+
const mocks = createMocks(logger);
29+
addMockFunctionsToSchema({ mocks, schema });
30+
}
1831
libs.framework.registerGraphQLEndpoint('/api/secops/graphql', schema);
1932
};
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { amMocking } from './kibana.index';
8+
9+
describe('kibana.index', () => {
10+
describe('#amMocking', () => {
11+
afterEach(() => delete process.env.INGEST_MOCKS);
12+
13+
test('should return true when process.ENV.mocking is set to a lower case string true', () => {
14+
process.env.INGEST_MOCKS = 'true';
15+
expect(amMocking()).toEqual(true);
16+
});
17+
test('should return false when process.ENV.mocking is not set', () => {
18+
expect(amMocking()).toEqual(false);
19+
});
20+
test('should return false when process.ENV.mocking is not set to a lower case string (since I am picky)', () => {
21+
process.env.INGEST_MOCKS = 'TRUE';
22+
expect(amMocking()).toEqual(false);
23+
});
24+
});
25+
});

x-pack/plugins/secops/server/kibana.index.ts

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,34 @@
66

77
import { Server } from 'hapi';
88
import JoiNamespace from 'joi';
9+
910
import { initServer } from './init_server';
1011
import { compose } from './lib/compose/kibana';
12+
import { createLogger } from './utils/logger';
13+
14+
const APP_ID = 'secops';
1115

1216
export interface KbnServer extends Server {
13-
usage: any;
17+
usage: unknown;
1418
}
1519

20+
export const amMocking = (): boolean => process.env.INGEST_MOCKS === 'true';
21+
1622
export const initServerWithKibana = (kbnServer: KbnServer) => {
23+
const logger = createLogger(kbnServer);
24+
logger.info('Plugin initializing');
25+
26+
const mocking = amMocking();
27+
if (mocking) {
28+
logger.info(
29+
`Mocks for ${APP_ID} is activated. No real ${APP_ID} data will be used, only mocks will be used.`
30+
);
31+
}
32+
1733
const libs = compose(kbnServer);
18-
initServer(libs);
34+
initServer(libs, { mocking, logger });
35+
36+
logger.info('Plugin done initializing');
1937
};
2038

2139
export const getConfigSchema = (Joi: typeof JoiNamespace) => {
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { createLogger } from './logger';
8+
9+
const APP_ID = 'secops';
10+
const createMockServer = () => ({ log: jest.fn() });
11+
12+
describe('logger', () => {
13+
describe('#createLogger', () => {
14+
test('should log out debug', () => {
15+
const kbnServer = createMockServer();
16+
const logger = createLogger(kbnServer as any);
17+
logger.debug('debug information');
18+
expect(kbnServer.log.mock.calls[0][0]).toEqual(['debug', APP_ID]);
19+
expect(kbnServer.log.mock.calls[0][1]).toEqual('debug information');
20+
});
21+
22+
test('should log out info', () => {
23+
const kbnServer = createMockServer();
24+
const logger = createLogger(kbnServer as any);
25+
logger.info('info information');
26+
expect(kbnServer.log.mock.calls[0][0]).toEqual(['info', APP_ID]);
27+
expect(kbnServer.log.mock.calls[0][1]).toEqual('info information');
28+
});
29+
30+
test('should log out warn', () => {
31+
const kbnServer = createMockServer();
32+
const logger = createLogger(kbnServer as any);
33+
logger.warn('warn information');
34+
expect(kbnServer.log.mock.calls[0][0]).toEqual(['warning', APP_ID]);
35+
expect(kbnServer.log.mock.calls[0][1]).toEqual('warn information');
36+
});
37+
38+
test('should log out error', () => {
39+
const kbnServer = createMockServer();
40+
const logger = createLogger(kbnServer as any);
41+
logger.error('error information');
42+
expect(kbnServer.log.mock.calls[0][0]).toEqual(['error', APP_ID]);
43+
expect(kbnServer.log.mock.calls[0][1]).toEqual('error information');
44+
});
45+
});
46+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the Elastic License;
4+
* you may not use this file except in compliance with the Elastic License.
5+
*/
6+
7+
import { Server } from 'hapi';
8+
9+
const LOGGING_TAGS = ['secops'];
10+
11+
export interface Logger {
12+
debug: (message: string) => void;
13+
info: (message: string) => void;
14+
warn: (message: string) => void;
15+
error: (message: string) => void;
16+
}
17+
18+
export const createLogger = (kbnServer: Readonly<Server>): Readonly<Logger> => ({
19+
debug: (message: string) => kbnServer.log(['debug', ...LOGGING_TAGS], message),
20+
info: (message: string) => kbnServer.log(['info', ...LOGGING_TAGS], message),
21+
warn: (message: string) => kbnServer.log(['warning', ...LOGGING_TAGS], message),
22+
error: (message: string) => kbnServer.log(['error', ...LOGGING_TAGS], message),
23+
});

0 commit comments

Comments
 (0)