odac 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/rules/coding.md +27 -0
- package/.agent/rules/memory.md +33 -0
- package/.agent/rules/project.md +30 -0
- package/.agent/rules/workflow.md +16 -0
- package/.github/workflows/release.yml +42 -1
- package/.github/workflows/test-coverage.yml +6 -5
- package/.github/workflows/test-publish.yml +36 -0
- package/.husky/pre-commit +10 -0
- package/.husky/pre-push +13 -0
- package/.releaserc.js +3 -3
- package/CHANGELOG.md +67 -0
- package/README.md +16 -0
- package/bin/odac.js +182 -40
- package/client/odac.js +10 -4
- package/docs/backend/01-overview/03-development-server.md +38 -45
- package/docs/backend/02-structure/01-typical-project-layout.md +59 -26
- package/docs/backend/03-config/00-configuration-overview.md +6 -6
- package/docs/backend/03-config/01-database-connection.md +2 -2
- package/docs/backend/03-config/02-static-route-mapping-optional.md +1 -1
- package/docs/backend/03-config/03-request-timeout.md +1 -1
- package/docs/backend/03-config/04-environment-variables.md +4 -4
- package/docs/backend/03-config/05-early-hints.md +2 -2
- package/docs/backend/04-routing/03-api-and-data-routes.md +18 -0
- package/docs/backend/04-routing/07-cron-jobs.md +17 -1
- package/docs/backend/05-controllers/01-how-to-build-a-controller.md +48 -3
- package/docs/backend/05-controllers/03-controller-classes.md +40 -20
- package/docs/backend/06-request-and-response/01-the-request-object-what-is-the-user-asking-for.md +17 -0
- package/docs/backend/07-views/10-styling-and-tailwind.md +93 -0
- package/docs/backend/08-database/01-getting-started.md +2 -2
- package/docs/backend/10-authentication/03-register.md +1 -1
- package/docs/backend/10-authentication/04-odac-register-forms.md +2 -2
- package/docs/backend/10-authentication/05-session-management.md +15 -1
- package/docs/backend/10-authentication/06-odac-login-forms.md +2 -2
- package/docs/backend/10-authentication/07-magic-links.md +1 -1
- package/docs/index.json +5 -1
- package/jest.config.js +1 -1
- package/package.json +9 -5
- package/src/Auth.js +58 -23
- package/src/Config.js +7 -7
- package/src/Env.js +3 -1
- package/src/Ipc.js +7 -0
- package/src/Lang.js +9 -2
- package/src/Odac.js +44 -35
- package/src/Request.js +1 -1
- package/src/Route/Cron.js +58 -17
- package/src/Route/Internal.js +1 -1
- package/src/Route.js +282 -99
- package/src/Server.js +40 -3
- package/src/Storage.js +4 -0
- package/src/Token.js +6 -4
- package/src/Validator.js +1 -1
- package/src/Var.js +22 -6
- package/src/View/EarlyHints.js +43 -33
- package/src/View/Form.js +17 -11
- package/src/View.js +62 -6
- package/template/package.json +3 -1
- package/template/view/content/home.html +3 -3
- package/template/view/head/main.html +2 -2
- package/test/Client.test.js +168 -0
- package/test/Config.test.js +112 -0
- package/test/Lang.test.js +92 -0
- package/test/Odac.test.js +86 -0
- package/test/{framework/middleware.test.js → Route/Middleware.test.js} +2 -2
- package/test/{framework/Route.test.js → Route.test.js} +1 -1
- package/test/{framework/View → View}/EarlyHints.test.js +1 -1
- package/test/{framework/WebSocket.test.js → WebSocket.test.js} +2 -2
- package/test/scripts/check-coverage.js +4 -4
- package/test/cli/Cli.test.js +0 -36
- package/test/core/Commands.test.js +0 -538
- package/test/core/Config.test.js +0 -1432
- package/test/core/Lang.test.js +0 -250
- package/test/core/Odac.test.js +0 -234
- package/test/core/Process.test.js +0 -156
- package/test/server/Api.test.js +0 -647
- package/test/server/DNS.test.js +0 -2050
- package/test/server/DNS.test.js.bak +0 -2084
- package/test/server/Hub.test.js +0 -497
- package/test/server/Log.test.js +0 -73
- package/test/server/Mail.account.test_.js +0 -460
- package/test/server/Mail.init.test_.js +0 -411
- package/test/server/Mail.test_.js +0 -1340
- package/test/server/SSL.test_.js +0 -1491
- package/test/server/Server.test.js +0 -765
- package/test/server/Service.test_.js +0 -1127
- package/test/server/Subdomain.test.js +0 -440
- package/test/server/Web/Firewall.test.js +0 -175
- package/test/server/Web/Proxy.test.js +0 -397
- package/test/server/Web.test.js +0 -1494
- package/test/server/__mocks__/acme-client.js +0 -17
- package/test/server/__mocks__/bcrypt.js +0 -50
- package/test/server/__mocks__/child_process.js +0 -389
- package/test/server/__mocks__/crypto.js +0 -432
- package/test/server/__mocks__/fs.js +0 -450
- package/test/server/__mocks__/globalOdac.js +0 -227
- package/test/server/__mocks__/http.js +0 -575
- package/test/server/__mocks__/https.js +0 -272
- package/test/server/__mocks__/index.js +0 -249
- package/test/server/__mocks__/mail/server.js +0 -100
- package/test/server/__mocks__/mail/smtp.js +0 -31
- package/test/server/__mocks__/mailparser.js +0 -81
- package/test/server/__mocks__/net.js +0 -369
- package/test/server/__mocks__/node-forge.js +0 -328
- package/test/server/__mocks__/os.js +0 -320
- package/test/server/__mocks__/path.js +0 -291
- package/test/server/__mocks__/selfsigned.js +0 -8
- package/test/server/__mocks__/server/src/mail/server.js +0 -100
- package/test/server/__mocks__/server/src/mail/smtp.js +0 -31
- package/test/server/__mocks__/smtp-server.js +0 -106
- package/test/server/__mocks__/sqlite3.js +0 -394
- package/test/server/__mocks__/testFactories.js +0 -299
- package/test/server/__mocks__/testHelpers.js +0 -363
- package/test/server/__mocks__/tls.js +0 -229
- /package/template/{config.json → odac.json} +0 -0
|
@@ -1,397 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for Web/Proxy.js module
|
|
3
|
-
* Tests custom HTTP proxy implementation for both HTTP/1 and HTTP/2
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
jest.mock('http')
|
|
7
|
-
|
|
8
|
-
const http = require('http')
|
|
9
|
-
const WebProxy = require('../../../server/src/Web/Proxy.js')
|
|
10
|
-
|
|
11
|
-
describe('WebProxy', () => {
|
|
12
|
-
let proxy
|
|
13
|
-
let mockLog
|
|
14
|
-
let mockReq
|
|
15
|
-
let mockRes
|
|
16
|
-
let mockWebsite
|
|
17
|
-
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
jest.clearAllMocks()
|
|
20
|
-
|
|
21
|
-
mockLog = jest.fn()
|
|
22
|
-
proxy = new WebProxy(mockLog)
|
|
23
|
-
|
|
24
|
-
mockReq = {
|
|
25
|
-
url: '/test',
|
|
26
|
-
method: 'GET',
|
|
27
|
-
headers: {
|
|
28
|
-
host: 'example.com',
|
|
29
|
-
'user-agent': 'test-agent'
|
|
30
|
-
},
|
|
31
|
-
socket: {
|
|
32
|
-
remoteAddress: '192.168.1.100'
|
|
33
|
-
},
|
|
34
|
-
setTimeout: jest.fn(),
|
|
35
|
-
on: jest.fn(),
|
|
36
|
-
pipe: jest.fn()
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
mockRes = {
|
|
40
|
-
writeHead: jest.fn(),
|
|
41
|
-
end: jest.fn(),
|
|
42
|
-
setTimeout: jest.fn(),
|
|
43
|
-
on: jest.fn(),
|
|
44
|
-
headersSent: false,
|
|
45
|
-
writeEarlyHints: jest.fn()
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
mockWebsite = {
|
|
49
|
-
port: 3000,
|
|
50
|
-
domain: 'example.com'
|
|
51
|
-
}
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
describe('http1 proxy', () => {
|
|
55
|
-
test('should create HTTP request with correct options', () => {
|
|
56
|
-
const mockProxyReq = {
|
|
57
|
-
on: jest.fn(),
|
|
58
|
-
pipe: jest.fn()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
http.request.mockReturnValue(mockProxyReq)
|
|
62
|
-
|
|
63
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
64
|
-
|
|
65
|
-
expect(http.request).toHaveBeenCalledWith(
|
|
66
|
-
expect.objectContaining({
|
|
67
|
-
hostname: '127.0.0.1',
|
|
68
|
-
port: 3000,
|
|
69
|
-
path: '/test',
|
|
70
|
-
method: 'GET',
|
|
71
|
-
timeout: 0
|
|
72
|
-
}),
|
|
73
|
-
expect.any(Function)
|
|
74
|
-
)
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
test('should add custom headers to proxy request', () => {
|
|
78
|
-
const mockProxyReq = {
|
|
79
|
-
on: jest.fn(),
|
|
80
|
-
pipe: jest.fn()
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
http.request.mockReturnValue(mockProxyReq)
|
|
84
|
-
|
|
85
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
86
|
-
|
|
87
|
-
const options = http.request.mock.calls[0][0]
|
|
88
|
-
expect(options.headers).toMatchObject({
|
|
89
|
-
host: 'example.com',
|
|
90
|
-
'user-agent': 'test-agent',
|
|
91
|
-
'x-odac-connection-remoteaddress': '192.168.1.100',
|
|
92
|
-
'x-odac-connection-ssl': 'true'
|
|
93
|
-
})
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
test('should handle proxy connection errors', () => {
|
|
97
|
-
const mockProxyReq = {
|
|
98
|
-
on: jest.fn(),
|
|
99
|
-
pipe: jest.fn()
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
http.request.mockReturnValue(mockProxyReq)
|
|
103
|
-
|
|
104
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
105
|
-
|
|
106
|
-
const errorHandler = mockProxyReq.on.mock.calls.find(call => call[0] === 'error')[1]
|
|
107
|
-
const error = new Error('Connection refused')
|
|
108
|
-
error.code = 'ECONNREFUSED'
|
|
109
|
-
|
|
110
|
-
errorHandler(error)
|
|
111
|
-
|
|
112
|
-
expect(mockLog).toHaveBeenCalledWith('Proxy error for example.com: Connection refused')
|
|
113
|
-
expect(mockRes.writeHead).toHaveBeenCalledWith(502)
|
|
114
|
-
expect(mockRes.end).toHaveBeenCalledWith('Bad Gateway')
|
|
115
|
-
})
|
|
116
|
-
|
|
117
|
-
test('should not send error response if headers already sent', () => {
|
|
118
|
-
const mockProxyReq = {
|
|
119
|
-
on: jest.fn(),
|
|
120
|
-
pipe: jest.fn()
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
http.request.mockReturnValue(mockProxyReq)
|
|
124
|
-
mockRes.headersSent = true
|
|
125
|
-
|
|
126
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
127
|
-
|
|
128
|
-
const errorHandler = mockProxyReq.on.mock.calls.find(call => call[0] === 'error')[1]
|
|
129
|
-
const error = new Error('Connection timeout')
|
|
130
|
-
|
|
131
|
-
errorHandler(error)
|
|
132
|
-
|
|
133
|
-
expect(mockLog).toHaveBeenCalledWith('Proxy error for example.com: Connection timeout')
|
|
134
|
-
expect(mockRes.writeHead).not.toHaveBeenCalled()
|
|
135
|
-
expect(mockRes.end).not.toHaveBeenCalledWith('Bad Gateway')
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
test('should ignore ECONNRESET errors', () => {
|
|
139
|
-
const mockProxyReq = {
|
|
140
|
-
on: jest.fn(),
|
|
141
|
-
pipe: jest.fn()
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
http.request.mockReturnValue(mockProxyReq)
|
|
145
|
-
|
|
146
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
147
|
-
|
|
148
|
-
const errorHandler = mockProxyReq.on.mock.calls.find(call => call[0] === 'error')[1]
|
|
149
|
-
const error = new Error('Connection reset')
|
|
150
|
-
error.code = 'ECONNRESET'
|
|
151
|
-
|
|
152
|
-
errorHandler(error)
|
|
153
|
-
|
|
154
|
-
expect(mockLog).not.toHaveBeenCalled()
|
|
155
|
-
expect(mockRes.writeHead).not.toHaveBeenCalled()
|
|
156
|
-
})
|
|
157
|
-
|
|
158
|
-
test('should filter forbidden response headers', done => {
|
|
159
|
-
const mockProxyRes = {
|
|
160
|
-
statusCode: 200,
|
|
161
|
-
headers: {
|
|
162
|
-
'content-type': 'application/json',
|
|
163
|
-
connection: 'keep-alive',
|
|
164
|
-
'keep-alive': 'timeout=5',
|
|
165
|
-
'transfer-encoding': 'chunked',
|
|
166
|
-
upgrade: 'websocket',
|
|
167
|
-
'proxy-connection': 'keep-alive',
|
|
168
|
-
'x-custom-header': 'value'
|
|
169
|
-
},
|
|
170
|
-
pipe: jest.fn()
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const mockProxyReq = {
|
|
174
|
-
on: jest.fn(),
|
|
175
|
-
pipe: jest.fn()
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
http.request.mockImplementation((options, callback) => {
|
|
179
|
-
setTimeout(() => callback(mockProxyRes), 0)
|
|
180
|
-
return mockProxyReq
|
|
181
|
-
})
|
|
182
|
-
|
|
183
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
184
|
-
|
|
185
|
-
setTimeout(() => {
|
|
186
|
-
expect(mockRes.writeHead).toHaveBeenCalledWith(
|
|
187
|
-
200,
|
|
188
|
-
expect.objectContaining({
|
|
189
|
-
'content-type': 'application/json',
|
|
190
|
-
'x-custom-header': 'value'
|
|
191
|
-
})
|
|
192
|
-
)
|
|
193
|
-
|
|
194
|
-
const headers = mockRes.writeHead.mock.calls[0][1]
|
|
195
|
-
expect(headers).not.toHaveProperty('connection')
|
|
196
|
-
expect(headers).not.toHaveProperty('keep-alive')
|
|
197
|
-
expect(headers).not.toHaveProperty('transfer-encoding')
|
|
198
|
-
expect(headers).not.toHaveProperty('upgrade')
|
|
199
|
-
expect(headers).not.toHaveProperty('proxy-connection')
|
|
200
|
-
done()
|
|
201
|
-
}, 10)
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
test('should handle Server-Sent Events connections', done => {
|
|
205
|
-
const mockProxyRes = {
|
|
206
|
-
statusCode: 200,
|
|
207
|
-
headers: {
|
|
208
|
-
'content-type': 'text/event-stream'
|
|
209
|
-
},
|
|
210
|
-
pipe: jest.fn()
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
const mockProxyReq = {
|
|
214
|
-
on: jest.fn(),
|
|
215
|
-
pipe: jest.fn(),
|
|
216
|
-
destroy: jest.fn()
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
http.request.mockImplementation((options, callback) => {
|
|
220
|
-
setTimeout(() => callback(mockProxyRes), 0)
|
|
221
|
-
return mockProxyReq
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
225
|
-
|
|
226
|
-
setTimeout(() => {
|
|
227
|
-
expect(mockReq.setTimeout).toHaveBeenCalledWith(0)
|
|
228
|
-
expect(mockRes.setTimeout).toHaveBeenCalledWith(0)
|
|
229
|
-
expect(mockReq.on).toHaveBeenCalledWith('close', expect.any(Function))
|
|
230
|
-
expect(mockReq.on).toHaveBeenCalledWith('aborted', expect.any(Function))
|
|
231
|
-
expect(mockRes.on).toHaveBeenCalledWith('close', expect.any(Function))
|
|
232
|
-
done()
|
|
233
|
-
}, 10)
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
test('should handle early hints', done => {
|
|
237
|
-
const mockProxyRes = {
|
|
238
|
-
statusCode: 200,
|
|
239
|
-
headers: {
|
|
240
|
-
'content-type': 'text/html',
|
|
241
|
-
'x-odac-early-hints': JSON.stringify(['</style.css>; rel=preload; as=style'])
|
|
242
|
-
},
|
|
243
|
-
pipe: jest.fn()
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
const mockProxyReq = {
|
|
247
|
-
on: jest.fn(),
|
|
248
|
-
pipe: jest.fn()
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
http.request.mockImplementation((options, callback) => {
|
|
252
|
-
setTimeout(() => callback(mockProxyRes), 0)
|
|
253
|
-
return mockProxyReq
|
|
254
|
-
})
|
|
255
|
-
|
|
256
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
257
|
-
|
|
258
|
-
setTimeout(() => {
|
|
259
|
-
expect(mockRes.writeEarlyHints).toHaveBeenCalledWith({
|
|
260
|
-
link: ['</style.css>; rel=preload; as=style']
|
|
261
|
-
})
|
|
262
|
-
|
|
263
|
-
const headers = mockRes.writeHead.mock.calls[0][1]
|
|
264
|
-
expect(headers).not.toHaveProperty('x-odac-early-hints')
|
|
265
|
-
done()
|
|
266
|
-
}, 10)
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
test('should ignore invalid early hints JSON', done => {
|
|
270
|
-
const mockProxyRes = {
|
|
271
|
-
statusCode: 200,
|
|
272
|
-
headers: {
|
|
273
|
-
'content-type': 'text/html',
|
|
274
|
-
'x-odac-early-hints': 'invalid-json'
|
|
275
|
-
},
|
|
276
|
-
pipe: jest.fn()
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
const mockProxyReq = {
|
|
280
|
-
on: jest.fn(),
|
|
281
|
-
pipe: jest.fn()
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
http.request.mockImplementation((options, callback) => {
|
|
285
|
-
setTimeout(() => callback(mockProxyRes), 0)
|
|
286
|
-
return mockProxyReq
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
290
|
-
|
|
291
|
-
setTimeout(() => {
|
|
292
|
-
expect(mockRes.writeEarlyHints).not.toHaveBeenCalled()
|
|
293
|
-
expect(mockRes.writeHead).toHaveBeenCalled()
|
|
294
|
-
done()
|
|
295
|
-
}, 10)
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
test('should pipe request to proxy', () => {
|
|
299
|
-
const mockProxyReq = {
|
|
300
|
-
on: jest.fn(),
|
|
301
|
-
pipe: jest.fn()
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
http.request.mockReturnValue(mockProxyReq)
|
|
305
|
-
|
|
306
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
307
|
-
|
|
308
|
-
expect(mockReq.pipe).toHaveBeenCalledWith(mockProxyReq)
|
|
309
|
-
})
|
|
310
|
-
|
|
311
|
-
test('should pipe proxy response to client', done => {
|
|
312
|
-
const mockProxyRes = {
|
|
313
|
-
statusCode: 200,
|
|
314
|
-
headers: {'content-type': 'text/plain'},
|
|
315
|
-
pipe: jest.fn()
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
const mockProxyReq = {
|
|
319
|
-
on: jest.fn(),
|
|
320
|
-
pipe: jest.fn()
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
http.request.mockImplementation((options, callback) => {
|
|
324
|
-
setTimeout(() => callback(mockProxyRes), 0)
|
|
325
|
-
return mockProxyReq
|
|
326
|
-
})
|
|
327
|
-
|
|
328
|
-
proxy.http1(mockReq, mockRes, mockWebsite, 'example.com')
|
|
329
|
-
|
|
330
|
-
setTimeout(() => {
|
|
331
|
-
expect(mockProxyRes.pipe).toHaveBeenCalledWith(mockRes)
|
|
332
|
-
done()
|
|
333
|
-
}, 10)
|
|
334
|
-
})
|
|
335
|
-
})
|
|
336
|
-
|
|
337
|
-
describe('http2 proxy', () => {
|
|
338
|
-
test('should filter HTTP/2 pseudo-headers', () => {
|
|
339
|
-
mockReq.headers[':method'] = 'GET'
|
|
340
|
-
mockReq.headers[':path'] = '/test'
|
|
341
|
-
mockReq.headers[':scheme'] = 'https'
|
|
342
|
-
mockReq.headers[':authority'] = 'example.com'
|
|
343
|
-
|
|
344
|
-
const mockProxyReq = {
|
|
345
|
-
on: jest.fn(),
|
|
346
|
-
pipe: jest.fn()
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
http.request.mockReturnValue(mockProxyReq)
|
|
350
|
-
|
|
351
|
-
proxy.http2(mockReq, mockRes, mockWebsite, 'example.com')
|
|
352
|
-
|
|
353
|
-
const options = http.request.mock.calls[0][0]
|
|
354
|
-
expect(options.headers).not.toHaveProperty(':method')
|
|
355
|
-
expect(options.headers).not.toHaveProperty(':path')
|
|
356
|
-
expect(options.headers).not.toHaveProperty(':scheme')
|
|
357
|
-
expect(options.headers).not.toHaveProperty(':authority')
|
|
358
|
-
expect(options.headers).toHaveProperty('user-agent')
|
|
359
|
-
})
|
|
360
|
-
|
|
361
|
-
test('should handle HTTP/2 proxy errors', () => {
|
|
362
|
-
const mockProxyReq = {
|
|
363
|
-
on: jest.fn(),
|
|
364
|
-
pipe: jest.fn()
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
http.request.mockReturnValue(mockProxyReq)
|
|
368
|
-
|
|
369
|
-
proxy.http2(mockReq, mockRes, mockWebsite, 'example.com')
|
|
370
|
-
|
|
371
|
-
const errorHandler = mockProxyReq.on.mock.calls.find(call => call[0] === 'error')[1]
|
|
372
|
-
const error = new Error('Connection failed')
|
|
373
|
-
|
|
374
|
-
errorHandler(error)
|
|
375
|
-
|
|
376
|
-
expect(mockLog).toHaveBeenCalledWith('Proxy error for example.com: Connection failed')
|
|
377
|
-
expect(mockRes.writeHead).toHaveBeenCalledWith(502)
|
|
378
|
-
expect(mockRes.end).toHaveBeenCalledWith('Bad Gateway')
|
|
379
|
-
})
|
|
380
|
-
|
|
381
|
-
test('should handle missing remote address', () => {
|
|
382
|
-
mockReq.socket = {}
|
|
383
|
-
|
|
384
|
-
const mockProxyReq = {
|
|
385
|
-
on: jest.fn(),
|
|
386
|
-
pipe: jest.fn()
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
http.request.mockReturnValue(mockProxyReq)
|
|
390
|
-
|
|
391
|
-
proxy.http2(mockReq, mockRes, mockWebsite, 'example.com')
|
|
392
|
-
|
|
393
|
-
const options = http.request.mock.calls[0][0]
|
|
394
|
-
expect(options.headers['x-odac-connection-remoteaddress']).toBe('')
|
|
395
|
-
})
|
|
396
|
-
})
|
|
397
|
-
})
|