Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: http2 client destroy tests in one file #15749

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 1 addition & 5 deletions lib/internal/http2/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -672,8 +672,6 @@ function submitShutdown(options) {

function finishSessionDestroy(self, socket) {
const state = self[kState];
if (state.destroyed)
return;

if (!socket.destroyed)
socket.destroy();
Expand Down Expand Up @@ -956,6 +954,7 @@ class Http2Session extends EventEmitter {
return;
debug(`[${sessionName(this[kType])}] destroying nghttp2session`);
state.destroying = true;
state.destroyed = false;

// Unenroll the timer
this.setTimeout(0, sessionOnTimeout);
Expand All @@ -970,9 +969,6 @@ class Http2Session extends EventEmitter {
delete this[kSocket];
delete this[kServer];

state.destroyed = false;
state.destroying = true;

if (this[kHandle] !== undefined)
this[kHandle].destroying();

Expand Down
29 changes: 0 additions & 29 deletions test/parallel/test-http2-client-destroy-before-connect.js

This file was deleted.

29 changes: 0 additions & 29 deletions test/parallel/test-http2-client-destroy-before-request.js

This file was deleted.

24 changes: 0 additions & 24 deletions test/parallel/test-http2-client-destroy-goaway.js

This file was deleted.

164 changes: 128 additions & 36 deletions test/parallel/test-http2-client-destroy.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,50 +6,142 @@ if (!common.hasCrypto)
const assert = require('assert');
const h2 = require('http2');

const server = h2.createServer();
server.listen(0);
{
const server = h2.createServer();
server.listen(
0,
common.mustCall(() => {
const destroyCallbacks = [
(client) => client.destroy(),
(client) => client.socket.destroy()
];

server.on('listening', common.mustCall(function() {
const port = this.address().port;
let remaining = destroyCallbacks.length;

const destroyCallbacks = [
(client) => client.destroy(),
(client) => client.socket.destroy()
];
destroyCallbacks.forEach((destroyCallback) => {
const client = h2.connect(`http://localhost:${server.address().port}`);
client.on(
'connect',
common.mustCall(() => {
const socket = client.socket;

let remaining = destroyCallbacks.length;
assert(client.socket, 'client session has associated socket');
assert(
!client.destroyed,
'client has not been destroyed before destroy is called'
);
assert(
!socket.destroyed,
'socket has not been destroyed before destroy is called'
);

destroyCallbacks.forEach((destroyCallback) => {
const client = h2.connect(`http://localhost:${port}`);
client.on('connect', common.mustCall(() => {
const socket = client.socket;
// Ensure that 'close' event is emitted
client.on('close', common.mustCall());

assert(client.socket, 'client session has associated socket');
assert(!client.destroyed,
'client has not been destroyed before destroy is called');
assert(!socket.destroyed,
'socket has not been destroyed before destroy is called');
destroyCallback(client);

// Ensure that 'close' event is emitted
client.on('close', common.mustCall());
assert(
!client.socket,
'client.socket undefined after destroy is called'
);

destroyCallback(client);
// Must must be closed
client.on(
'close',
common.mustCall(() => {
assert(client.destroyed);
})
);

assert(!client.socket, 'client.socket undefined after destroy is called');
// socket will close on process.nextTick
socket.on(
'close',
common.mustCall(() => {
assert(socket.destroyed);
})
);

// Must must be closed
client.on('close', common.mustCall(() => {
assert(client.destroyed);
}));
if (--remaining === 0) {
server.close();
}
})
);
});
})
);
}

// socket will close on process.nextTick
socket.on('close', common.mustCall(() => {
assert(socket.destroyed);
}));
// test destroy before connect
{
const server = h2.createServer();
server.listen(
0,
common.mustCall(() => {
const client = h2.connect(`http://localhost:${server.address().port}`);

if (--remaining === 0) {
server.close();
}
}));
});
}));
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();
})
);
}