0
0
mirror of https://github.com/nodejs/node.git synced 2024-11-30 07:27:22 +01:00
nodejs/test/common/udppair.js
James M Snell a808cb76ce
test: add common/udppair utility
Extracted from the QUIC PR. This adds a utility used to
deterministically test UDP traffic. It is currently only
used by the experimental QUIC implementation. Separated
out on request to make review easier.

PR-URL: https://github.com/nodejs/node/pull/33380
Reviewed-By: Sam Roberts <vieuxtech@gmail.com>
2020-06-16 06:56:06 -07:00

103 lines
2.5 KiB
JavaScript

/* eslint-disable node-core/require-common-first, node-core/required-modules */
'use strict';
const { internalBinding } = require('internal/test/binding');
const { JSUDPWrap } = internalBinding('js_udp_wrap');
const EventEmitter = require('events');
// FakeUDPWrap is a testing utility that emulates a UDP connection
// for the sake of making UDP tests more deterministic.
class FakeUDPWrap extends EventEmitter {
constructor() {
super();
this._handle = new JSUDPWrap();
this._handle.onreadstart = () => this._startReading();
this._handle.onreadstop = () => this._stopReading();
this._handle.onwrite =
(wrap, buffers, addr) => this._write(wrap, buffers, addr);
this._handle.getsockname = (obj) => {
Object.assign(obj, { address: '127.0.0.1', family: 'IPv4', port: 1337 });
return 0;
};
this.reading = false;
this.bufferedReceived = [];
this.emitBufferedImmediate = null;
}
_emitBuffered = () => {
if (!this.reading) return;
if (this.bufferedReceived.length > 0) {
this.emitReceived(this.bufferedReceived.shift());
this.emitBufferedImmediate = setImmediate(this._emitBuffered);
} else {
this.emit('wantRead');
}
};
_startReading() {
this.reading = true;
this.emitBufferedImmediate = setImmediate(this._emitBuffered);
}
_stopReading() {
this.reading = false;
clearImmediate(this.emitBufferedImmediate);
}
_write(wrap, buffers, addr) {
this.emit('send', { buffers, addr });
setImmediate(() => this._handle.onSendDone(wrap, 0));
}
afterBind() {
this._handle.onAfterBind();
}
emitReceived(info) {
if (!this.reading) {
this.bufferedReceived.push(info);
return;
}
const {
buffers,
addr: {
family = 4,
address = '127.0.0.1',
port = 1337,
},
flags = 0
} = info;
let familyInt;
switch (family) {
case 'IPv4': familyInt = 4; break;
case 'IPv6': familyInt = 6; break;
default: throw new Error('bad family');
}
for (const buffer of buffers) {
this._handle.emitReceived(buffer, familyInt, address, port, flags);
}
}
}
function makeUDPPair() {
const serverSide = new FakeUDPWrap();
const clientSide = new FakeUDPWrap();
serverSide.on('send',
(chk) => setImmediate(() => clientSide.emitReceived(chk)));
clientSide.on('send',
(chk) => setImmediate(() => serverSide.emitReceived(chk)));
return { serverSide, clientSide };
}
module.exports = {
FakeUDPWrap,
makeUDPPair
};