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

feat: port client-connect, client-dispatch, client-errors test to node:test #2591

Merged
merged 11 commits into from
Jan 16, 2024
Next Next commit
client-connect
  • Loading branch information
sosukesuzuki committed Jan 11, 2024
commit 00c7cd278dc71c3468dc911e3fad8759af90bdac
162 changes: 89 additions & 73 deletions test/client-connect.js → test/node-test/client-connect.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
'use strict'

const { test } = require('tap')
const { Client, errors } = require('..')
const { test } = require('node:test')
const { Client, errors } = require('../..')
const http = require('http')
const EE = require('events')
const { kBusy } = require('../lib/core/symbols')
const { kBusy } = require('../../lib/core/symbols')
const { tspl } = require('@matteo.collina/tspl')

test('basic connect', (t) => {
t.plan(3)
test('basic connect', async (t) => {
const p = tspl(t, { plan: 3 })

const server = http.createServer((c) => {
t.fail()
p.ok(0)
})
server.on('connect', (req, socket, firstBodyChunk) => {
socket.write('HTTP/1.1 200 Connection established\r\n\r\n')
Expand All @@ -24,97 +25,101 @@ test('basic connect', (t) => {
socket.end(data)
})
})
t.teardown(server.close.bind(server))
t.after(server.close.bind(server))

server.listen(0, async () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.teardown(client.close.bind(client))
t.after(() => client.close.bind(client)())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems the function is getting called instead of passed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the two codes below are equivalent:

t.after(() => client.close.bind(client)())
t.after(() => {
  return client.close.bind(client)()
})

However, to make it easier to understand, I rewritten it as t.after(() => { client.close() })

e44332a


const signal = new EE()
const promise = client.connect({
signal,
path: '/'
})
t.equal(signal.listenerCount('abort'), 1)
p.strictEqual(signal.listenerCount('abort'), 1)
const { socket } = await promise
t.equal(signal.listenerCount('abort'), 0)
p.strictEqual(signal.listenerCount('abort'), 0)

let recvData = ''
socket.on('data', (d) => {
recvData += d
})

socket.on('end', () => {
t.equal(recvData.toString(), 'Body')
p.strictEqual(recvData.toString(), 'Body')
})

socket.write('Body')
socket.end()
})

await p.completed
})

test('connect error', (t) => {
t.plan(1)
test('connect error', async (t) => {
const p = tspl(t, { plan: 1 })

const server = http.createServer((c) => {
t.fail()
p.ok(0)
})
server.on('connect', (req, socket, firstBodyChunk) => {
socket.destroy()
})
t.teardown(server.close.bind(server))
t.after(server.close.bind(server))

server.listen(0, async () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.teardown(client.close.bind(client))
t.after(() => client.close.bind(client)())

try {
await client.connect({
path: '/'
})
} catch (err) {
t.ok(err)
p.ok(err)
}
})

await p.completed
})

test('connect invalid opts', (t) => {
t.plan(6)
const p = tspl(t, { plan: 6 })

const client = new Client('http://localhost:5432')

client.connect(null, err => {
t.type(err, errors.InvalidArgumentError)
t.equal(err.message, 'invalid opts')
p.ok(err instanceof errors.InvalidArgumentError)
p.strictEqual(err.message, 'invalid opts')
})

try {
client.connect(null, null)
t.fail()
p.ok(0)
} catch (err) {
t.type(err, errors.InvalidArgumentError)
t.equal(err.message, 'invalid opts')
p.ok(err instanceof errors.InvalidArgumentError)
p.strictEqual(err.message, 'invalid opts')
}

try {
client.connect({ path: '/' }, null)
t.fail()
p.ok(0)
} catch (err) {
t.type(err, errors.InvalidArgumentError)
t.equal(err.message, 'invalid callback')
p.ok(err instanceof errors.InvalidArgumentError)
p.strictEqual(err.message, 'invalid callback')
}
})

test('connect wait for empty pipeline', (t) => {
t.plan(7)
test('connect wait for empty pipeline', async (t) => {
const p = tspl(t, { plan: 7 })

let canConnect = false
const server = http.createServer((req, res) => {
res.end()
canConnect = true
})
server.on('connect', (req, socket, firstBodyChunk) => {
t.equal(canConnect, true)
p.strictEqual(canConnect, true)
socket.write('HTTP/1.1 200 Connection established\r\n\r\n')

let data = firstBodyChunk.toString()
Expand All @@ -126,95 +131,100 @@ test('connect wait for empty pipeline', (t) => {
socket.end(data)
})
})
t.teardown(server.close.bind(server))
t.after(server.close.bind(server))

server.listen(0, async () => {
const client = new Client(`http://localhost:${server.address().port}`, {
pipelining: 3
})
t.teardown(client.close.bind(client))
t.after(() => client.close.bind(client)())

client.request({
path: '/',
method: 'GET'
}, (err) => {
t.error(err)
p.ifError(err)
})
client.once('connect', () => {
process.nextTick(() => {
t.equal(client[kBusy], false)
p.strictEqual(client[kBusy], false)

client.connect({
path: '/'
}, (err, { socket }) => {
t.error(err)
p.ifError(err)
let recvData = ''
socket.on('data', (d) => {
recvData += d
})

socket.on('end', () => {
t.equal(recvData.toString(), 'Body')
p.strictEqual(recvData.toString(), 'Body')
})

socket.write('Body')
socket.end()
})
t.equal(client[kBusy], true)
p.strictEqual(client[kBusy], true)

client.request({
path: '/',
method: 'GET'
}, (err) => {
t.error(err)
p.ifError(err)
})
})
})
})
await p.completed
})

test('connect aborted', (t) => {
t.plan(6)
test('connect aborted', async (t) => {
const p = tspl(t, { plan: 6 })

const server = http.createServer((req, res) => {
t.fail()
p.ok(0)
})
server.on('connect', (req, c, firstBodyChunk) => {
t.fail()
p.ok(0)
})
t.teardown(server.close.bind(server))
t.after(server.close.bind(server))

server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`, {
pipelining: 3
})
t.teardown(client.destroy.bind(client))
t.after(() => {
client.destroy()
})

const signal = new EE()
client.connect({
path: '/',
signal,
opaque: 'asd'
}, (err, { opaque }) => {
t.equal(opaque, 'asd')
t.equal(signal.listenerCount('abort'), 0)
t.type(err, errors.RequestAbortedError)
p.strictEqual(opaque, 'asd')
p.strictEqual(signal.listenerCount('abort'), 0)
p.ok(err instanceof errors.RequestAbortedError)
})
t.equal(client[kBusy], true)
t.equal(signal.listenerCount('abort'), 1)
p.strictEqual(client[kBusy], true)
p.strictEqual(signal.listenerCount('abort'), 1)
signal.emit('abort')

client.close(() => {
t.pass()
p.ok(1)
})
})

await p.completed
})

test('basic connect error', (t) => {
t.plan(2)
test('basic connect error', async (t) => {
const p = tspl(t, { plan: 2 })

const server = http.createServer((c) => {
t.fail()
p.ok(0)
})
server.on('connect', (req, socket, firstBodyChunk) => {
socket.write('HTTP/1.1 200 Connection established\r\n\r\n')
Expand All @@ -228,81 +238,87 @@ test('basic connect error', (t) => {
socket.end(data)
})
})
t.teardown(server.close.bind(server))
t.after(server.close.bind(server))

server.listen(0, async () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.teardown(client.close.bind(client))
t.after(() => client.close.bind(client)())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same


const _err = new Error()
client.connect({
path: '/'
}, (err, { socket }) => {
t.error(err)
p.ifError(err)
socket.on('error', (err) => {
t.equal(err, _err)
p.strictEqual(err, _err)
})
throw _err
})
})

await p.completed
})

test('connect invalid signal', (t) => {
t.plan(2)
test('connect invalid signal', async (t) => {
const p = tspl(t, { plan: 2 })

const server = http.createServer((req, res) => {
t.fail()
p.ok(0)
})
server.on('connect', (req, c, firstBodyChunk) => {
t.fail()
p.ok(0)
})
t.teardown(server.close.bind(server))
t.after(server.close.bind(server))

server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`)
t.teardown(client.destroy.bind(client))
t.after(client.destroy.bind(client))

client.on('disconnect', () => {
t.fail()
p.ok(0)
})

client.connect({
path: '/',
signal: 'error',
opaque: 'asd'
}, (err, { opaque }) => {
t.equal(opaque, 'asd')
t.type(err, errors.InvalidArgumentError)
p.strictEqual(opaque, 'asd')
p.ok(err instanceof errors.InvalidArgumentError)
})
})

await p.completed
})

test('connect aborted after connect', (t) => {
t.plan(3)
test('connect aborted after connect', async (t) => {
const p = tspl(t, { plan: 3 })

const signal = new EE()
const server = http.createServer((req, res) => {
t.fail()
p.ok(0)
})
server.on('connect', (req, c, firstBodyChunk) => {
signal.emit('abort')
})
t.teardown(server.close.bind(server))
t.after(server.close.bind(server))

server.listen(0, () => {
const client = new Client(`http://localhost:${server.address().port}`, {
pipelining: 3
})
t.teardown(client.destroy.bind(client))
t.after(client.destroy.bind(client))

client.connect({
path: '/',
signal,
opaque: 'asd'
}, (err, { opaque }) => {
t.equal(opaque, 'asd')
t.type(err, errors.RequestAbortedError)
p.strictEqual(opaque, 'asd')
p.ok(err instanceof errors.RequestAbortedError)
})
t.equal(client[kBusy], true)
p.strictEqual(client[kBusy], true)
})

await p.completed
})