elasticsearch::Client#child performance improvements (#77836) (#78445)

* Updating the version of the elasticsearch-js Client

* ES Client methods aren't implicitly bound to the Client anymore

* Adjusting mocks to work with prototypical inheritance

* Fixing effects of ping returning a Boolean, now.

* Updating @elastic/elasticsearch to 7.9.1

* Responding to @restrry's feedback

* Now with destructuring...
This commit is contained in:
Brandon Kobel 2020-09-24 11:00:01 -07:00 committed by GitHub
parent 22ded370ee
commit 977259d9e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 26 deletions

View file

@ -115,7 +115,7 @@
"@babel/core": "^7.11.1",
"@babel/register": "^7.10.5",
"@elastic/datemath": "5.0.3",
"@elastic/elasticsearch": "7.9.0-rc.2",
"@elastic/elasticsearch": "7.9.1",
"@elastic/eui": "29.0.0",
"@elastic/good": "8.1.1-kibana2",
"@elastic/numeral": "^2.5.0",

View file

@ -31,6 +31,7 @@ const createInternalClientMock = (): DeeplyMockedKeys<Client> => {
'_events',
'_eventsCount',
'_maxListeners',
'constructor',
'name',
'serializer',
'connectionPool',
@ -38,35 +39,57 @@ const createInternalClientMock = (): DeeplyMockedKeys<Client> => {
'helpers',
];
const getAllPropertyDescriptors = (obj: Record<string, any>) => {
const descriptors = Object.entries(Object.getOwnPropertyDescriptors(obj));
let prototype = Object.getPrototypeOf(obj);
while (prototype != null && prototype !== Object.prototype) {
descriptors.push(...Object.entries(Object.getOwnPropertyDescriptors(prototype)));
prototype = Object.getPrototypeOf(prototype);
}
return descriptors;
};
const mockify = (obj: Record<string, any>, omitted: string[] = []) => {
Object.keys(obj)
.filter((key) => !omitted.includes(key))
.forEach((key) => {
const propType = typeof obj[key];
if (propType === 'function') {
// the @elastic/elasticsearch::Client uses prototypical inheritance
// so we have to crawl up the prototype chain and get all descriptors
// to find everything that we should be mocking
const descriptors = getAllPropertyDescriptors(obj);
descriptors
.filter(([key]) => !omitted.includes(key))
.forEach(([key, descriptor]) => {
if (typeof descriptor.value === 'function') {
obj[key] = jest.fn(() => createSuccessTransportRequestPromise({}));
} else if (propType === 'object' && obj[key] != null) {
mockify(obj[key]);
} else if (typeof obj[key] === 'object' && obj[key] != null) {
mockify(obj[key], omitted);
}
});
};
mockify(client, omittedProps);
// client got some read-only (getter) properties
// so we need to extend it to override the getter-only props.
const mock: any = { ...client };
client.close = jest.fn().mockReturnValue(Promise.resolve());
client.child = jest.fn().mockImplementation(() => createInternalClientMock());
mock.transport = {
const mockGetter = (obj: Record<string, any>, propertyName: string) => {
Object.defineProperty(obj, propertyName, {
configurable: true,
enumerable: false,
get: () => jest.fn(),
set: undefined,
});
};
// `on`, `off`, and `once` are properties without a setter.
// We can't `client.on = jest.fn()` because the following error will be thrown:
// TypeError: Cannot set property on of #<Client> which has only a getter
mockGetter(client, 'on');
mockGetter(client, 'off');
mockGetter(client, 'once');
client.transport = {
request: jest.fn(),
};
mock.close = jest.fn().mockReturnValue(Promise.resolve());
mock.child = jest.fn().mockImplementation(() => createInternalClientMock());
mock.on = jest.fn();
mock.off = jest.fn();
mock.once = jest.fn();
return (mock as unknown) as DeeplyMockedKeys<Client>;
return client as DeeplyMockedKeys<Client>;
};
export type ElasticsearchClientMock = DeeplyMockedKeys<ElasticsearchClient>;

View file

@ -80,7 +80,7 @@ export function createMigrationEsClient(
throw new Error(`unknown ElasticsearchClient client method [${key}]`);
}
return await migrationRetryCallCluster(
() => fn(params, { maxRetries: 0, ...options }),
() => fn.call(client, params, { maxRetries: 0, ...options }),
log,
delay
);

View file

@ -26,7 +26,7 @@ export class ElasticsearchClientPlugin implements Plugin {
{ path: '/api/elasticsearch_client_plugin/context/ping', validate: false },
async (context, req, res) => {
const { body } = await context.core.elasticsearch.client.asInternalUser.ping();
return res.ok({ body });
return res.ok({ body: JSON.stringify(body) });
}
);
router.get(
@ -34,14 +34,14 @@ export class ElasticsearchClientPlugin implements Plugin {
async (context, req, res) => {
const [coreStart] = await core.getStartServices();
const { body } = await coreStart.elasticsearch.client.asInternalUser.ping();
return res.ok({ body });
return res.ok({ body: JSON.stringify(body) });
}
);
router.get(
{ path: '/api/elasticsearch_client_plugin/custom_client/ping', validate: false },
async (context, req, res) => {
const { body } = await this.client!.asInternalUser.ping();
return res.ok({ body });
return res.ok({ body: JSON.stringify(body) });
}
);
}

View file

@ -1215,10 +1215,10 @@
pump "^3.0.0"
secure-json-parse "^2.1.0"
"@elastic/elasticsearch@7.9.0-rc.2":
version "7.9.0-rc.2"
resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.9.0-rc.2.tgz#cbc935f30940a15484b5ec3758c9b1ef119a5e5c"
integrity sha512-1FKCQJVr7s/LasKq6VbrmbWCI0LjoPcnjgmh2vKPzC+yyEEHVoYlmEfR5wBRchK1meATTXZtDhCVF95+Q9kVbA==
"@elastic/elasticsearch@7.9.1":
version "7.9.1"
resolved "https://registry.yarnpkg.com/@elastic/elasticsearch/-/elasticsearch-7.9.1.tgz#40f1c38e8f70d783851c13be78a7cb346891c15e"
integrity sha512-NfPADbm9tRK/4ohpm9+aBtJ8WPKQqQaReyBKT225pi2oKQO1IzRlfM+OPplAvbhoH1efrSj1NKk27L+4BCrzXQ==
dependencies:
debug "^4.1.1"
decompress-response "^4.2.0"