diff --git a/lib/Transport.js b/lib/Transport.js index 8d23aea86..f25e9f82d 100644 --- a/lib/Transport.js +++ b/lib/Transport.js @@ -182,10 +182,14 @@ class Transport { let request = { abort: noop }; const transportReturn = { then(onFulfilled, onRejected) { - return p.then(onFulfilled, onRejected); + if (p != null) { + return p.then(onFulfilled, onRejected); + } }, catch(onRejected) { - return p.catch(onRejected); + if (p != null) { + return p.catch(onRejected); + } }, abort() { meta.aborted = true; @@ -194,7 +198,9 @@ class Transport { return this; }, finally(onFinally) { - return p.finally(onFinally); + if (p != null) { + return p.finally(onFinally); + } }, }; diff --git a/test/unit/client.test.js b/test/unit/client.test.js index 4a4f2bf98..ce79d91c8 100644 --- a/test/unit/client.test.js +++ b/test/unit/client.test.js @@ -34,8 +34,9 @@ const { test } = require('tap'); const { URL } = require('url'); const buffer = require('buffer'); const intoStream = require('into-stream'); -const { ConnectionPool, Transport, Connection, errors } = require('../../index'); -const { Client, buildServer } = require('../utils'); +const { ConnectionPool, Transport, Connection, errors, Client: ProductClient } = require('../../index'); +const { Client, buildServer, connection } = require('../utils'); +const { buildMockConnection } = connection let clientVersion = require('../../package.json').version; if (clientVersion.includes('-')) { clientVersion = clientVersion.slice(0, clientVersion.indexOf('-')) + 'p'; @@ -1189,3 +1190,130 @@ test('API compatibility header (x-ndjson)', (t) => { }); }); }); + +test('Issue #253 with promises', async t => { + t.plan(1) + + const delay = () => new Promise(resolve => setTimeout(resolve, 10)) + + const MockConnection = buildMockConnection({ + onRequest (params) { + return { + statusCode: 200, + headers: { + 'x-elastic-product': 'Elasticsearch' + }, + body: { + name: '1ef419078577', + cluster_name: 'docker-cluster', + cluster_uuid: 'cQ5pAMvRRTyEzObH4L5mTA', + version: { + number: '8.0.0-SNAPSHOT', + build_flavor: 'default', + build_type: 'docker', + build_hash: '5fb4c050958a6b0b6a70a6fb3e616d0e390eaac3', + build_date: '2021-07-10T01:45:02.136546168Z', + build_snapshot: true, + lucene_version: '8.9.0', + minimum_wire_compatibility_version: '7.15.0', + minimum_index_compatibility_version: '7.0.0' + }, + tagline: 'You Know, for Search' + } + } + } + }) + + class MyTransport extends Transport { + request (params, options = {}, callback) { + if (typeof options === 'function') { + callback = options + options = {} + } + + if (typeof callback === 'undefined') { + return delay() + .then(() => super.request(params, options)) + } + + // Callback support + delay() + .then(() => super.request(params, options, callback)) + } + } + + const client = new ProductClient({ + node: 'http://localhost:9200', + Transport: MyTransport, + Connection: MockConnection + }) + + try { + await client.search({}) + t.pass('ok') + } catch (err) { + t.fail(err) + } +}) + +test('Issue #253 with callbacks', t => { + t.plan(1) + + const delay = () => new Promise(resolve => setTimeout(resolve, 10)) + + const MockConnection = buildMockConnection({ + onRequest (params) { + return { + statusCode: 200, + headers: { + 'x-elastic-product': 'Elasticsearch' + }, + body: { + name: '1ef419078577', + cluster_name: 'docker-cluster', + cluster_uuid: 'cQ5pAMvRRTyEzObH4L5mTA', + version: { + number: '8.0.0-SNAPSHOT', + build_flavor: 'default', + build_type: 'docker', + build_hash: '5fb4c050958a6b0b6a70a6fb3e616d0e390eaac3', + build_date: '2021-07-10T01:45:02.136546168Z', + build_snapshot: true, + lucene_version: '8.9.0', + minimum_wire_compatibility_version: '7.15.0', + minimum_index_compatibility_version: '7.0.0' + }, + tagline: 'You Know, for Search' + } + } + } + }) + + class MyTransport extends Transport { + request (params, options = {}, callback) { + if (typeof options === 'function') { + callback = options + options = {} + } + + if (typeof callback === 'undefined') { + return delay() + .then(() => super.request(params, options)) + } + + // Callback support + delay() + .then(() => super.request(params, options, callback)) + } + } + + const client = new ProductClient({ + node: 'http://localhost:9200', + Transport: MyTransport, + Connection: MockConnection + }) + + client.search({}, (err, result) => { + t.error(err) + }) +})