Skip to content

Commit

Permalink
Add ClusterClient, KibanaRequest, SessionFactory and Lifecycle toolki…
Browse files Browse the repository at this point in the history
…t mocks (elastic#40352)

* add mocks

- expose Elatissearch mocks, KibanaRequest mock
- Logging service mock should accept LoggerFactory
- Provide mocks for session storage
- add return for registerAuth mock
- add mocks for http lifecycle toolkits

* remove leftovers

* address @eli comments
  • Loading branch information
mshustov committed Jul 11, 2019
1 parent 11d1bab commit 4bf1b59
Show file tree
Hide file tree
Showing 6 changed files with 164 additions and 30 deletions.
20 changes: 17 additions & 3 deletions src/core/server/elasticsearch/elasticsearch_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,30 @@

import { BehaviorSubject } from 'rxjs';
import { ClusterClient } from './cluster_client';
import { ScopedClusterClient } from './scoped_cluster_client';
import { ElasticsearchConfig } from './elasticsearch_config';
import { ElasticsearchService, ElasticsearchServiceSetup } from './elasticsearch_service';

const createScopedClusterClientMock = (): jest.Mocked<PublicMethodsOf<ScopedClusterClient>> => ({
callAsInternalUser: jest.fn(),
callAsCurrentUser: jest.fn(),
});

const createClusterClientMock = (): jest.Mocked<PublicMethodsOf<ClusterClient>> => ({
callAsInternalUser: jest.fn(),
asScoped: jest.fn().mockImplementation(createScopedClusterClientMock),
close: jest.fn(),
});

const createSetupContractMock = () => {
const setupContract: jest.Mocked<ElasticsearchServiceSetup> = {
legacy: {
config$: new BehaviorSubject({} as ElasticsearchConfig),
},

createClient: jest.fn(),
adminClient$: new BehaviorSubject({} as ClusterClient),
dataClient$: new BehaviorSubject({} as ClusterClient),
createClient: jest.fn().mockImplementation(createClusterClientMock),
adminClient$: new BehaviorSubject((createClusterClientMock() as unknown) as ClusterClient),
dataClient$: new BehaviorSubject((createClusterClientMock() as unknown) as ClusterClient),
};
return setupContract;
};
Expand All @@ -50,4 +62,6 @@ const createMock = () => {
export const elasticsearchServiceMock = {
create: createMock,
createSetupContract: createSetupContractMock,
createClusterClient: createClusterClientMock,
createScopedClusterClient: createScopedClusterClientMock,
};
46 changes: 46 additions & 0 deletions src/core/server/http/cookie_session_storage.mocks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { SessionStorageFactory, SessionStorage } from './session_storage';

const createSessionStorageMock = <T>(): jest.Mocked<SessionStorage<T>> => ({
get: jest.fn().mockResolvedValue({}),
set: jest.fn(),
clear: jest.fn(),
});

type ReturnMocked<T> = {
[K in keyof T]: T[K] extends (...args: any[]) => infer U
? (...args: any[]) => jest.Mocked<U>
: T[K];
};

type DeepMocked<T> = jest.Mocked<ReturnMocked<T>>;

const creatSessionStorageFactoryMock = <T>() => {
const mocked: DeepMocked<SessionStorageFactory<T>> = {
asScoped: jest.fn(),
};
mocked.asScoped.mockImplementation(createSessionStorageMock);
return mocked;
};

export const sessionStorageMock = {
create: createSessionStorageMock,
createFactory: creatSessionStorageFactoryMock,
};
52 changes: 50 additions & 2 deletions src/core/server/http/http_server.mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,55 @@
import { Request, ResponseToolkit } from 'hapi';
import { merge } from 'lodash';

import { KibanaRequest } from './router';
import querystring from 'querystring';

import { schema } from '@kbn/config-schema';

import { KibanaRequest, RouteMethod } from './router';

interface RequestFixtureOptions {
headers?: Record<string, string>;
params?: Record<string, unknown>;
body?: Record<string, unknown>;
query?: Record<string, unknown>;
path?: string;
method?: RouteMethod;
}

function createKibanaRequestMock({
path = '/path',
headers = { accept: 'something/html' },
params = {},
body = {},
query = {},
method = 'get',
}: RequestFixtureOptions = {}) {
const queryString = querystring.stringify(query);
return KibanaRequest.from(
{
headers,
params,
query,
payload: body,
path,
method,
url: {
path,
query: queryString,
search: queryString ? `?${queryString}` : queryString,
},
route: { settings: {} },
raw: {
req: {},
},
} as any,
{
params: schema.object({}, { allowUnknowns: true }),
body: schema.object({}, { allowUnknowns: true }),
query: schema.object({}, { allowUnknowns: true }),
}
);
}

type DeepPartial<T> = T extends any[]
? DeepPartialArray<T[number]>
Expand Down Expand Up @@ -54,7 +102,7 @@ function createRawResponseToolkitMock(customization: DeepPartial<ResponseToolkit
}

export const httpServerMock = {
createKibanaRequest: () => KibanaRequest.from(createRawRequestMock()),
createKibanaRequest: createKibanaRequestMock,
createRawRequest: createRawRequestMock,
createRawResponseToolkit: createRawResponseToolkitMock,
};
54 changes: 38 additions & 16 deletions src/core/server/http/http_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,22 @@ import { Server } from 'hapi';
import { HttpService } from './http_service';
import { HttpServerSetup } from './http_server';
import { HttpServiceSetup } from './http_service';
import { OnPreAuthToolkit } from './lifecycle/on_pre_auth';
import { AuthToolkit } from './lifecycle/auth';
import { OnPostAuthToolkit } from './lifecycle/on_post_auth';
import { sessionStorageMock } from './cookie_session_storage.mocks';

type ServiceSetupMockType = jest.Mocked<HttpServiceSetup> & {
basePath: jest.Mocked<HttpServiceSetup['basePath']>;
};

const createBasePathMock = (): jest.Mocked<HttpServiceSetup['basePath']> => ({
get: jest.fn(),
set: jest.fn(),
prepend: jest.fn(),
remove: jest.fn(),
});

const createSetupContractMock = () => {
const setupContract: ServiceSetupMockType = {
// we can mock some hapi server method when we need it
Expand All @@ -33,12 +45,7 @@ const createSetupContractMock = () => {
registerAuth: jest.fn(),
registerOnPostAuth: jest.fn(),
registerRouter: jest.fn(),
basePath: {
get: jest.fn(),
set: jest.fn(),
prepend: jest.fn(),
remove: jest.fn(),
},
basePath: createBasePathMock(),
auth: {
get: jest.fn(),
isAuthenticated: jest.fn(),
Expand All @@ -48,17 +55,12 @@ const createSetupContractMock = () => {
isTlsEnabled: false,
};
setupContract.createNewServer.mockResolvedValue({} as HttpServerSetup);
setupContract.registerAuth.mockResolvedValue({
sessionStorageFactory: sessionStorageMock.createFactory(),
});
return setupContract;
};

const createStartContractMock = () => {
const startContract = {
isListening: jest.fn(),
};
startContract.isListening.mockReturnValue(true);
return startContract;
};

type HttpServiceContract = PublicMethodsOf<HttpService>;
const createHttpServiceMock = () => {
const mocked: jest.Mocked<HttpServiceContract> = {
Expand All @@ -67,12 +69,32 @@ const createHttpServiceMock = () => {
stop: jest.fn(),
};
mocked.setup.mockResolvedValue(createSetupContractMock());
mocked.start.mockResolvedValue(createStartContractMock());
return mocked;
};

const createOnPreAuthToolkitMock = (): jest.Mocked<OnPreAuthToolkit> => ({
next: jest.fn(),
redirected: jest.fn(),
rejected: jest.fn(),
});

const createAuthToolkitMock = (): jest.Mocked<AuthToolkit> => ({
authenticated: jest.fn(),
redirected: jest.fn(),
rejected: jest.fn(),
});

const createOnPostAuthToolkitMock = (): jest.Mocked<OnPostAuthToolkit> => ({
next: jest.fn(),
redirected: jest.fn(),
rejected: jest.fn(),
});

export const httpServiceMock = {
create: createHttpServiceMock,
createBasePath: createBasePathMock,
createSetupContract: createSetupContractMock,
createStartContract: createStartContractMock,
createOnPreAuthToolkit: createOnPreAuthToolkitMock,
createAuthToolkit: createAuthToolkitMock,
createOnPostAuthToolkit: createOnPostAuthToolkitMock,
};
18 changes: 10 additions & 8 deletions src/core/server/logging/logging_service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
// Test helpers to simplify mocking logs and collecting all their outputs
import { Logger } from './logger';
import { LoggingService } from './logging_service';
import { LoggerFactory } from './logger_factory';

type LoggingServiceContract = PublicMethodsOf<LoggingService>;
type MockedLogger = jest.Mocked<Logger>;
Expand Down Expand Up @@ -50,8 +51,8 @@ const createLoggingServiceMock = () => {
return mocked;
};

const collectLoggingServiceMock = (mocked: ReturnType<typeof createLoggingServiceMock>) => {
const mockLog = mocked.get() as MockedLogger;
const collectLoggingServiceMock = (loggerFactory: LoggerFactory) => {
const mockLog = loggerFactory.get() as MockedLogger;
return {
debug: mockLog.debug.mock.calls,
error: mockLog.error.mock.calls,
Expand All @@ -63,13 +64,14 @@ const collectLoggingServiceMock = (mocked: ReturnType<typeof createLoggingServic
};
};

const clearLoggingServiceMock = (mocked: ReturnType<typeof createLoggingServiceMock>) => {
const mockLog = mocked.get() as MockedLogger;
mocked.get.mockClear();
mocked.asLoggerFactory.mockClear();
mocked.upgrade.mockClear();
mocked.stop.mockClear();
const clearLoggingServiceMock = (loggerFactory: LoggerFactory) => {
const mockedLoggerFactory = (loggerFactory as unknown) as jest.Mocked<LoggingServiceContract>;
mockedLoggerFactory.get.mockClear();
mockedLoggerFactory.asLoggerFactory.mockClear();
mockedLoggerFactory.upgrade.mockClear();
mockedLoggerFactory.stop.mockClear();

const mockLog = loggerFactory.get() as MockedLogger;
mockLog.debug.mockClear();
mockLog.info.mockClear();
mockLog.warn.mockClear();
Expand Down
4 changes: 3 additions & 1 deletion src/core/server/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { loggingServiceMock } from './logging/logging_service.mock';
import { elasticsearchServiceMock } from './elasticsearch/elasticsearch_service.mock';
import { httpServiceMock } from './http/http_service.mock';

export { httpServerMock } from './http/http_server.mocks';
export { sessionStorageMock } from './http/cookie_session_storage.mocks';
export { configServiceMock } from './config/config_service.mock';
export { elasticsearchServiceMock } from './elasticsearch/elasticsearch_service.mock';
export { httpServiceMock } from './http/http_service.mock';
Expand All @@ -38,7 +40,7 @@ export function pluginInitializerContextConfigMock<T>(config: T) {
}

function pluginInitializerContextMock<T>(config: T) {
const mock: jest.Mocked<PluginInitializerContext<T>> = {
const mock: PluginInitializerContext<T> = {
logger: loggingServiceMock.create(),
env: {
mode: {
Expand Down

0 comments on commit 4bf1b59

Please sign in to comment.