Support for Elasticsearch 7.3 (#928)

This commit is contained in:
Tomas Della Vedova
2019-08-01 10:09:16 +02:00
committed by GitHub
parent 823c209c32
commit 8c78f47ac3
330 changed files with 3990 additions and 6302 deletions

View File

@ -1,21 +1,6 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'

View File

@ -1,21 +1,6 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'
@ -38,7 +23,6 @@ test('Basic (callback)', t => {
client.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
}, (err, { body }) => {
t.error(err)
@ -64,7 +48,6 @@ test('Basic (promises)', t => {
client
.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
})
.then(({ body }) => {
@ -91,7 +74,6 @@ test('Error (callback)', t => {
client.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
}, (err, { body }) => {
t.ok(err)
@ -117,7 +99,6 @@ test('Error (promises)', t => {
client
.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
})
.then(t.fail)
@ -143,7 +124,6 @@ test('Abort method (callback)', t => {
const request = client.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
}, (err, { body }) => {
t.error(err)
@ -170,7 +150,6 @@ test('Abort is not supported in promises', t => {
const request = client.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
})
@ -200,7 +179,6 @@ test('Basic (options and callback)', t => {
client.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
}, {
requestTimeout: 10000
@ -228,7 +206,6 @@ test('Basic (options and promises)', t => {
client
.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
}, {
requestTimeout: 10000
@ -245,7 +222,7 @@ test('Pass unknown parameters as query parameters (and get a warning)', t => {
t.plan(4)
function handler (req, res) {
t.strictEqual(req.url, '/test/doc/_search?q=foo%3Abar&winter=is%20coming')
t.strictEqual(req.url, '/test/_search?q=foo%3Abar&winter=is%20coming')
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
@ -257,7 +234,6 @@ test('Pass unknown parameters as query parameters (and get a warning)', t => {
client.search({
index: 'test',
type: 'doc',
q: 'foo:bar',
winter: 'is coming'
}, (err, { body, warnings }) => {
@ -273,7 +249,7 @@ test('If the API uses the same key for both url and query parameter, the url sho
t.plan(2)
function handler (req, res) {
t.strictEqual(req.url, '/index/type/_bulk')
t.strictEqual(req.url, '/index/_bulk')
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
@ -286,7 +262,6 @@ test('If the API uses the same key for both url and query parameter, the url sho
// bulk has two `type` parameters
client.bulk({
index: 'index',
type: 'type',
body: []
}, (err, { body, warnings }) => {
t.error(err)

View File

@ -0,0 +1,490 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'
const { test } = require('tap')
const { URL } = require('url')
const BaseConnectionPool = require('../../lib/pool/BaseConnectionPool')
const Connection = require('../../lib/Connection')
test('API', t => {
t.test('addConnection', t => {
const pool = new BaseConnectionPool({ Connection })
const href = 'http://localhost:9200/'
pool.addConnection(href)
t.ok(pool.connections.find(c => c.id === href) instanceof Connection)
t.strictEqual(pool.connections.find(c => c.id === href).status, Connection.statuses.ALIVE)
t.end()
})
t.test('addConnection should throw with two connections with the same id', t => {
const pool = new BaseConnectionPool({ Connection })
const href = 'http://localhost:9200/'
pool.addConnection(href)
try {
pool.addConnection(href)
t.fail('Should throw')
} catch (err) {
t.is(err.message, `Connection with id '${href}' is already present`)
}
t.end()
})
t.test('addConnection should handle not-friendly url parameters for user and password', t => {
const pool = new BaseConnectionPool({ Connection })
const href = 'http://us"er:p@assword@localhost:9200/'
pool.addConnection(href)
const conn = pool.connections[0]
t.strictEqual(conn.url.username, 'us%22er')
t.strictEqual(conn.url.password, 'p%40assword')
t.match(conn.headers, {
authorization: 'Basic ' + Buffer.from('us"er:p@assword').toString('base64')
})
t.end()
})
t.test('markDead', t => {
const pool = new BaseConnectionPool({ Connection, sniffEnabled: true })
const href = 'http://localhost:9200/'
var connection = pool.addConnection(href)
t.same(pool.markDead(connection), pool)
connection = pool.connections.find(c => c.id === href)
t.strictEqual(connection.status, Connection.statuses.ALIVE)
t.end()
})
t.test('markAlive', t => {
const pool = new BaseConnectionPool({ Connection, sniffEnabled: true })
const href = 'http://localhost:9200/'
var connection = pool.addConnection(href)
t.same(pool.markAlive(connection), pool)
connection = pool.connections.find(c => c.id === href)
t.strictEqual(connection.status, Connection.statuses.ALIVE)
t.end()
})
t.test('getConnection should throw', t => {
const pool = new BaseConnectionPool({ Connection })
const href = 'http://localhost:9200/'
pool.addConnection(href)
try {
pool.getConnection()
t.fail('Should fail')
} catch (err) {
t.is(err.message, 'getConnection must be implemented')
}
t.end()
})
t.test('removeConnection', t => {
const pool = new BaseConnectionPool({ Connection })
const href = 'http://localhost:9200/'
var connection = pool.addConnection(href)
pool.removeConnection(connection)
t.strictEqual(pool.size, 0)
t.end()
})
t.test('empty', t => {
const pool = new BaseConnectionPool({ Connection })
pool.addConnection('http://localhost:9200/')
pool.addConnection('http://localhost:9201/')
pool.empty(() => {
t.strictEqual(pool.size, 0)
t.end()
})
})
t.test('urlToHost', t => {
const pool = new BaseConnectionPool({ Connection })
const url = 'http://localhost:9200'
t.deepEqual(
pool.urlToHost(url),
{ url: new URL(url) }
)
t.end()
})
t.test('nodesToHost', t => {
t.test('publish_address as ip address (IPv4)', t => {
const pool = new BaseConnectionPool({ Connection })
const nodes = {
a1: {
http: {
publish_address: '127.0.0.1:9200'
},
roles: ['master', 'data', 'ingest']
},
a2: {
http: {
publish_address: '127.0.0.1:9201'
},
roles: ['master', 'data', 'ingest']
}
}
t.deepEqual(pool.nodesToHost(nodes, 'http:'), [{
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: {
master: true,
data: true,
ingest: true,
ml: false
}
}, {
url: new URL('http://127.0.0.1:9201'),
id: 'a2',
roles: {
master: true,
data: true,
ingest: true,
ml: false
}
}])
t.strictEqual(pool.nodesToHost(nodes, 'http:')[0].url.host, '127.0.0.1:9200')
t.strictEqual(pool.nodesToHost(nodes, 'http:')[1].url.host, '127.0.0.1:9201')
t.end()
})
t.test('publish_address as ip address (IPv6)', t => {
const pool = new BaseConnectionPool({ Connection })
const nodes = {
a1: {
http: {
publish_address: '[::1]:9200'
},
roles: ['master', 'data', 'ingest']
},
a2: {
http: {
publish_address: '[::1]:9201'
},
roles: ['master', 'data', 'ingest']
}
}
t.deepEqual(pool.nodesToHost(nodes, 'http:'), [{
url: new URL('http://[::1]:9200'),
id: 'a1',
roles: {
master: true,
data: true,
ingest: true,
ml: false
}
}, {
url: new URL('http://[::1]:9201'),
id: 'a2',
roles: {
master: true,
data: true,
ingest: true,
ml: false
}
}])
t.strictEqual(pool.nodesToHost(nodes, 'http:')[0].url.host, '[::1]:9200')
t.strictEqual(pool.nodesToHost(nodes, 'http:')[1].url.host, '[::1]:9201')
t.end()
})
t.test('publish_address as host/ip (IPv4)', t => {
const pool = new BaseConnectionPool({ Connection })
const nodes = {
a1: {
http: {
publish_address: 'example.com/127.0.0.1:9200'
},
roles: ['master', 'data', 'ingest']
},
a2: {
http: {
publish_address: 'example.com/127.0.0.1:9201'
},
roles: ['master', 'data', 'ingest']
}
}
t.deepEqual(pool.nodesToHost(nodes, 'http:'), [{
url: new URL('http://example.com:9200'),
id: 'a1',
roles: {
master: true,
data: true,
ingest: true,
ml: false
}
}, {
url: new URL('http://example.com:9201'),
id: 'a2',
roles: {
master: true,
data: true,
ingest: true,
ml: false
}
}])
t.strictEqual(pool.nodesToHost(nodes, 'http:')[0].url.host, 'example.com:9200')
t.strictEqual(pool.nodesToHost(nodes, 'http:')[1].url.host, 'example.com:9201')
t.end()
})
t.test('publish_address as host/ip (IPv6)', t => {
const pool = new BaseConnectionPool({ Connection })
const nodes = {
a1: {
http: {
publish_address: 'example.com/[::1]:9200'
},
roles: ['master', 'data', 'ingest']
},
a2: {
http: {
publish_address: 'example.com/[::1]:9201'
},
roles: ['master', 'data', 'ingest']
}
}
t.deepEqual(pool.nodesToHost(nodes, 'http:'), [{
url: new URL('http://example.com:9200'),
id: 'a1',
roles: {
master: true,
data: true,
ingest: true,
ml: false
}
}, {
url: new URL('http://example.com:9201'),
id: 'a2',
roles: {
master: true,
data: true,
ingest: true,
ml: false
}
}])
t.strictEqual(pool.nodesToHost(nodes, 'http:')[0].url.host, 'example.com:9200')
t.strictEqual(pool.nodesToHost(nodes, 'http:')[1].url.host, 'example.com:9201')
t.end()
})
t.test('Should use the configure protocol', t => {
const pool = new BaseConnectionPool({ Connection })
const nodes = {
a1: {
http: {
publish_address: 'example.com/127.0.0.1:9200'
},
roles: ['master', 'data', 'ingest']
},
a2: {
http: {
publish_address: 'example.com/127.0.0.1:9201'
},
roles: ['master', 'data', 'ingest']
}
}
t.strictEqual(pool.nodesToHost(nodes, 'https:')[0].url.protocol, 'https:')
t.strictEqual(pool.nodesToHost(nodes, 'http:')[1].url.protocol, 'http:')
t.end()
})
t.end()
})
t.test('update', t => {
t.test('Should not update existing connections', t => {
t.plan(2)
const pool = new BaseConnectionPool({ Connection })
pool.addConnection([{
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: {
master: true,
data: true,
ingest: true
}
}, {
url: new URL('http://127.0.0.1:9201'),
id: 'a2',
roles: {
master: true,
data: true,
ingest: true
}
}])
pool.update([{
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: null
}, {
url: new URL('http://127.0.0.1:9201'),
id: 'a2',
roles: null
}])
t.ok(pool.connections.find(c => c.id === 'a1').roles !== null)
t.ok(pool.connections.find(c => c.id === 'a2').roles !== null)
})
t.test('Should not update existing connections (mark alive)', t => {
t.plan(5)
class CustomBaseConnectionPool extends BaseConnectionPool {
markAlive (connection) {
t.ok('called')
super.markAlive(connection)
}
}
const pool = new CustomBaseConnectionPool({ Connection })
const conn1 = pool.addConnection({
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: {
master: true,
data: true,
ingest: true
}
})
const conn2 = pool.addConnection({
url: new URL('http://127.0.0.1:9201'),
id: 'a2',
roles: {
master: true,
data: true,
ingest: true
}
})
pool.markDead(conn1)
pool.markDead(conn2)
pool.update([{
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: null
}, {
url: new URL('http://127.0.0.1:9201'),
id: 'a2',
roles: null
}])
t.ok(pool.connections.find(c => c.id === 'a1').roles !== null)
t.ok(pool.connections.find(c => c.id === 'a2').roles !== null)
})
t.test('Should not update existing connections (same url, different id)', t => {
t.plan(3)
class CustomBaseConnectionPool extends BaseConnectionPool {
markAlive (connection) {
t.ok('called')
super.markAlive(connection)
}
}
const pool = new CustomBaseConnectionPool({ Connection })
pool.addConnection([{
url: new URL('http://127.0.0.1:9200'),
id: 'http://127.0.0.1:9200/',
roles: {
master: true,
data: true,
ingest: true
}
}])
pool.update([{
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: true
}])
// roles will never be updated, we only use it to do
// a dummy check to see if the connection has been updated
t.deepEqual(pool.connections.find(c => c.id === 'a1').roles, {
master: true,
data: true,
ingest: true,
ml: false
})
t.strictEqual(pool.connections.find(c => c.id === 'http://127.0.0.1:9200/'), undefined)
})
t.test('Add a new connection', t => {
t.plan(2)
const pool = new BaseConnectionPool({ Connection })
pool.addConnection({
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: {
master: true,
data: true,
ingest: true
}
})
pool.update([{
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: null
}, {
url: new URL('http://127.0.0.1:9201'),
id: 'a2',
roles: null
}])
t.ok(pool.connections.find(c => c.id === 'a1').roles !== null)
t.ok(pool.connections.find(c => c.id === 'a2'))
})
t.test('Remove old connections', t => {
t.plan(3)
const pool = new BaseConnectionPool({ Connection })
pool.addConnection({
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: null
})
pool.update([{
url: new URL('http://127.0.0.1:9200'),
id: 'a2',
roles: null
}, {
url: new URL('http://127.0.0.1:9201'),
id: 'a3',
roles: null
}])
t.false(pool.connections.find(c => c.id === 'a1'))
t.true(pool.connections.find(c => c.id === 'a2'))
t.true(pool.connections.find(c => c.id === 'a3'))
})
t.end()
})
t.test('CreateConnection', t => {
t.plan(1)
const pool = new BaseConnectionPool({ Connection })
const conn = pool.createConnection('http://localhost:9200')
pool.connections.push(conn)
try {
pool.createConnection('http://localhost:9200')
t.fail('Should throw')
} catch (err) {
t.is(err.message, 'Connection with id \'http://localhost:9200/\' is already present')
}
})
t.end()
})

View File

@ -1,21 +1,6 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'

View File

@ -1,27 +1,13 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'
const { test } = require('tap')
const { URL } = require('url')
const { Client, ConnectionPool, Transport } = require('../../index')
const { CloudConnectionPool } = require('../../lib/pool')
const { buildServer } = require('../utils')
test('Configure host', t => {
@ -30,7 +16,7 @@ test('Configure host', t => {
node: 'http://localhost:9200'
})
const pool = client.connectionPool
t.match(pool.connections.get('http://localhost:9200/'), {
t.match(pool.connections.find(c => c.id === 'http://localhost:9200/'), {
url: new URL('http://localhost:9200'),
id: 'http://localhost:9200/',
ssl: null,
@ -51,7 +37,7 @@ test('Configure host', t => {
nodes: ['http://localhost:9200', 'http://localhost:9201']
})
const pool = client.connectionPool
t.match(pool.connections.get('http://localhost:9200/'), {
t.match(pool.connections.find(c => c.id === 'http://localhost:9200/'), {
url: new URL('http://localhost:9200'),
id: 'http://localhost:9200/',
ssl: null,
@ -64,7 +50,7 @@ test('Configure host', t => {
ml: false
}
})
t.match(pool.connections.get('http://localhost:9201/'), {
t.match(pool.connections.find(c => c.id === 'http://localhost:9201/'), {
url: new URL('http://localhost:9201'),
id: 'http://localhost:9201/',
ssl: null,
@ -95,7 +81,7 @@ test('Configure host', t => {
}
})
const pool = client.connectionPool
t.match(pool.connections.get('node'), {
t.match(pool.connections.find(c => c.id === 'node'), {
url: new URL('http://localhost:9200'),
id: 'node',
ssl: 'ssl',
@ -103,7 +89,7 @@ test('Configure host', t => {
resurrectTimeout: 0
})
t.deepEqual(pool.connections.get('node').roles, {
t.deepEqual(pool.connections.find(c => c.id === 'node').roles, {
master: true,
data: false,
ingest: false,
@ -136,7 +122,7 @@ test('Configure host', t => {
}]
})
const pool = client.connectionPool
t.match(pool.connections.get('node1'), {
t.match(pool.connections.find(c => c.id === 'node1'), {
url: new URL('http://localhost:9200'),
id: 'node1',
ssl: 'ssl',
@ -144,14 +130,14 @@ test('Configure host', t => {
resurrectTimeout: 0
})
t.deepEqual(pool.connections.get('node1').roles, {
t.deepEqual(pool.connections.find(c => c.id === 'node1').roles, {
master: true,
data: false,
ingest: false,
ml: false
})
t.match(pool.connections.get('node2'), {
t.match(pool.connections.find(c => c.id === 'node2'), {
url: new URL('http://localhost:9200'),
id: 'node2',
ssl: 'ssl',
@ -159,7 +145,7 @@ test('Configure host', t => {
resurrectTimeout: 0
})
t.deepEqual(pool.connections.get('node2').roles, {
t.deepEqual(pool.connections.find(c => c.id === 'node2').roles, {
master: false,
data: true,
ingest: false,
@ -178,7 +164,7 @@ test('Configure host', t => {
}
})
const pool = client.connectionPool
t.match(pool.connections.get('node'), {
t.match(pool.connections.find(c => c.id === 'node'), {
url: new URL('http://localhost:9200'),
headers: { 'x-foo': 'bar' }
})
@ -198,63 +184,293 @@ test('Configure host', t => {
t.end()
})
test('Node with auth data in the url', t => {
t.plan(3)
test('Authentication', t => {
t.test('Basic', t => {
t.test('Node with basic auth data in the url', t => {
t.plan(3)
function handler (req, res) {
t.match(req.headers, {
authorization: 'Basic Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://foo:bar@localhost:${port}`
})
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
test('Custom authentication per request', t => {
t.plan(6)
var first = true
function handler (req, res) {
t.match(req.headers, {
authorization: first ? 'hello' : 'Basic Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://foo:bar@localhost:${port}`
})
client.info({}, {
headers: {
authorization: 'hello'
function handler (req, res) {
t.match(req.headers, {
authorization: 'Basic Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
}, (err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
first = false
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://foo:bar@localhost:${port}`
})
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
t.test('Node with basic auth data in the url (array of nodes)', t => {
t.plan(3)
function handler (req, res) {
t.match(req.headers, {
authorization: 'Basic Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
nodes: [`http://foo:bar@localhost:${port}`]
})
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
t.test('Node with basic auth data in the options', t => {
t.plan(3)
function handler (req, res) {
t.match(req.headers, {
authorization: 'Basic Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://localhost:${port}`,
auth: {
username: 'foo',
password: 'bar'
}
})
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
t.test('Custom basic authentication per request', t => {
t.plan(6)
var first = true
function handler (req, res) {
t.match(req.headers, {
authorization: first ? 'hello' : 'Basic Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://foo:bar@localhost:${port}`
})
client.info({}, {
headers: {
authorization: 'hello'
}
}, (err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
first = false
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
})
t.test('Override default basic authentication per request', t => {
t.plan(6)
var first = true
function handler (req, res) {
t.match(req.headers, {
authorization: first ? 'hello' : 'Basic Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://localhost:${port}`,
auth: {
username: 'foo',
password: 'bar'
}
})
client.info({}, {
headers: {
authorization: 'hello'
}
}, (err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
first = false
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
})
t.end()
})
t.test('ApiKey', t => {
t.test('Node with ApiKey auth data in the options as string', t => {
t.plan(3)
function handler (req, res) {
t.match(req.headers, {
authorization: 'ApiKey Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://localhost:${port}`,
auth: {
apiKey: 'Zm9vOmJhcg=='
}
})
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
t.test('Node with ApiKey auth data in the options as object', t => {
t.plan(3)
function handler (req, res) {
t.match(req.headers, {
authorization: 'ApiKey Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://localhost:${port}`,
auth: {
apiKey: { id: 'foo', api_key: 'bar' }
}
})
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
t.test('Custom ApiKey authentication per request', t => {
t.plan(6)
var first = true
function handler (req, res) {
t.match(req.headers, {
authorization: first ? 'ApiKey Zm9vOmJhcg==' : 'Basic Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://foo:bar@localhost:${port}`
})
client.info({}, {
headers: {
authorization: 'ApiKey Zm9vOmJhcg=='
}
}, (err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
first = false
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
})
t.test('Override default ApiKey authentication per request', t => {
t.plan(6)
var first = true
function handler (req, res) {
t.match(req.headers, {
authorization: first ? 'hello' : 'ApiKey Zm9vOmJhcg=='
})
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
buildServer(handler, ({ port }, server) => {
const client = new Client({
node: `http://localhost:${port}`,
auth: {
apiKey: 'Zm9vOmJhcg=='
}
})
client.info({}, {
headers: {
authorization: 'hello'
}
}, (err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
first = false
client.info((err, { body }) => {
t.error(err)
t.deepEqual(body, { hello: 'world' })
server.stop()
})
})
})
})
t.end()
})
t.end()
})
test('Custom headers per request', t => {
@ -540,7 +756,7 @@ test('Extend client APIs', t => {
test('Elastic cloud config', t => {
t.test('Basic', t => {
t.plan(4)
t.plan(5)
const client = new Client({
cloud: {
// 'localhost$abcd$efgh'
@ -551,9 +767,50 @@ test('Elastic cloud config', t => {
})
const pool = client.connectionPool
t.match(pool.connections.get('https://abcd.localhost/'), {
t.ok(pool instanceof CloudConnectionPool)
t.match(pool.connections.find(c => c.id === 'https://abcd.localhost/'), {
url: new URL('https://elastic:changeme@abcd.localhost'),
id: 'https://abcd.localhost/',
headers: {
authorization: 'Basic ' + Buffer.from('elastic:changeme').toString('base64')
},
ssl: { secureProtocol: 'TLSv1_2_method' },
deadCount: 0,
resurrectTimeout: 0,
roles: {
master: true,
data: true,
ingest: true,
ml: false
}
})
t.strictEqual(client.transport.compression, 'gzip')
t.strictEqual(client.transport.suggestCompression, true)
t.deepEqual(pool._ssl, { secureProtocol: 'TLSv1_2_method' })
})
t.test('Auth as separate option', t => {
t.plan(5)
const client = new Client({
cloud: {
// 'localhost$abcd$efgh'
id: 'name:bG9jYWxob3N0JGFiY2QkZWZnaA=='
},
auth: {
username: 'elastic',
password: 'changeme'
}
})
const pool = client.connectionPool
t.ok(pool instanceof CloudConnectionPool)
t.match(pool.connections.find(c => c.id === 'https://abcd.localhost/'), {
url: new URL('https://elastic:changeme@abcd.localhost'),
id: 'https://abcd.localhost/',
headers: {
authorization: 'Basic ' + Buffer.from('elastic:changeme').toString('base64')
},
ssl: { secureProtocol: 'TLSv1_2_method' },
deadCount: 0,
resurrectTimeout: 0,
@ -571,7 +828,7 @@ test('Elastic cloud config', t => {
})
t.test('Override default options', t => {
t.plan(3)
t.plan(4)
const client = new Client({
cloud: {
// 'localhost$abcd$efgh'
@ -586,6 +843,7 @@ test('Elastic cloud config', t => {
}
})
t.ok(client.connectionPool instanceof CloudConnectionPool)
t.strictEqual(client.transport.compression, false)
t.strictEqual(client.transport.suggestCompression, false)
t.deepEqual(client.connectionPool._ssl, { secureProtocol: 'TLSv1_1_method' })

View File

@ -0,0 +1,33 @@
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'
const { test } = require('tap')
const { CloudConnectionPool } = require('../../lib/pool')
const Connection = require('../../lib/Connection')
test('Should expose a cloudConnection property', t => {
const pool = new CloudConnectionPool({ Connection })
pool.addConnection('http://localhost:9200/')
t.ok(pool.cloudConnection instanceof Connection)
t.end()
})
test('Get connection should always return cloudConnection', t => {
const pool = new CloudConnectionPool({ Connection })
const conn = pool.addConnection('http://localhost:9200/')
t.deepEqual(pool.getConnection(), conn)
t.end()
})
test('pool.empty should reset cloudConnection', t => {
const pool = new CloudConnectionPool({ Connection })
pool.addConnection('http://localhost:9200/')
t.ok(pool.cloudConnection instanceof Connection)
pool.empty(() => {
t.strictEqual(pool.cloudConnection, null)
t.end()
})
})

View File

@ -1,27 +1,12 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'
const { test } = require('tap')
const { URL } = require('url')
const ConnectionPool = require('../../lib/ConnectionPool')
const ConnectionPool = require('../../lib/pool/ConnectionPool')
const Connection = require('../../lib/Connection')
const { defaultNodeFilter, roundRobinSelector } = require('../../lib/Transport').internals
const { connection: { MockConnection, MockConnectionTimeout } } = require('../utils')
@ -31,8 +16,8 @@ test('API', t => {
const pool = new ConnectionPool({ Connection })
const href = 'http://localhost:9200/'
pool.addConnection(href)
t.ok(pool.connections.get(href) instanceof Connection)
t.strictEqual(pool.connections.get(href).status, Connection.statuses.ALIVE)
t.ok(pool.connections.find(c => c.id === href) instanceof Connection)
t.strictEqual(pool.connections.find(c => c.id === href).status, Connection.statuses.ALIVE)
t.deepEqual(pool.dead, [])
t.end()
})
@ -50,25 +35,6 @@ test('API', t => {
t.end()
})
t.test('addConnection (should store the auth data)', t => {
const pool = new ConnectionPool({ Connection })
const href = 'http://localhost:9200/'
pool.addConnection('http://foo:bar@localhost:9200')
t.ok(pool.connections.get(href) instanceof Connection)
t.strictEqual(pool.connections.get(href).status, Connection.statuses.ALIVE)
t.deepEqual(pool.dead, [])
t.deepEqual(pool._auth, { username: 'foo', password: 'bar' })
pool.addConnection('http://localhost:9201')
const conn = pool.connections.get('http://localhost:9201/')
t.strictEqual(conn.url.username, 'foo')
t.strictEqual(conn.url.password, 'bar')
t.strictEqual(conn.auth.username, 'foo')
t.strictEqual(conn.auth.password, 'bar')
t.end()
})
t.test('addConnection should handle not-friendly url parameters for user and password', t => {
const pool = new ConnectionPool({ Connection })
const href = 'http://us"er:p@assword@localhost:9200/'
@ -76,8 +42,9 @@ test('API', t => {
const conn = pool.getConnection()
t.strictEqual(conn.url.username, 'us%22er')
t.strictEqual(conn.url.password, 'p%40assword')
t.strictEqual(conn.auth.username, 'us"er')
t.strictEqual(conn.auth.password, 'p@assword')
t.match(conn.headers, {
authorization: 'Basic ' + Buffer.from('us"er:p@assword').toString('base64')
})
t.end()
})
@ -86,7 +53,7 @@ test('API', t => {
const href = 'http://localhost:9200/'
var connection = pool.addConnection(href)
pool.markDead(connection)
connection = pool.connections.get(href)
connection = pool.connections.find(c => c.id === href)
t.strictEqual(connection.deadCount, 1)
t.true(connection.resurrectTimeout > 0)
t.deepEqual(pool.dead, [href])
@ -113,7 +80,7 @@ test('API', t => {
var connection = pool.addConnection(href)
pool.markDead(connection)
pool.markAlive(connection)
connection = pool.connections.get(href)
connection = pool.connections.find(c => c.id === href)
t.strictEqual(connection.deadCount, 0)
t.strictEqual(connection.resurrectTimeout, 0)
t.strictEqual(connection.status, Connection.statuses.ALIVE)
@ -140,7 +107,7 @@ test('API', t => {
}
pool.resurrect(opts, (isAlive, connection) => {
t.true(isAlive)
connection = pool.connections.get(connection.id)
connection = pool.connections.find(c => c.id === connection.id)
t.strictEqual(connection.deadCount, 0)
t.strictEqual(connection.resurrectTimeout, 0)
t.strictEqual(connection.status, Connection.statuses.ALIVE)
@ -166,7 +133,7 @@ test('API', t => {
}
pool.resurrect(opts, (isAlive, connection) => {
t.false(isAlive)
connection = pool.connections.get(connection.id)
connection = pool.connections.find(c => c.id === connection.id)
t.strictEqual(connection.deadCount, 2)
t.true(connection.resurrectTimeout > 0)
t.strictEqual(connection.status, Connection.statuses.DEAD)
@ -194,7 +161,7 @@ test('API', t => {
}
pool.resurrect(opts, (isAlive, connection) => {
t.true(isAlive)
connection = pool.connections.get(connection.id)
connection = pool.connections.find(c => c.id === connection.id)
t.strictEqual(connection.deadCount, 1)
t.true(connection.resurrectTimeout > 0)
t.strictEqual(connection.status, Connection.statuses.ALIVE)
@ -220,7 +187,7 @@ test('API', t => {
pool.resurrect(opts, (isAlive, connection) => {
t.ok(isAlive === null)
t.ok(connection === null)
connection = pool.connections.get(href)
connection = pool.connections.find(c => c.id === href)
t.strictEqual(connection.deadCount, 1)
t.true(connection.resurrectTimeout > 0)
t.strictEqual(connection.status, Connection.statuses.DEAD)
@ -300,7 +267,7 @@ test('API', t => {
pool.addConnection('http://localhost:9200/')
pool.addConnection('http://localhost:9201/')
pool.empty(() => {
t.strictEqual(pool.connections.size, 0)
t.strictEqual(pool.size, 0)
t.deepEqual(pool.dead, [])
t.end()
})
@ -513,12 +480,7 @@ test('API', t => {
t.test('update', t => {
t.test('Should not update existing connections', t => {
t.plan(2)
class CustomConnectionPool extends ConnectionPool {
markAlive () {
t.fail('Should not be called')
}
}
const pool = new CustomConnectionPool({ Connection })
const pool = new ConnectionPool({ Connection })
pool.addConnection([{
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
@ -547,12 +509,12 @@ test('API', t => {
roles: null
}])
t.ok(pool.connections.get('a1').roles !== null)
t.ok(pool.connections.get('a2').roles !== null)
t.ok(pool.connections.find(c => c.id === 'a1').roles !== null)
t.ok(pool.connections.find(c => c.id === 'a2').roles !== null)
})
t.test('Should not update existing connections (mark alive)', t => {
t.plan(4)
t.plan(5)
class CustomConnectionPool extends ConnectionPool {
markAlive (connection) {
t.ok('called')
@ -593,15 +555,16 @@ test('API', t => {
roles: null
}])
t.ok(pool.connections.get('a1').roles !== null)
t.ok(pool.connections.get('a2').roles !== null)
t.ok(pool.connections.find(c => c.id === 'a1').roles !== null)
t.ok(pool.connections.find(c => c.id === 'a2').roles !== null)
})
t.test('Should not update existing connections (same url, different id)', t => {
t.plan(2)
t.plan(3)
class CustomConnectionPool extends ConnectionPool {
markAlive () {
t.fail('Should not be called')
markAlive (connection) {
t.ok('called')
super.markAlive(connection)
}
}
const pool = new CustomConnectionPool({ Connection })
@ -623,13 +586,13 @@ test('API', t => {
// roles will never be updated, we only use it to do
// a dummy check to see if the connection has been updated
t.deepEqual(pool.connections.get('a1').roles, {
t.deepEqual(pool.connections.find(c => c.id === 'a1').roles, {
master: true,
data: true,
ingest: true,
ml: false
})
t.strictEqual(pool.connections.get('http://127.0.0.1:9200/'), undefined)
t.strictEqual(pool.connections.find(c => c.id === 'http://127.0.0.1:9200/'), undefined)
})
t.test('Add a new connection', t => {
@ -655,8 +618,8 @@ test('API', t => {
roles: null
}])
t.ok(pool.connections.get('a1').roles !== null)
t.true(pool.connections.has('a2'))
t.ok(pool.connections.find(c => c.id === 'a1').roles !== null)
t.ok(pool.connections.find(c => c.id === 'a2'))
})
t.test('Remove old connections', t => {
@ -678,9 +641,37 @@ test('API', t => {
roles: null
}])
t.false(pool.connections.has('a1'))
t.true(pool.connections.has('a2'))
t.true(pool.connections.has('a3'))
t.false(pool.connections.find(c => c.id === 'a1'))
t.true(pool.connections.find(c => c.id === 'a2'))
t.true(pool.connections.find(c => c.id === 'a3'))
})
t.test('Remove old connections (markDead)', t => {
t.plan(5)
const pool = new ConnectionPool({ Connection, sniffEnabled: true })
const conn = pool.addConnection({
url: new URL('http://127.0.0.1:9200'),
id: 'a1',
roles: null
})
pool.markDead(conn)
t.deepEqual(pool.dead, ['a1'])
pool.update([{
url: new URL('http://127.0.0.1:9200'),
id: 'a2',
roles: null
}, {
url: new URL('http://127.0.0.1:9201'),
id: 'a3',
roles: null
}])
t.deepEqual(pool.dead, [])
t.false(pool.connections.find(c => c.id === 'a1'))
t.true(pool.connections.find(c => c.id === 'a2'))
t.true(pool.connections.find(c => c.id === 'a3'))
})
t.end()
@ -735,22 +726,22 @@ test('Node filter', t => {
test('Single node behavior', t => {
t.test('sniffing disabled (markDead and markAlive should be noop)', t => {
t.plan(2)
t.plan(4)
const pool = new ConnectionPool({ Connection, sniffEnabled: false })
const conn = pool.addConnection('http://localhost:9200/')
pool.markDead(conn)
t.true(pool.markDead(conn) instanceof ConnectionPool)
t.strictEqual(pool.dead.length, 0)
pool.markAlive(conn)
t.true(pool.markAlive(conn) instanceof ConnectionPool)
t.strictEqual(pool.dead.length, 0)
})
t.test('sniffing enabled (markDead and markAlive should work)', t => {
t.plan(2)
t.plan(4)
const pool = new ConnectionPool({ Connection, sniffEnabled: true })
const conn = pool.addConnection('http://localhost:9200/')
pool.markDead(conn)
t.true(pool.markDead(conn) instanceof ConnectionPool)
t.strictEqual(pool.dead.length, 1)
pool.markAlive(conn)
t.true(pool.markAlive(conn) instanceof ConnectionPool)
t.strictEqual(pool.dead.length, 0)
})

View File

@ -1,21 +1,6 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'
@ -748,7 +733,7 @@ test('Util.inspect Connection class should hide agent, ssl and auth', t => {
resurrectTimeout: 0,
_openRequests: 0,
status: 'alive',
roles: { master: true, data: true, ingest: true, ml: false } }`)
roles: { master: true, data: true, ingest: true, ml: false }}`)
)
})
@ -811,6 +796,53 @@ test('Port handling', t => {
t.end()
})
test('Authorization header', t => {
t.test('None', t => {
const connection = new Connection({
url: new URL('http://localhost:9200')
})
t.deepEqual(connection.headers, {})
t.end()
})
t.test('Basic', t => {
const connection = new Connection({
url: new URL('http://localhost:9200'),
auth: { username: 'foo', password: 'bar' }
})
t.deepEqual(connection.headers, { authorization: 'Basic Zm9vOmJhcg==' })
t.end()
})
t.test('ApiKey (string)', t => {
const connection = new Connection({
url: new URL('http://localhost:9200'),
auth: { apiKey: 'Zm9vOmJhcg==' }
})
t.deepEqual(connection.headers, { authorization: 'ApiKey Zm9vOmJhcg==' })
t.end()
})
t.test('ApiKey (object)', t => {
const connection = new Connection({
url: new URL('http://localhost:9200'),
auth: { apiKey: { id: 'foo', api_key: 'bar' } }
})
t.deepEqual(connection.headers, { authorization: 'ApiKey Zm9vOmJhcg==' })
t.end()
})
t.end()
})
test('Should not add agent and ssl to the serialized connection', t => {
const connection = new Connection({
url: new URL('http://localhost:9200')
@ -818,7 +850,7 @@ test('Should not add agent and ssl to the serialized connection', t => {
t.strictEqual(
JSON.stringify(connection),
'{"url":"http://localhost:9200/","id":"http://localhost:9200/","headers":null,"deadCount":0,"resurrectTimeout":0,"_openRequests":0,"status":"alive","roles":{"master":true,"data":true,"ingest":true,"ml":false}}'
'{"url":"http://localhost:9200/","id":"http://localhost:9200/","headers":{},"deadCount":0,"resurrectTimeout":0,"_openRequests":0,"status":"alive","roles":{"master":true,"data":true,"ingest":true,"ml":false}}'
)
t.end()

View File

@ -1,21 +1,6 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'

View File

@ -1,21 +1,6 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'
@ -45,7 +30,7 @@ test('Should emit a request event when a request is performed', t => {
request: {
params: {
method: 'GET',
path: '/test/doc/_search',
path: '/test/_search',
body: '',
querystring: 'q=foo%3Abar',
headers: {
@ -67,7 +52,6 @@ test('Should emit a request event when a request is performed', t => {
client.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
}, (err, result) => {
t.error(err)
@ -98,7 +82,7 @@ test('Should emit a response event in case of a successful response', t => {
request: {
params: {
method: 'GET',
path: '/test/doc/_search',
path: '/test/_search',
body: '',
querystring: 'q=foo%3Abar',
headers: {
@ -120,7 +104,6 @@ test('Should emit a response event in case of a successful response', t => {
client.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
}, (err, result) => {
t.error(err)
@ -149,7 +132,7 @@ test('Should emit a response event with the error set', t => {
request: {
params: {
method: 'GET',
path: '/test/doc/_search',
path: '/test/_search',
body: '',
querystring: 'q=foo%3Abar',
headers: {
@ -173,7 +156,6 @@ test('Should emit a response event with the error set', t => {
client.search({
index: 'test',
type: 'doc',
q: 'foo:bar'
}, {
requestTimeout: 500

View File

@ -1,21 +1,6 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'

View File

@ -1,21 +1,6 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'

View File

@ -1,26 +1,12 @@
/*
* 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.
*/
// Licensed to Elasticsearch B.V under one or more agreements.
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information
'use strict'
const { test } = require('tap')
const { URL } = require('url')
const lolex = require('lolex')
const { createGunzip } = require('zlib')
const os = require('os')
const intoStream = require('into-stream')
@ -38,7 +24,7 @@ const {
ConfigurationError
} = require('../../lib/errors')
const ConnectionPool = require('../../lib/ConnectionPool')
const ConnectionPool = require('../../lib/pool/ConnectionPool')
const Connection = require('../../lib/Connection')
const Serializer = require('../../lib/Serializer')
const Transport = require('../../lib/Transport')
@ -893,148 +879,95 @@ test('Override requestTimeout', t => {
test('sniff', t => {
t.test('sniffOnStart', t => {
t.plan(3)
t.plan(1)
class CustomConnectionPool extends ConnectionPool {
update () {
t.ok('called')
return this
}
nodesToHost (nodes) {
t.ok('called')
return []
class MyTransport extends Transport {
sniff (opts) {
t.strictEqual(opts.reason, Transport.sniffReasons.SNIFF_ON_START)
}
}
function handler (req, res) {
t.strictEqual(req.url, '/sniff')
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
const pool = new ConnectionPool({ Connection })
pool.addConnection('http://localhost:9200')
buildServer(handler, ({ port }, server) => {
const pool = new CustomConnectionPool({ Connection })
pool.addConnection(`http://localhost:${port}`)
// eslint-disable-next-line
new Transport({
emit: () => {},
connectionPool: pool,
serializer: new Serializer(),
maxRetries: 3,
requestTimeout: 30000,
sniffInterval: false,
sniffOnStart: true,
sniffEndpoint: '/sniff'
})
setTimeout(() => server.stop(), 100)
// eslint-disable-next-line
new MyTransport({
emit: () => {},
connectionPool: pool,
serializer: new Serializer(),
maxRetries: 3,
requestTimeout: 30000,
sniffInterval: false,
sniffOnStart: true,
sniffEndpoint: '/sniff'
})
})
t.test('sniffOnConnectionFault', t => {
t.plan(3)
t.plan(2)
class CustomConnectionPool extends ConnectionPool {
update () {
t.ok('called')
return this
}
nodesToHost (nodes) {
t.ok('called')
return []
class MyTransport extends Transport {
sniff (opts) {
t.strictEqual(opts.reason, Transport.sniffReasons.SNIFF_ON_CONNECTION_FAULT)
}
}
function handler (req, res) {
if (req.url === '/other/sniff') {
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
} else {
setTimeout(() => res.end(), 1000)
}
}
const pool = new ConnectionPool({ Connection: MockConnectionTimeout })
pool.addConnection('http://localhost:9200')
buildServer(handler, ({ port }, server) => {
const pool = new CustomConnectionPool({ Connection })
pool.addConnection(`http://localhost:${port}`)
pool.addConnection(`http://localhost:${port}/other`)
const transport = new MyTransport({
emit: () => {},
connectionPool: pool,
serializer: new Serializer(),
maxRetries: 0,
requestTimeout: 500,
sniffInterval: false,
sniffOnConnectionFault: true,
sniffEndpoint: '/sniff'
})
const transport = new Transport({
emit: () => {},
connectionPool: pool,
serializer: new Serializer(),
maxRetries: 0,
requestTimeout: 500,
sniffInterval: false,
sniffOnConnectionFault: true,
sniffEndpoint: '/sniff'
})
transport.request({
method: 'GET',
path: '/'
}, (err, { body }) => {
t.ok(err instanceof TimeoutError)
})
setTimeout(() => server.stop(), 1100)
transport.request({
method: 'GET',
path: '/'
}, (err, { body }) => {
t.ok(err instanceof TimeoutError)
})
})
t.test('sniffInterval', t => {
t.plan(9)
t.plan(6)
class CustomConnectionPool extends ConnectionPool {
update () {
return this
}
const clock = lolex.install({ toFake: ['Date'] })
t.teardown(() => clock.uninstall())
nodesToHost (nodes) {
return []
class MyTransport extends Transport {
sniff (opts) {
t.strictEqual(opts.reason, Transport.sniffReasons.SNIFF_INTERVAL)
}
}
function handler (req, res) {
// this should be called 6 times
t.ok('called')
res.setHeader('Content-Type', 'application/json;utf=8')
res.end(JSON.stringify({ hello: 'world' }))
}
const pool = new ConnectionPool({ Connection: MockConnection })
pool.addConnection('http://localhost:9200')
buildServer(handler, ({ port }, server) => {
const pool = new CustomConnectionPool({ Connection })
pool.addConnection(`http://localhost:${port}`)
const transport = new Transport({
emit: () => {},
connectionPool: pool,
serializer: new Serializer(),
maxRetries: 3,
requestTimeout: 3000,
sniffInterval: 1,
sniffEndpoint: '/sniff'
})
const params = { method: 'GET', path: '/' }
setTimeout(() => {
transport.request(params, t.error)
}, 100)
setTimeout(() => {
transport.request(params, t.error)
}, 200)
setTimeout(() => {
transport.request(params, t.error)
}, 300)
setTimeout(() => {
server.stop()
}, 400)
const transport = new MyTransport({
emit: () => {},
connectionPool: pool,
serializer: new Serializer(),
maxRetries: 3,
requestTimeout: 3000,
sniffInterval: 1,
sniffEndpoint: '/sniff'
})
const params = { method: 'GET', path: '/' }
clock.tick(100)
transport.request(params, t.error)
clock.tick(200)
transport.request(params, t.error)
clock.tick(300)
transport.request(params, t.error)
})
t.test('errored', t => {