mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-11-13 21:53:43 +01:00
Merge pull request #14029 from overleaf/bg-csh-kustomize-spelling-2
kustomize spelling GitOrigin-RevId: 5b5203c5de92c3443741cabc081df7afe1063e71
This commit is contained in:
committed by
Copybot
parent
8763e991b0
commit
ec47cf45cd
@@ -0,0 +1,4 @@
|
||||
const chai = require('chai')
|
||||
const chaiAsPromised = require('chai-as-promised')
|
||||
|
||||
chai.use(chaiAsPromised)
|
||||
@@ -0,0 +1,230 @@
|
||||
const { expect } = require('chai')
|
||||
const { FetchError, AbortError } = require('node-fetch')
|
||||
const { Readable } = require('stream')
|
||||
const { once } = require('events')
|
||||
const { TestServer } = require('./helpers/TestServer')
|
||||
const {
|
||||
fetchJson,
|
||||
fetchStream,
|
||||
fetchNothing,
|
||||
fetchString,
|
||||
RequestFailedError,
|
||||
} = require('../..')
|
||||
|
||||
const PORT = 30001
|
||||
|
||||
describe('fetch-utils', function () {
|
||||
before(async function () {
|
||||
this.server = new TestServer()
|
||||
await this.server.start(PORT)
|
||||
this.url = path => `http://localhost:${PORT}${path}`
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
await this.server.stop()
|
||||
})
|
||||
|
||||
describe('fetchJson', function () {
|
||||
it('parses a JSON response', async function () {
|
||||
const json = await fetchJson(this.url('/json/hello'))
|
||||
expect(json).to.deep.equal({ msg: 'hello' })
|
||||
})
|
||||
|
||||
it('parses JSON in the request', async function () {
|
||||
const json = await fetchJson(this.url('/json/add'), {
|
||||
method: 'POST',
|
||||
json: { a: 2, b: 3 },
|
||||
})
|
||||
expect(json).to.deep.equal({ sum: 5 })
|
||||
})
|
||||
|
||||
it('accepts stringified JSON as body', async function () {
|
||||
const json = await fetchJson(this.url('/json/add'), {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ a: 2, b: 3 }),
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
})
|
||||
expect(json).to.deep.equal({ sum: 5 })
|
||||
})
|
||||
|
||||
it('throws a FetchError when the payload is not JSON', async function () {
|
||||
await expect(fetchJson(this.url('/hello'))).to.be.rejectedWith(FetchError)
|
||||
})
|
||||
|
||||
it('aborts the request if JSON parsing fails', async function () {
|
||||
await expect(fetchJson(this.url('/large'))).to.be.rejectedWith(FetchError)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('handles errors when the payload is JSON', async function () {
|
||||
await expect(fetchJson(this.url('/json/500'))).to.be.rejectedWith(
|
||||
RequestFailedError
|
||||
)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('handles errors when the payload is not JSON', async function () {
|
||||
await expect(fetchJson(this.url('/500'))).to.be.rejectedWith(
|
||||
RequestFailedError
|
||||
)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('supports abort signals', async function () {
|
||||
await expect(
|
||||
fetchJson(this.url('/hang'), { signal: AbortSignal.timeout(10) })
|
||||
).to.be.rejectedWith(AbortError)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('supports basic auth', async function () {
|
||||
const json = await fetchJson(this.url('/json/basic-auth'), {
|
||||
basicAuth: { user: 'user', password: 'pass' },
|
||||
})
|
||||
expect(json).to.deep.equal({ key: 'verysecret' })
|
||||
})
|
||||
|
||||
it("destroys the request body if it doesn't get consumed", async function () {
|
||||
const stream = Readable.from(infiniteIterator())
|
||||
await fetchJson(this.url('/json/ignore-request'), {
|
||||
method: 'POST',
|
||||
body: stream,
|
||||
})
|
||||
expect(stream.destroyed).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
describe('fetchStream', function () {
|
||||
it('returns a stream', async function () {
|
||||
const stream = await fetchStream(this.url('/large'))
|
||||
const text = await streamToString(stream)
|
||||
expect(text).to.equal(this.server.largePayload)
|
||||
})
|
||||
|
||||
it('aborts the request when the stream is destroyed', async function () {
|
||||
const stream = await fetchStream(this.url('/large'))
|
||||
stream.destroy()
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('aborts the request when the request body is destroyed', async function () {
|
||||
const stream = Readable.from(infiniteIterator())
|
||||
const promise = fetchStream(this.url('/hang'), {
|
||||
method: 'POST',
|
||||
body: stream,
|
||||
})
|
||||
stream.destroy()
|
||||
await expect(promise).to.be.rejectedWith(AbortError)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('handles errors', async function () {
|
||||
await expect(fetchStream(this.url('/500'))).to.be.rejectedWith(
|
||||
RequestFailedError
|
||||
)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('supports abort signals', async function () {
|
||||
await expect(
|
||||
fetchStream(this.url('/hang'), { signal: AbortSignal.timeout(10) })
|
||||
).to.be.rejectedWith(AbortError)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('destroys the request body when an error occurs', async function () {
|
||||
const stream = Readable.from(infiniteIterator())
|
||||
await expect(
|
||||
fetchStream(this.url('/hang'), {
|
||||
body: stream,
|
||||
signal: AbortSignal.timeout(10),
|
||||
})
|
||||
).to.be.rejectedWith(AbortError)
|
||||
expect(stream.destroyed).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
describe('fetchNothing', function () {
|
||||
it('closes the connection', async function () {
|
||||
await fetchNothing(this.url('/large'))
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('aborts the request when the request body is destroyed', async function () {
|
||||
const stream = Readable.from(infiniteIterator())
|
||||
const promise = fetchNothing(this.url('/hang'), {
|
||||
method: 'POST',
|
||||
body: stream,
|
||||
})
|
||||
stream.destroy()
|
||||
await expect(promise).to.be.rejectedWith(AbortError)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it("doesn't abort the request if the request body ends normally", async function () {
|
||||
const stream = Readable.from('hello there')
|
||||
await fetchNothing(this.url('/sink'), { method: 'POST', body: stream })
|
||||
})
|
||||
|
||||
it('handles errors', async function () {
|
||||
await expect(fetchNothing(this.url('/500'))).to.be.rejectedWith(
|
||||
RequestFailedError
|
||||
)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('supports abort signals', async function () {
|
||||
await expect(
|
||||
fetchNothing(this.url('/hang'), { signal: AbortSignal.timeout(10) })
|
||||
).to.be.rejectedWith(AbortError)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
|
||||
it('destroys the request body when an error occurs', async function () {
|
||||
const stream = Readable.from(infiniteIterator())
|
||||
await expect(
|
||||
fetchNothing(this.url('/hang'), {
|
||||
body: stream,
|
||||
signal: AbortSignal.timeout(10),
|
||||
})
|
||||
).to.be.rejectedWith(AbortError)
|
||||
expect(stream.destroyed).to.be.true
|
||||
})
|
||||
})
|
||||
|
||||
describe('fetchString', function () {
|
||||
it('returns a string', async function () {
|
||||
const body = await fetchString(this.url('/hello'))
|
||||
expect(body).to.equal('hello')
|
||||
})
|
||||
|
||||
it('handles errors', async function () {
|
||||
await expect(fetchJson(this.url('/500'))).to.be.rejectedWith(
|
||||
RequestFailedError
|
||||
)
|
||||
await expectRequestAborted(this.server.lastReq)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
async function streamToString(stream) {
|
||||
let s = ''
|
||||
for await (const chunk of stream) {
|
||||
s += chunk
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
async function* infiniteIterator() {
|
||||
let i = 1
|
||||
while (true) {
|
||||
yield `chunk ${i++}\n`
|
||||
}
|
||||
}
|
||||
|
||||
async function expectRequestAborted(req) {
|
||||
if (!req.destroyed) {
|
||||
await once(req, 'close')
|
||||
expect(req.destroyed).to.be.true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
const express = require('express')
|
||||
const bodyParser = require('body-parser')
|
||||
|
||||
class TestServer {
|
||||
constructor(port) {
|
||||
this.app = express()
|
||||
|
||||
this.app.use(bodyParser.json())
|
||||
this.app.use((req, res, next) => {
|
||||
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
|
||||
|
||||
this.app.post('/hang', (req, res) => {})
|
||||
}
|
||||
|
||||
start(port) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.server = this.app.listen(port, err => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
stop() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.server.close(err => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { TestServer }
|
||||
Reference in New Issue
Block a user