text: /*
   * 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.
   */
  
  'use strict'
  
  const { test } = require('tap')
  const intoStream = require('into-stream')
  const { Connection, events } = require('../../index')
  const {
    TimeoutError,
    ConnectionError,
    ResponseError,
    RequestAbortedError,
    SerializationError,
    DeserializationError
  } = require('../../lib/errors')
  const {
    Client,
    buildServer,
    connection: {
      MockConnection,
      MockConnectionError,
      MockConnectionTimeout,
      buildMockConnection
    }
  } = require('../utils')
  
  test('No errors', t => {
    t.plan(10)
  
    const client = new Client({
      node: 'http://localhost:9200',
      Connection: MockConnection
    })
  
    const order = [
      events.SERIALIZATION,
      events.REQUEST,
      events.DESERIALIZATION,
      events.RESPONSE
    ]
  
    client.on(events.SERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.SERIALIZATION)
    })
  
    client.on(events.REQUEST, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.REQUEST)
    })
  
    client.on(events.DESERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.DESERIALIZATION)
    })
  
    client.on(events.RESPONSE, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.RESPONSE)
    })
  
    client.info((err, result) => {
      t.error(err)
      t.equal(order.length, 0)
    })
  })
  
  test('Connection error', t => {
    t.plan(10)
  
    const client = new Client({
      node: 'http://localhost:9200',
      Connection: MockConnectionError,
      maxRetries: 1
    })
  
    const order = [
      events.SERIALIZATION,
      events.REQUEST,
      events.REQUEST,
      events.RESPONSE
    ]
  
    client.on(events.SERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.SERIALIZATION)
    })
  
    client.on(events.REQUEST, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.REQUEST)
    })
  
    client.on(events.DESERIALIZATION, (_err, request) => {
      t.fail('Should not be called')
    })
  
    client.on(events.RESPONSE, (err, request) => {
      t.ok(err instanceof ConnectionError)
      t.equal(order.shift(), events.RESPONSE)
    })
  
    client.info((err, result) => {
      t.ok(err instanceof ConnectionError)
      t.equal(order.length, 0)
    })
  })
  
  test('TimeoutError error', t => {
    t.plan(10)
  
    const client = new Client({
      node: 'http://localhost:9200',
      Connection: MockConnectionTimeout,
      maxRetries: 1
    })
  
    const order = [
      events.SERIALIZATION,
      events.REQUEST,
      events.REQUEST,
      events.RESPONSE
    ]
  
    client.on(events.SERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.SERIALIZATION)
    })
  
    client.on(events.REQUEST, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.REQUEST)
    })
  
    client.on(events.DESERIALIZATION, (_err, request) => {
      t.fail('Should not be called')
    })
  
    client.on(events.RESPONSE, (err, request) => {
      t.ok(err instanceof TimeoutError)
      t.equal(order.shift(), events.RESPONSE)
    })
  
    client.info((err, result) => {
      t.ok(err instanceof TimeoutError)
      t.equal(order.length, 0)
    })
  })
  
  test('RequestAbortedError error', t => {
    t.plan(8)
  
    const client = new Client({
      node: 'http://localhost:9200',
      Connection: MockConnectionTimeout,
      maxRetries: 1
    })
  
    const order = [
      events.SERIALIZATION,
      events.REQUEST,
      events.RESPONSE
    ]
  
    client.on(events.SERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.SERIALIZATION)
    })
  
    client.on(events.REQUEST, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.REQUEST)
    })
  
    client.on(events.DESERIALIZATION, (_err, request) => {
      t.fail('Should not be called')
    })
  
    client.on(events.RESPONSE, (err, request) => {
      t.ok(err instanceof RequestAbortedError)
      t.equal(order.shift(), events.RESPONSE)
    })
  
    const request = client.info((err, result) => {
      t.ok(err instanceof RequestAbortedError)
      t.equal(order.length, 0)
    })
  
    request.abort()
  })
  
  test('ResponseError error (no retry)', t => {
    t.plan(10)
  
    const MockConnection = buildMockConnection({
      onRequest (params) {
        return {
          statusCode: 400,
          body: { hello: 'world' }
        }
      }
    })
  
    const client = new Client({
      node: 'http://localhost:9200',
      Connection: MockConnection,
      maxRetries: 1
    })
  
    const order = [
      events.SERIALIZATION,
      events.REQUEST,
      events.DESERIALIZATION,
      events.RESPONSE
    ]
  
    client.on(events.SERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.SERIALIZATION)
    })
  
    client.on(events.REQUEST, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.REQUEST)
    })
  
    client.on(events.DESERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.DESERIALIZATION)
    })
  
    client.on(events.RESPONSE, (err, request) => {
      t.ok(err instanceof ResponseError)
      t.equal(order.shift(), events.RESPONSE)
    })
  
    client.info((err, result) => {
      t.ok(err instanceof ResponseError)
      t.equal(order.length, 0)
    })
  })
  
  test('ResponseError error (with retry)', t => {
    t.plan(14)
  
    const MockConnection = buildMockConnection({
      onRequest (params) {
        return {
          statusCode: 504,
          body: { hello: 'world' }
        }
      }
    })
  
    const client = new Client({
      node: 'http://localhost:9200',
      Connection: MockConnection,
      maxRetries: 1
    })
  
    const order = [
      events.SERIALIZATION,
      events.REQUEST,
      events.DESERIALIZATION,
      events.REQUEST,
      events.DESERIALIZATION,
      events.RESPONSE
    ]
  
    client.on(events.SERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.SERIALIZATION)
    })
  
    client.on(events.REQUEST, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.REQUEST)
    })
  
    client.on(events.DESERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.DESERIALIZATION)
    })
  
    client.on(events.RESPONSE, (err, request) => {
      t.ok(err instanceof ResponseError)
      t.equal(order.shift(), events.RESPONSE)
    })
  
    client.info((err, result) => {
      t.ok(err instanceof ResponseError)
      t.equal(order.length, 0)
    })
  })
  
  test('Serialization Error', t => {
    t.plan(6)
  
    const client = new Client({
      node: 'http://localhost:9200',
      Connection: MockConnection,
      maxRetries: 1
    })
  
    const order = [
      events.SERIALIZATION,
      events.REQUEST
    ]
  
    client.on(events.SERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.SERIALIZATION)
    })
  
    client.on(events.REQUEST, (err, request) => {
      t.ok(err instanceof SerializationError)
      t.equal(order.shift(), events.REQUEST)
    })
  
    client.on(events.DESERIALIZATION, (_err, request) => {
      t.fail('Should not be called')
    })
  
    client.on(events.RESPONSE, (_err, request) => {
      t.fail('Should not be called')
    })
  
    const body = {}
    body.o = body
    client.index({ index: 'test', body }, (err, result) => {
      t.ok(err instanceof SerializationError)
      t.equal(order.length, 0)
    })
  })
  
  test('Deserialization Error', t => {
    t.plan(10)
  
    class MockConnection extends Connection {
      request (params, callback) {
        const body = '{"hello":"wor'
        const stream = intoStream(body)
        stream.statusCode = 200
        stream.headers = {
          'content-type': 'application/json;utf=8',
          'content-length': body.length,
          connection: 'keep-alive',
          date: new Date().toISOString()
        }
        stream.on('close', () => t.pass('Stream destroyed'))
        process.nextTick(callback, null, stream)
        return { abort () {} }
      }
    }
  
    const client = new Client({
      node: 'http://localhost:9200',
      Connection: MockConnection,
      maxRetries: 1
    })
  
    const order = [
      events.SERIALIZATION,
      events.REQUEST,
      events.DESERIALIZATION,
      events.RESPONSE
    ]
  
    client.on(events.SERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.SERIALIZATION)
    })
  
    client.on(events.REQUEST, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.REQUEST)
    })
  
    client.on(events.DESERIALIZATION, (err, request) => {
      t.error(err)
      t.equal(order.shift(), events.DESERIALIZATION)
    })
  
    client.on(events.RESPONSE, (err, request) => {
      t.ok(err instanceof DeserializationError)
      t.equal(order.shift(), events.RESPONSE)
    })
  
    client.info((err, result) => {
      t.ok(err instanceof DeserializationError)
      t.equal(order.length, 0)
    })
  })
  
  test('Socket destroyed while reading the body', t => {
    t.plan(14)
  
    function handler (req, res) {
      const body = JSON.stringify({ hello: 'world' })
      res.setHeader('Content-Type', 'application/json;utf=8')
      res.setHeader('Content-Length', body.length + '')
      res.write(body.slice(0, -5))
      setTimeout(() => {
        res.socket.destroy()
      }, 500)
    }
  
    buildServer(handler, ({ port }, server) => {
      const client = new Client({ node: `http://localhost:${port}`, maxRetries: 1 })
  
      const order = [
        events.SERIALIZATION,
        events.REQUEST,
        events.DESERIALIZATION,
        events.REQUEST,
        events.DESERIALIZATION,
        events.RESPONSE
      ]
  
      client.on(events.SERIALIZATION, (err, request) => {
        t.error(err)
        t.equal(order.shift(), events.SERIALIZATION)
      })
  
      client.on(events.REQUEST, (err, request) => {
        t.error(err)
        t.equal(order.shift(), events.REQUEST)
      })
  
      client.on(events.DESERIALIZATION, (err, request) => {
        t.error(err)
        t.equal(order.shift(), events.DESERIALIZATION)
      })
  
      client.on(events.RESPONSE, (err, request) => {
        t.ok(err instanceof ConnectionError)
        t.equal(order.shift(), events.RESPONSE)
      })
  
      client.info((err, result) => {
        t.ok(err instanceof ConnectionError)
        t.equal(order.length, 0)
        server.stop()
      })
    })
  })
  