Elasticsearch v8 (#1558)
This commit is contained in:
committed by
GitHub
parent
4c72b981cd
commit
1a227459f0
434
test/unit/client.test.ts
Normal file
434
test/unit/client.test.ts
Normal file
@ -0,0 +1,434 @@
|
||||
/*
|
||||
* 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 { test } from 'tap'
|
||||
import { URL } from 'url'
|
||||
import { connection } from '../utils'
|
||||
import { Client, errors } from '../..'
|
||||
import * as symbols from '@elastic/transport/lib/symbols'
|
||||
import { BaseConnectionPool, CloudConnectionPool, WeightedConnectionPool } from '@elastic/transport'
|
||||
|
||||
let clientVersion: string = require('../../package.json').version // eslint-disable-line
|
||||
if (clientVersion.includes('-')) {
|
||||
clientVersion = clientVersion.slice(0, clientVersion.indexOf('-')) + 'p'
|
||||
}
|
||||
let transportVersion: string = require('@elastic/transport/package.json').version // eslint-disable-line
|
||||
if (transportVersion.includes('-')) {
|
||||
transportVersion = transportVersion.slice(0, transportVersion.indexOf('-')) + 'p'
|
||||
}
|
||||
const nodeVersion = process.versions.node
|
||||
|
||||
test('Create a client instance, single node as string', t => {
|
||||
const client = new Client({ node: 'http://localhost:9200' })
|
||||
t.ok(client.connectionPool instanceof WeightedConnectionPool)
|
||||
t.equal(client.connectionPool.size, 1)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Create a client instance, multi node as strings', t => {
|
||||
const client = new Client({ nodes: ['http://localhost:9200', 'http://localhost:9201'] })
|
||||
t.ok(client.connectionPool instanceof WeightedConnectionPool)
|
||||
t.equal(client.connectionPool.size, 2)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Create a client instance, single node as object', t => {
|
||||
const client = new Client({
|
||||
node: {
|
||||
url: new URL('http://localhost:9200')
|
||||
}
|
||||
})
|
||||
t.equal(client.connectionPool.size, 1)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Create a client instance, multi node as object', t => {
|
||||
const client = new Client({
|
||||
nodes: [{
|
||||
url: new URL('http://localhost:9200')
|
||||
}, {
|
||||
url: new URL('http://localhost:9201')
|
||||
}]
|
||||
})
|
||||
t.equal(client.connectionPool.size, 2)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Missing node(s)', t => {
|
||||
t.throws(() => new Client({}), errors.ConfigurationError)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Custom headers', t => {
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
headers: { foo: 'bar' }
|
||||
})
|
||||
t.match(client.transport[symbols.kHeaders], { foo: 'bar' })
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Basic auth', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const Connection = connection.buildMockConnection({
|
||||
onRequest (opts) {
|
||||
t.match(opts.headers, { authorization: 'Basic aGVsbG86d29ybGQ=' })
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: { hello: 'world' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection,
|
||||
auth: {
|
||||
username: 'hello',
|
||||
password: 'world'
|
||||
}
|
||||
})
|
||||
|
||||
await client.transport.request({ method: 'GET', path: '/' })
|
||||
})
|
||||
|
||||
test('Basic auth via url', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const Connection = connection.buildMockConnection({
|
||||
onRequest (opts) {
|
||||
t.match(opts.headers, { authorization: 'Basic aGVsbG86d29ybGQ=' })
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: { hello: 'world' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://hello:world@localhost:9200',
|
||||
Connection
|
||||
})
|
||||
|
||||
await client.transport.request({ method: 'GET', path: '/' })
|
||||
})
|
||||
|
||||
test('ApiKey as string', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const Connection = connection.buildMockConnection({
|
||||
onRequest (opts) {
|
||||
t.match(opts.headers, { authorization: 'ApiKey foobar' })
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: { hello: 'world' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection,
|
||||
auth: {
|
||||
apiKey: 'foobar'
|
||||
}
|
||||
})
|
||||
|
||||
await client.transport.request({ method: 'GET', path: '/' })
|
||||
})
|
||||
|
||||
test('ApiKey as object', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const Connection = connection.buildMockConnection({
|
||||
onRequest (opts) {
|
||||
t.match(opts.headers, { authorization: 'ApiKey Zm9vOmJhcg==' })
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: { hello: 'world' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection,
|
||||
auth: {
|
||||
apiKey: {
|
||||
id: 'foo',
|
||||
api_key: 'bar'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await client.transport.request({ method: 'GET', path: '/' })
|
||||
})
|
||||
|
||||
test('Bearer auth', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const Connection = connection.buildMockConnection({
|
||||
onRequest (opts) {
|
||||
t.match(opts.headers, { authorization: 'Bearer token' })
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: { hello: 'world' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection,
|
||||
auth: {
|
||||
bearer: 'token'
|
||||
}
|
||||
})
|
||||
|
||||
await client.transport.request({ method: 'GET', path: '/' })
|
||||
})
|
||||
|
||||
test('Override authentication per request', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const Connection = connection.buildMockConnection({
|
||||
onRequest (opts) {
|
||||
t.match(opts.headers, { authorization: 'Basic foobar' })
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: { hello: 'world' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection,
|
||||
auth: {
|
||||
username: 'hello',
|
||||
password: 'world'
|
||||
}
|
||||
})
|
||||
|
||||
await client.transport.request(
|
||||
{ method: 'GET', path: '/' },
|
||||
{ headers: { authorization: 'Basic foobar' } }
|
||||
)
|
||||
})
|
||||
|
||||
test('Custom headers per request', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const Connection = connection.buildMockConnection({
|
||||
onRequest (opts) {
|
||||
t.match(opts.headers, {
|
||||
foo: 'bar',
|
||||
faz: 'bar'
|
||||
})
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: { hello: 'world' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection,
|
||||
headers: { foo: 'bar' }
|
||||
})
|
||||
|
||||
await client.transport.request(
|
||||
{ method: 'GET', path: '/' },
|
||||
{ headers: { faz: 'bar' } }
|
||||
)
|
||||
})
|
||||
|
||||
test('Close the client', async t => {
|
||||
t.plan(1)
|
||||
|
||||
class MyConnectionPool extends BaseConnectionPool {
|
||||
async empty (): Promise<void> {
|
||||
t.pass('called')
|
||||
}
|
||||
}
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
ConnectionPool: MyConnectionPool
|
||||
})
|
||||
|
||||
await client.close()
|
||||
})
|
||||
|
||||
test('Elastic Cloud config', t => {
|
||||
const client = new Client({
|
||||
cloud: {
|
||||
// 'localhost$abcd$'
|
||||
id: 'name:bG9jYWxob3N0JGFiY2Qk'
|
||||
},
|
||||
auth: {
|
||||
username: 'elastic',
|
||||
password: 'changeme'
|
||||
}
|
||||
})
|
||||
|
||||
t.ok(client.connectionPool instanceof CloudConnectionPool)
|
||||
t.match(client.connectionPool.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')
|
||||
},
|
||||
tls: { secureProtocol: 'TLSv1_2_method' }
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Override default Elastic Cloud options', t => {
|
||||
const client = new Client({
|
||||
cloud: {
|
||||
// 'localhost$abcd$efgh'
|
||||
id: 'name:bG9jYWxob3N0JGFiY2QkZWZnaA==',
|
||||
},
|
||||
auth: {
|
||||
username: 'elastic',
|
||||
password: 'changeme'
|
||||
},
|
||||
compression: false,
|
||||
tls: {
|
||||
secureProtocol: 'TLSv1_1_method'
|
||||
}
|
||||
})
|
||||
|
||||
t.ok(client.connectionPool instanceof CloudConnectionPool)
|
||||
t.equal(client.transport[symbols.kCompression], false)
|
||||
t.same(client.connectionPool._tls, { secureProtocol: 'TLSv1_1_method' })
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Configure opaqueIdPrefix', t => {
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
opaqueIdPrefix: 'foobar'
|
||||
})
|
||||
|
||||
t.equal(client.transport[symbols.kOpaqueIdPrefix], 'foobar')
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('name as string', t => {
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
name: 'es-client'
|
||||
})
|
||||
|
||||
t.equal(client.name, 'es-client')
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('name as symbol', t => {
|
||||
const s = Symbol()
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
name: s
|
||||
})
|
||||
|
||||
t.equal(client.name, s)
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Meta header enabled by default', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const Connection = connection.buildMockConnection({
|
||||
onRequest (opts) {
|
||||
t.match(opts.headers, { 'x-elastic-client-meta': `es=${clientVersion},js=${nodeVersion},t=${transportVersion},hc=${nodeVersion}` })
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: { hello: 'world' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection
|
||||
})
|
||||
|
||||
await client.transport.request({ method: 'GET', path: '/' })
|
||||
})
|
||||
|
||||
test('Meta header disabled', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const Connection = connection.buildMockConnection({
|
||||
onRequest (opts) {
|
||||
t.notOk(opts.headers?.['x-elastic-client-meta'])
|
||||
return {
|
||||
statusCode: 200,
|
||||
body: { hello: 'world' }
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const client = new Client({
|
||||
node: 'http://localhost:9200',
|
||||
Connection,
|
||||
enableMetaHeader: false
|
||||
})
|
||||
|
||||
await client.transport.request({ method: 'GET', path: '/' })
|
||||
})
|
||||
|
||||
test('caFingerprint', t => {
|
||||
const client = new Client({
|
||||
node: 'https://localhost:9200',
|
||||
caFingerprint: 'FO:OB:AR'
|
||||
})
|
||||
|
||||
t.equal(client.connectionPool[symbols.kCaFingerprint], 'FO:OB:AR')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('caFingerprint can\'t be configured over http / 1', t => {
|
||||
t.throws(() => new Client({
|
||||
node: 'http://localhost:9200',
|
||||
caFingerprint: 'FO:OB:AR'
|
||||
}),
|
||||
errors.ConfigurationError
|
||||
)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('caFingerprint can\'t be configured over http / 2', t => {
|
||||
t.throws(() => new Client({
|
||||
nodes: ['http://localhost:9200'],
|
||||
caFingerprint: 'FO:OB:AR'
|
||||
}),
|
||||
errors.ConfigurationError
|
||||
)
|
||||
t.end()
|
||||
})
|
||||
Reference in New Issue
Block a user