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(` `); } 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(` `); } 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 = ` ` 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) })