Skip to content
This repository has been archived by the owner on Aug 11, 2020. It is now read-only.

Commit

Permalink
squash! quic: allow testing QUIC without real UDP handle
Browse files Browse the repository at this point in the history
  • Loading branch information
addaleax committed Oct 16, 2019
1 parent 4e70ee0 commit 5453076
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/js_udp_wrap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ void JSUDPWrap::OnSendDone(const FunctionCallbackInfo<Value>& args) {
CHECK(args[0]->IsObject());
CHECK(args[1]->IsInt32());
ReqWrap<uv_udp_send_t>* req_wrap;
ASSIGN_OR_RETURN_UNWRAP(&wrap, args[0].As<Object>());
ASSIGN_OR_RETURN_UNWRAP(&req_wrap, args[0].As<Object>());
int status = args[1].As<Int32>()->Value();

wrap->listener()->OnSendDone(req_wrap, status);
Expand Down
14 changes: 14 additions & 0 deletions test/common/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ This directory contains modules used to test the Node.js implementation.
* [Report module](#report-module)
* [tick module](#tick-module)
* [tmpdir module](#tmpdir-module)
* [UDP pair helper](#udp-pair-helper)
* [WPT module](#wpt-module)

## Benchmark Module
Expand Down Expand Up @@ -912,6 +913,19 @@ listener to process `'beforeExit'`. If a file needs to be left open until
Node.js completes, use a child process and call `refresh()` only in the
parent.

## UDP pair helper

The `common/udppair` module exports a function `makeUDPPair` and a class
`FakeUDPWrap`.

`FakeUDPWrap` emits `'send'` events when data is to be sent on it, and provides
an `emitReceived()` API for acting as if data has been received on it.

`makeUDPPair` returns an object `{ clientSide, serverSide }` where each side
is an `FakeUDPWrap` connected to the other side.

There is no difference between client or server side beyond their names.

## WPT Module

### harness
Expand Down
100 changes: 100 additions & 0 deletions test/common/udppair.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/* 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');

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
};
72 changes: 72 additions & 0 deletions test/parallel/test-quic-with-fake-udp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Flags: --expose-internals
'use strict';
const common = require('../common');
const { makeUDPPair } = require('../common/udppair');
const assert = require('assert');
const quic = require('quic');
const { kUDPHandleForTesting } = require('internal/quic/core');

const fixtures = require('../common/fixtures');
const key = fixtures.readKey('agent1-key.pem', 'binary');
const cert = fixtures.readKey('agent1-cert.pem', 'binary');
const ca = fixtures.readKey('ca1-cert.pem', 'binary');

const { serverSide, clientSide } = makeUDPPair();

const server = quic.createSocket({
port: 0, validateAddress: true, [kUDPHandleForTesting]: serverSide._handle
});

serverSide.afterBind();
server.listen({
key,
cert,
ca,
rejectUnauthorized: false,
maxCryptoBuffer: 4096,
alpn: 'meow'
});

server.on('session', common.mustCall((session) => {
session.on('secure', common.mustCall((servername, alpn, cipher) => {
const stream = session.openStream({ halfOpen: false });
stream.end('Hi!');
stream.on('data', common.mustNotCall());
stream.on('finish', common.mustCall());
stream.on('close', common.mustNotCall());
stream.on('end', common.mustNotCall());
}));

session.on('close', common.mustNotCall());
}));

server.on('ready', common.mustCall(() => {
const client = quic.createSocket({
port: 0,
[kUDPHandleForTesting]: clientSide._handle,
client: {
key,
cert,
ca,
alpn: 'meow'
}
});
clientSide.afterBind();

const req = client.connect({
address: 'localhost',
port: server.address.port
});

req.on('stream', common.mustCall((stream) => {
stream.on('data', common.mustCall((data) => {
assert.strictEqual(data.toString(), 'Hi!');
}));

stream.on('end', common.mustCall());
}));

req.on('close', common.mustNotCall());
}));

server.on('close', common.mustNotCall());

0 comments on commit 5453076

Please sign in to comment.