Browse Source

test: http2 client destroy tests in one file

Refs: #14985
PR-URL: https://github.com/nodejs/node/pull/15749
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
v9.x-staging
Trivikram Kamat 8 years ago
committed by Matteo Collina
parent
commit
d6031bc1c6
  1. 6
      lib/internal/http2/core.js
  2. 29
      test/parallel/test-http2-client-destroy-before-connect.js
  3. 29
      test/parallel/test-http2-client-destroy-before-request.js
  4. 24
      test/parallel/test-http2-client-destroy-goaway.js
  5. 130
      test/parallel/test-http2-client-destroy.js

6
lib/internal/http2/core.js

@ -671,8 +671,6 @@ function submitShutdown(options) {
function finishSessionDestroy(self, socket) { function finishSessionDestroy(self, socket) {
const state = self[kState]; const state = self[kState];
if (state.destroyed)
return;
if (!socket.destroyed) if (!socket.destroyed)
socket.destroy(); socket.destroy();
@ -955,6 +953,7 @@ class Http2Session extends EventEmitter {
return; return;
debug(`[${sessionName(this[kType])}] destroying nghttp2session`); debug(`[${sessionName(this[kType])}] destroying nghttp2session`);
state.destroying = true; state.destroying = true;
state.destroyed = false;
// Unenroll the timer // Unenroll the timer
this.setTimeout(0, sessionOnTimeout); this.setTimeout(0, sessionOnTimeout);
@ -969,9 +968,6 @@ class Http2Session extends EventEmitter {
delete this[kSocket]; delete this[kSocket];
delete this[kServer]; delete this[kServer];
state.destroyed = false;
state.destroying = true;
if (this[kHandle] !== undefined) if (this[kHandle] !== undefined)
this[kHandle].destroying(); this[kHandle].destroying();

29
test/parallel/test-http2-client-destroy-before-connect.js

@ -1,29 +0,0 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const h2 = require('http2');
const server = h2.createServer();
// we use the lower-level API here
server.on('stream', common.mustNotCall());
server.listen(0);
server.on('listening', common.mustCall(() => {
const client = h2.connect(`http://localhost:${server.address().port}`);
const req = client.request({ ':path': '/' });
client.destroy();
req.on('response', common.mustNotCall());
req.resume();
req.on('end', common.mustCall(() => {
server.close();
}));
req.end();
}));

29
test/parallel/test-http2-client-destroy-before-request.js

@ -1,29 +0,0 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const assert = require('assert');
const h2 = require('http2');
const server = h2.createServer();
// we use the lower-level API here
server.on('stream', common.mustNotCall());
server.listen(0);
server.on('listening', common.mustCall(() => {
const client = h2.connect(`http://localhost:${server.address().port}`);
client.destroy();
assert.throws(() => client.request({ ':path': '/' }),
common.expectsError({
code: 'ERR_HTTP2_INVALID_SESSION',
message: /^The session has been destroyed$/
}));
server.close();
}));

24
test/parallel/test-http2-client-destroy-goaway.js

@ -1,24 +0,0 @@
'use strict';
const common = require('../common');
if (!common.hasCrypto)
common.skip('missing crypto');
const http2 = require('http2');
const server = http2.createServer();
server.on('stream', common.mustCall((stream) => {
stream.on('error', common.mustCall());
stream.session.shutdown();
}));
server.listen(0, common.mustCall(() => {
const client = http2.connect(`http://localhost:${server.address().port}`);
client.on('goaway', common.mustCall(() => {
// We ought to be able to destroy the client in here without an error
server.close();
client.destroy();
}));
client.request();
}));

130
test/parallel/test-http2-client-destroy.js

@ -6,12 +6,11 @@ if (!common.hasCrypto)
const assert = require('assert'); const assert = require('assert');
const h2 = require('http2'); const h2 = require('http2');
const server = h2.createServer(); {
server.listen(0); const server = h2.createServer();
server.listen(
server.on('listening', common.mustCall(function() { 0,
const port = this.address().port; common.mustCall(() => {
const destroyCallbacks = [ const destroyCallbacks = [
(client) => client.destroy(), (client) => client.destroy(),
(client) => client.socket.destroy() (client) => client.socket.destroy()
@ -20,36 +19,129 @@ server.on('listening', common.mustCall(function() {
let remaining = destroyCallbacks.length; let remaining = destroyCallbacks.length;
destroyCallbacks.forEach((destroyCallback) => { destroyCallbacks.forEach((destroyCallback) => {
const client = h2.connect(`http://localhost:${port}`); const client = h2.connect(`http://localhost:${server.address().port}`);
client.on('connect', common.mustCall(() => { client.on(
'connect',
common.mustCall(() => {
const socket = client.socket; const socket = client.socket;
assert(client.socket, 'client session has associated socket'); assert(client.socket, 'client session has associated socket');
assert(!client.destroyed, assert(
'client has not been destroyed before destroy is called'); !client.destroyed,
assert(!socket.destroyed, 'client has not been destroyed before destroy is called'
'socket has not been destroyed before destroy is called'); );
assert(
!socket.destroyed,
'socket has not been destroyed before destroy is called'
);
// Ensure that 'close' event is emitted // Ensure that 'close' event is emitted
client.on('close', common.mustCall()); client.on('close', common.mustCall());
destroyCallback(client); destroyCallback(client);
assert(!client.socket, 'client.socket undefined after destroy is called'); assert(
!client.socket,
'client.socket undefined after destroy is called'
);
// Must must be closed // Must must be closed
client.on('close', common.mustCall(() => { client.on(
'close',
common.mustCall(() => {
assert(client.destroyed); assert(client.destroyed);
})); })
);
// socket will close on process.nextTick // socket will close on process.nextTick
socket.on('close', common.mustCall(() => { socket.on(
'close',
common.mustCall(() => {
assert(socket.destroyed); assert(socket.destroyed);
})); })
);
if (--remaining === 0) { if (--remaining === 0) {
server.close(); server.close();
} }
})); })
);
}); });
})); })
);
}
// test destroy before connect
{
const server = h2.createServer();
server.listen(
0,
common.mustCall(() => {
const client = h2.connect(`http://localhost:${server.address().port}`);
const req = client.request({ ':path': '/' });
client.destroy();
req.on('response', common.mustNotCall());
req.resume();
req.on(
'end',
common.mustCall(() => {
server.close();
})
);
req.end();
})
);
}
// test destroy before request
{
const server = h2.createServer();
server.listen(
0,
common.mustCall(() => {
const client = h2.connect(`http://localhost:${server.address().port}`);
client.destroy();
assert.throws(
() => client.request({ ':path': '/' }),
common.expectsError({
code: 'ERR_HTTP2_INVALID_SESSION',
message: 'The session has been destroyed'
})
);
server.close();
})
);
}
// test destroy before goaway
{
const server = h2.createServer();
server.on(
'stream',
common.mustCall((stream) => {
stream.on('error', common.mustCall());
stream.session.shutdown();
})
);
server.listen(
0,
common.mustCall(() => {
const client = h2.connect(`http://localhost:${server.address().port}`);
client.on(
'goaway',
common.mustCall(() => {
// We ought to be able to destroy the client in here without an error
server.close();
client.destroy();
})
);
client.request();
})
);
}

Loading…
Cancel
Save