'use strict';

const common = require('../common');
if (!common.hasCrypto)
  common.skip('missing crypto');
const assert = require('assert');
const h2 = require('http2');
const Countdown = require('../common/countdown');

// Calling .destroy() on the socket proxy must not throw
// (previously threw ERR_HTTP2_NO_SOCKET_MANIPULATION) and must
// destroy the Http2Session and the underlying socket.

const server = h2.createServer();

server.on('stream', common.mustCall(function(stream) {
  stream.respond();
  stream.end('ok');
}, 2));

const countdown = new Countdown(2, () => server.close());

server.listen(0, common.mustCall(() => {
  const port = server.address().port;

  // Test destroy() without an error.
  {
    const client = h2.connect(`http://localhost:${port}`);
    const request = client.request();
    request.resume();
    request.on('close', common.mustCall(() => {
      const socket = client.socket;
      socket.destroy();
      assert.strictEqual(client.destroyed, true);
      client.on('close', common.mustCall(() => {
        assert.strictEqual(client.socket, undefined);
        // Destroying again through a stale proxy reference must not throw.
        socket.destroy();
        countdown.dec();
      }));
    }));
    client.on('error', common.mustNotCall());
  }

  // Test destroy() with an error.
  {
    const client = h2.connect(`http://localhost:${port}`);
    const request = client.request();
    request.resume();
    request.on('close', common.mustCall(() => {
      client.socket.destroy(new Error('boom'));
      assert.strictEqual(client.destroyed, true);
    }));
    client.on('error', common.mustCall((err) => {
      assert.strictEqual(err.message, 'boom');
    }));
    client.on('close', common.mustCall(() => {
      countdown.dec();
    }));
  }
}));
