Skip to content

Commit bccb191

Browse files
authored
test: duplicate jest unspecific tests to native runner (#3075)
1 parent 8a07bbd commit bccb191

File tree

2 files changed

+253
-0
lines changed

2 files changed

+253
-0
lines changed

test/interceptor.js

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
'use strict'
2+
3+
const { strictEqual, deepStrictEqual } = require('node:assert')
4+
const { describe, beforeEach, afterEach, test } = require('node:test')
5+
const { createServer } = require('node:http')
6+
const { Agent, request } = require('../index')
7+
const DecoratorHandler = require('../lib/handler/decorator-handler')
8+
9+
const defaultOpts = { keepAliveTimeout: 10, keepAliveMaxTimeout: 10 }
10+
11+
describe('interceptors', () => {
12+
let server
13+
beforeEach(async () => {
14+
server = createServer((req, res) => {
15+
res.setHeader('Content-Type', 'text/plain')
16+
res.end('hello')
17+
})
18+
await new Promise((resolve) => { server.listen(0, resolve) })
19+
})
20+
afterEach(async () => {
21+
await new Promise((resolve) => server.close(resolve))
22+
})
23+
24+
test('interceptors are applied on client from an agent', async () => {
25+
const interceptors = []
26+
const buildInterceptor = dispatch => {
27+
const interceptorContext = { requestCount: 0 }
28+
interceptors.push(interceptorContext)
29+
return (opts, handler) => {
30+
interceptorContext.requestCount++
31+
return dispatch(opts, handler)
32+
}
33+
}
34+
35+
const opts = { interceptors: { Client: [buildInterceptor] }, ...defaultOpts }
36+
const agent = new Agent(opts)
37+
const origin = new URL(`http://localhost:${server.address().port}`)
38+
await Promise.all([
39+
request(origin, { dispatcher: agent }),
40+
request(origin, { dispatcher: agent })
41+
])
42+
43+
// Assert that the requests are run on different interceptors (different Clients)
44+
const requestCounts = interceptors.map(x => x.requestCount)
45+
deepStrictEqual(requestCounts, [1, 1])
46+
})
47+
48+
test('interceptors are applied in the correct order', async () => {
49+
const setHeaderInterceptor = (dispatch) => {
50+
return (opts, handler) => {
51+
opts.headers.push('foo', 'bar')
52+
return dispatch(opts, handler)
53+
}
54+
}
55+
56+
const assertHeaderInterceptor = (dispatch) => {
57+
return (opts, handler) => {
58+
deepStrictEqual(opts.headers, ['foo', 'bar'])
59+
return dispatch(opts, handler)
60+
}
61+
}
62+
63+
const opts = { interceptors: { Pool: [setHeaderInterceptor, assertHeaderInterceptor] }, ...defaultOpts }
64+
const agent = new Agent(opts)
65+
const origin = new URL(`http://localhost:${server.address().port}`)
66+
await request(origin, { dispatcher: agent, headers: [] })
67+
})
68+
69+
test('interceptors handlers are called in reverse order', async () => {
70+
const clearResponseHeadersInterceptor = (dispatch) => {
71+
return (opts, handler) => {
72+
class ResultInterceptor extends DecoratorHandler {
73+
onHeaders (statusCode, headers, resume) {
74+
return super.onHeaders(statusCode, [], resume)
75+
}
76+
}
77+
78+
return dispatch(opts, new ResultInterceptor(handler))
79+
}
80+
}
81+
82+
const assertHeaderInterceptor = (dispatch) => {
83+
return (opts, handler) => {
84+
class ResultInterceptor extends DecoratorHandler {
85+
onHeaders (statusCode, headers, resume) {
86+
deepStrictEqual(headers, [])
87+
return super.onHeaders(statusCode, headers, resume)
88+
}
89+
}
90+
91+
return dispatch(opts, new ResultInterceptor(handler))
92+
}
93+
}
94+
95+
const opts = { interceptors: { Agent: [assertHeaderInterceptor, clearResponseHeadersInterceptor] }, ...defaultOpts }
96+
const agent = new Agent(opts)
97+
const origin = new URL(`http://localhost:${server.address().port}`)
98+
await request(origin, { dispatcher: agent, headers: [] })
99+
})
100+
})
101+
102+
describe('interceptors with NtlmRequestHandler', () => {
103+
class FakeNtlmRequestHandler {
104+
constructor (dispatch, opts, handler) {
105+
this.dispatch = dispatch
106+
this.opts = opts
107+
this.handler = handler
108+
this.requestCount = 0
109+
}
110+
111+
onConnect (...args) {
112+
return this.handler.onConnect(...args)
113+
}
114+
115+
onError (...args) {
116+
return this.handler.onError(...args)
117+
}
118+
119+
onUpgrade (...args) {
120+
return this.handler.onUpgrade(...args)
121+
}
122+
123+
onHeaders (statusCode, headers, resume, statusText) {
124+
this.requestCount++
125+
if (this.requestCount < 2) {
126+
// Do nothing
127+
} else {
128+
return this.handler.onHeaders(statusCode, headers, resume, statusText)
129+
}
130+
}
131+
132+
onData (...args) {
133+
if (this.requestCount < 2) {
134+
// Do nothing
135+
} else {
136+
return this.handler.onData(...args)
137+
}
138+
}
139+
140+
onComplete (...args) {
141+
if (this.requestCount < 2) {
142+
this.dispatch(this.opts, this)
143+
} else {
144+
return this.handler.onComplete(...args)
145+
}
146+
}
147+
148+
onBodySent (...args) {
149+
if (this.requestCount < 2) {
150+
// Do nothing
151+
} else {
152+
return this.handler.onBodySent(...args)
153+
}
154+
}
155+
}
156+
let server
157+
158+
beforeEach(async () => {
159+
// This Test is important because NTLM and Negotiate require several
160+
// http requests in sequence to run on the same keepAlive socket
161+
162+
const socketRequestCountSymbol = Symbol('Socket Request Count')
163+
server = createServer((req, res) => {
164+
if (req.socket[socketRequestCountSymbol] === undefined) {
165+
req.socket[socketRequestCountSymbol] = 0
166+
}
167+
req.socket[socketRequestCountSymbol]++
168+
res.setHeader('Content-Type', 'text/plain')
169+
170+
// Simulate NTLM/Negotiate logic, by returning 200
171+
// on the second request of each socket
172+
if (req.socket[socketRequestCountSymbol] >= 2) {
173+
res.statusCode = 200
174+
res.end()
175+
} else {
176+
res.statusCode = 401
177+
res.end()
178+
}
179+
})
180+
await new Promise((resolve) => { server.listen(0, resolve) })
181+
})
182+
afterEach(async () => {
183+
await new Promise((resolve) => server.close(resolve))
184+
})
185+
186+
test('Retry interceptor on Client will use the same socket', async () => {
187+
const interceptor = dispatch => {
188+
return (opts, handler) => {
189+
return dispatch(opts, new FakeNtlmRequestHandler(dispatch, opts, handler))
190+
}
191+
}
192+
const opts = { interceptors: { Client: [interceptor] }, ...defaultOpts }
193+
const agent = new Agent(opts)
194+
const origin = new URL(`http://localhost:${server.address().port}`)
195+
const { statusCode } = await request(origin, { dispatcher: agent, headers: [] })
196+
strictEqual(statusCode, 200)
197+
})
198+
})

test/issue-1757.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
'use strict'
2+
3+
const { deepStrictEqual, strictEqual } = require('node:assert')
4+
const { test } = require('node:test')
5+
const { Dispatcher, setGlobalDispatcher, fetch, MockAgent } = require('..')
6+
7+
class MiniflareDispatcher extends Dispatcher {
8+
constructor (inner, options) {
9+
super(options)
10+
this.inner = inner
11+
}
12+
13+
dispatch (options, handler) {
14+
return this.inner.dispatch(options, handler)
15+
}
16+
17+
close (...args) {
18+
return this.inner.close(...args)
19+
}
20+
21+
destroy (...args) {
22+
return this.inner.destroy(...args)
23+
}
24+
}
25+
26+
test('https://github.com/nodejs/undici/issues/1757', async () => {
27+
const mockAgent = new MockAgent()
28+
const mockClient = mockAgent.get('http://localhost:3000')
29+
mockAgent.disableNetConnect()
30+
setGlobalDispatcher(new MiniflareDispatcher(mockAgent))
31+
32+
mockClient.intercept({
33+
path: () => true,
34+
method: () => true
35+
}).reply(200, async (opts) => {
36+
if (opts.body?.[Symbol.asyncIterator]) {
37+
const chunks = []
38+
for await (const chunk of opts.body) {
39+
chunks.push(chunk)
40+
}
41+
42+
return Buffer.concat(chunks)
43+
}
44+
45+
return opts.body
46+
})
47+
48+
const response = await fetch('http://localhost:3000', {
49+
method: 'POST',
50+
body: JSON.stringify({ foo: 'bar' })
51+
})
52+
53+
deepStrictEqual(await response.json(), { foo: 'bar' })
54+
strictEqual(response.status, 200)
55+
})

0 commit comments

Comments
 (0)