overleaf/libraries/fetch-utils/test/unit/helpers/TestServer.js

131 lines
3.2 KiB
JavaScript
Raw Normal View History

const express = require('express')
const bodyParser = require('body-parser')
const { EventEmitter } = require('node:events')
const http = require('node:http')
const https = require('node:https')
const { promisify } = require('node:util')
class TestServer {
constructor() {
this.app = express()
[fetch-utils] Fix unit tests (#20210) * [fetch-utils] Fix FetchUtilsTests.js tests * Cleanup between tests * Define `AbortError` * [fetch-utils] Add `expectConnectionCount` showcasing that the connection stays on when the stream is destroyed * Revert "[fetch-utils] Add `expectConnectionCount` showcasing that the connection stays on when the stream is destroyed" This reverts commit b10da7b3fc06a7345df8fd70f27fad70a478bbb4. * [fetch-utils] Fix `supports abort signals` test * [fetch-utils] Add tests "aborts the request when the request body is destroyed during transfer" * [fetch-utils] Add extra waiting step before `expectRequestAborted` * [fetch-utils] Add `while (!req?.destroyed) await wait(10)` Unfortunately I couldn't find a better event to await. To try with this to test flakiness ``` for i in {1..100}; do npm run test:unit || break; echo "Run $i completed"; done ``` * [fetch-utils] Replace arbitrary `wait(10)` by `this.server.waitForEvent('request-received')` * [fetch-utils] Improve tests per PR comments See https://github.com/overleaf/internal/pull/20210 1. Replace `waitForEvent` with `once` 2. Replace `waitForRequestAborted` by `expectRequestAborted` 3. Add comment in `expectRequestAborted` empty catch block Non-flakiness rechecked with `for i in {1..100}; do npm run test:unit || break; echo "Run $i completed"; done` * [fetch-utils] Add small wait before checking `lastReq === undefined` Per https://github.com/overleaf/internal/pull/20210#discussion_r1743329462 GitOrigin-RevId: 5fe542e0a8e6011307e03237e2f81404d9a0e674
2024-09-04 09:30:16 -04:00
this.events = new EventEmitter()
this.app.use(bodyParser.json())
this.app.use((req, res, next) => {
this.events.emit('request-received')
this.lastReq = req
next()
})
// Plain text endpoints
this.app.get('/hello', (req, res) => {
res.send('hello')
})
this.largePayload = 'x'.repeat(16 * 1024 * 1024)
this.app.get('/large', (req, res) => {
res.send(this.largePayload)
})
this.app.get('/204', (req, res) => {
res.status(204).end()
})
this.app.get('/empty', (req, res) => {
res.end()
})
this.app.get('/500', (req, res) => {
res.sendStatus(500)
})
this.app.post('/sink', (req, res) => {
req.on('data', () => {})
req.on('end', () => {
res.status(204).end()
})
})
// JSON endpoints
this.app.get('/json/hello', (req, res) => {
res.json({ msg: 'hello' })
})
this.app.post('/json/add', (req, res) => {
const { a, b } = req.body
res.json({ sum: a + b })
})
this.app.get('/json/500', (req, res) => {
res.status(500).json({ error: 'Internal server error' })
})
this.app.get('/json/basic-auth', (req, res) => {
const expectedAuth =
'Basic ' + Buffer.from('user:pass').toString('base64')
if (req.headers.authorization === expectedAuth) {
res.json({ key: 'verysecret' })
} else {
res.status(401).json({ error: 'unauthorized' })
}
})
this.app.post('/json/ignore-request', (req, res) => {
res.json({ msg: 'hello' })
})
// Never returns
[fetch-utils] Fix unit tests (#20210) * [fetch-utils] Fix FetchUtilsTests.js tests * Cleanup between tests * Define `AbortError` * [fetch-utils] Add `expectConnectionCount` showcasing that the connection stays on when the stream is destroyed * Revert "[fetch-utils] Add `expectConnectionCount` showcasing that the connection stays on when the stream is destroyed" This reverts commit b10da7b3fc06a7345df8fd70f27fad70a478bbb4. * [fetch-utils] Fix `supports abort signals` test * [fetch-utils] Add tests "aborts the request when the request body is destroyed during transfer" * [fetch-utils] Add extra waiting step before `expectRequestAborted` * [fetch-utils] Add `while (!req?.destroyed) await wait(10)` Unfortunately I couldn't find a better event to await. To try with this to test flakiness ``` for i in {1..100}; do npm run test:unit || break; echo "Run $i completed"; done ``` * [fetch-utils] Replace arbitrary `wait(10)` by `this.server.waitForEvent('request-received')` * [fetch-utils] Improve tests per PR comments See https://github.com/overleaf/internal/pull/20210 1. Replace `waitForEvent` with `once` 2. Replace `waitForRequestAborted` by `expectRequestAborted` 3. Add comment in `expectRequestAborted` empty catch block Non-flakiness rechecked with `for i in {1..100}; do npm run test:unit || break; echo "Run $i completed"; done` * [fetch-utils] Add small wait before checking `lastReq === undefined` Per https://github.com/overleaf/internal/pull/20210#discussion_r1743329462 GitOrigin-RevId: 5fe542e0a8e6011307e03237e2f81404d9a0e674
2024-09-04 09:30:16 -04:00
this.app.get('/hang', (req, res) => {})
this.app.post('/hang', (req, res) => {})
// Redirect
this.app.get('/redirect/1', (req, res) => {
res.redirect('/redirect/2')
})
this.app.get('/redirect/2', (req, res) => {
res.send('body after redirect')
})
this.app.get('/redirect/empty-location', (req, res) => {
res.sendStatus(302)
})
}
start(port, httpsPort, httpsOptions) {
const startHttp = new Promise((resolve, reject) => {
this.server = http.createServer(this.app).listen(port, err => {
if (err) {
reject(err)
} else {
resolve()
}
})
})
const startHttps = new Promise((resolve, reject) => {
this.https_server = https
.createServer(httpsOptions, this.app)
.listen(httpsPort, err => {
if (err) {
reject(err)
} else {
resolve()
}
})
})
return Promise.all([startHttp, startHttps])
}
stop() {
const stopHttp = promisify(this.server.close).bind(this.server)
const stopHttps = promisify(this.https_server.close).bind(this.https_server)
[fetch-utils] Fix unit tests (#20210) * [fetch-utils] Fix FetchUtilsTests.js tests * Cleanup between tests * Define `AbortError` * [fetch-utils] Add `expectConnectionCount` showcasing that the connection stays on when the stream is destroyed * Revert "[fetch-utils] Add `expectConnectionCount` showcasing that the connection stays on when the stream is destroyed" This reverts commit b10da7b3fc06a7345df8fd70f27fad70a478bbb4. * [fetch-utils] Fix `supports abort signals` test * [fetch-utils] Add tests "aborts the request when the request body is destroyed during transfer" * [fetch-utils] Add extra waiting step before `expectRequestAborted` * [fetch-utils] Add `while (!req?.destroyed) await wait(10)` Unfortunately I couldn't find a better event to await. To try with this to test flakiness ``` for i in {1..100}; do npm run test:unit || break; echo "Run $i completed"; done ``` * [fetch-utils] Replace arbitrary `wait(10)` by `this.server.waitForEvent('request-received')` * [fetch-utils] Improve tests per PR comments See https://github.com/overleaf/internal/pull/20210 1. Replace `waitForEvent` with `once` 2. Replace `waitForRequestAborted` by `expectRequestAborted` 3. Add comment in `expectRequestAborted` empty catch block Non-flakiness rechecked with `for i in {1..100}; do npm run test:unit || break; echo "Run $i completed"; done` * [fetch-utils] Add small wait before checking `lastReq === undefined` Per https://github.com/overleaf/internal/pull/20210#discussion_r1743329462 GitOrigin-RevId: 5fe542e0a8e6011307e03237e2f81404d9a0e674
2024-09-04 09:30:16 -04:00
this.server.closeAllConnections()
this.https_server.closeAllConnections()
return Promise.all([stopHttp(), stopHttps()])
}
}
module.exports = { TestServer }