service-core/test/client.test.mjs

285 lines
8.1 KiB
JavaScript

import { Eltro as t, assert} from 'eltro'
import fs from 'fs/promises'
import http from 'http'
import Util from '../core/util.mjs'
import { request } from '../core/client.mjs'
const util = new Util(import.meta.url)
const testTargetFile = util.getPathFromRoot('./filetest.html')
const port = 61412
const defaultHandler = function(req, res) {
res.statusCode = 200
res.end('{"a":1}');
}
let server = null
let prefix = `http://localhost:${port}/`
let handler = defaultHandler
t.before(function(cb) {
server = http.createServer(function(req, res) {
req.on('error', function(err) {
console.log('error', err)
})
res.on('error', function(err) {
console.log('error', err)
})
handler(req, res)
})
server.listen(port, cb)
})
t.after(function() {
return fs.rm(testTargetFile)
.catch(function() { })
})
t.describe('Basics', function() {
t.beforeEach(function() {
handler = defaultHandler
})
t.test('should require valid config', async function() {
function checkError(err) {
assert.match(err.message, /config/i)
}
await assert.isRejected(request(prefix)).then(checkError)
await assert.isRejected(request('', prefix)).then(checkError)
await assert.isRejected(request([], prefix)).then(checkError)
await assert.isRejected(request(123, prefix)).then(checkError)
await assert.isRejected(request(0, prefix)).then(checkError)
})
t.test('should fail if url is invalid', async function() {
function checkError(check, err) {
assert.match(err.message, /invalid/i)
assert.match(err.message, /url/i)
if (check) {
assert.match(err.message, new RegExp(check))
}
}
await assert.isRejected(request({}, 123)).then(checkError.bind(this, null))
await assert.isRejected(request({}, [])).then(checkError.bind(this, null))
await assert.isRejected(request({}, {})).then(checkError.bind(this, null))
await assert.isRejected(request({}, '')).then(checkError.bind(this, null))
await assert.isRejected(request({}, 'asdf')).then(checkError.bind(this, 'asdf'))
await assert.isRejected(request({}, 'httpppp')).then(checkError.bind(this, 'httpppp'))
})
})
t.describe('Request', function() {
t.test('should work normally', async function() {
let res = await request({}, prefix)
assert.deepEqual(res.body, {a:1})
})
t.test('should follow redirects', async function() {
let counter = 0
handler = function(req, res) {
if (counter < 3) {
res.statusCode = 302
res.setHeader('Location', encodeURI(prefix))
res.end();
counter++
return
}
assert.strictEqual(req.url, '/')
res.statusCode = 200
res.end('{"a":1}');
return
}
let res = await request({}, prefix)
assert.deepEqual(res.body, {a:1})
assert.strictEqual(counter, 3)
})
t.test('should fail gracefully if HTML is received', async function() {
handler = function(req, res) {
res.statusCode = 200
res.end(`<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
</body>
</html>`);
}
let err = await assert.isRejected(request({}, prefix))
assert.match(err.message, /html/i)
assert.notMatch(err.message, /Unexpected token/i)
handler = function(req, res) {
res.statusCode = 200
res.end(`<html>
<head>
</head>
<body>
</body>
</html>`);
}
err = await assert.isRejected(request({}, prefix))
assert.match(err.message, /html/i)
assert.notMatch(err.message, /Unexpected token/i)
})
t.test('should fail if infinite redirect', async function() {
const assertRelativeLocation = 'some/text/here'
const assertLocation = prefix + assertRelativeLocation
let counter = 0
handler = function(req, res) {
res.statusCode = 302
res.setHeader('Location', encodeURI(assertLocation))
if (counter === 0) {
assert.strictEqual(req.url, '/')
} else {
assert.strictEqual(req.url, '/' + assertRelativeLocation)
}
res.end();
counter++
}
let err = await assert.isRejected(request({}, prefix))
assert.strictEqual(counter, 6)
assert.match(err.message, /redirect/i)
assert.match(err.message, new RegExp(assertRelativeLocation))
})
t.test('should fail if redirect is missing location', async function() {
let counter = 0
handler = function(req, res) {
res.statusCode = 302
res.end();
counter++
}
let err = await assert.isRejected(request({}, prefix))
assert.strictEqual(counter, 1)
assert.match(err.message, /redirect/i)
assert.match(err.message, /location/i)
})
t.test('should follow relative redirects', async function() {
const assertUrl = 'asdf1234'
let counter = 0
let url = ''
handler = function(req, res) {
if (counter < 1) {
res.statusCode = 302
res.setHeader('Location', encodeURI(assertUrl))
res.end();
counter++
return
}
url = req.url
res.statusCode = 200
res.end('{"a":1}');
return
}
let res = await request({}, prefix)
assert.deepEqual(res.body, {a:1})
assert.strictEqual(counter, 1)
assert.strictEqual(url, '/' + assertUrl)
counter = 0
res = await request({}, prefix + 'some/url/here')
assert.deepEqual(res.body, {a:1})
assert.strictEqual(counter, 1)
assert.strictEqual(url, '/some/url/' + assertUrl)
})
t.timeout(30).test('should support timeout on invalid url', async function() {
// blocked off port, should time out
let err = await assert.isRejected(request({ timeout: 15 }, 'http://git.nfp.is:8080'))
assert.match(err.message, /timed out/i)
assert.match(err.message, /15/i)
})
})
t.describe('Request download', function() {
const assertBody = `<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
</body>
</html>`
t.beforeEach(function() {
handler = defaultHandler
})
t.afterEach(function() {
return fs.rm(testTargetFile)
.catch(function() { })
})
t.test('should support downloading file successfully', async function() {
handler = function(req, res) {
res.statusCode = 200
res.end(assertBody);
}
await request({}, prefix, testTargetFile)
let stat = await fs.stat(testTargetFile)
assert.notStrictEqual(stat.size, 0)
assert.strictEqual(stat.size, assertBody.length)
let contents = await (await fs.readFile(testTargetFile)).toString()
assert.strictEqual(contents, assertBody)
})
t.test('should support downloading file after redirect successfully', async function() {
let counter = 0
handler = function(req, res) {
if (counter < 3) {
res.statusCode = 302
res.setHeader('Location', encodeURI(prefix))
res.end();
counter++
return
}
res.statusCode = 200
res.end(assertBody);
}
await request({}, prefix, testTargetFile)
assert.strictEqual(counter, 3)
let stat = await fs.stat(testTargetFile)
assert.notStrictEqual(stat.size, 0)
assert.strictEqual(stat.size, assertBody.length)
let contents = await (await fs.readFile(testTargetFile)).toString()
assert.strictEqual(contents, assertBody)
})
t.test('should not create file if download redirects too many times', async function() {
handler = function(req, res) {
res.statusCode = 302
res.setHeader('Location', encodeURI(prefix))
res.end(assertBody);
}
let err = await assert.isRejected(request({}, prefix, testTargetFile))
assert.match(err.message, /redirects/)
let errStat = await assert.isRejected(fs.stat(testTargetFile))
assert.strictEqual(errStat.code, 'ENOENT')
})
t.test('should not create file if download fails', async function() {
handler = function(req, res) {
res.statusCode = 404
res.end('{}');
}
let err = await assert.isRejected(request({}, prefix, testTargetFile))
assert.match(err.message, /HTTP/)
assert.match(err.message, /404/)
let errStat = await assert.isRejected(fs.stat(testTargetFile))
assert.strictEqual(errStat.code, 'ENOENT')
})
})
t.after(function(cb) {
server.close(cb)
})