@small-tech/auto-encrypt
Version:
Automatically provisions and renews Let’s Encrypt TLS certificates on Node.js https servers (including Kitten, Polka, Express.js, etc.)
180 lines (154 loc) • 4.64 kB
JavaScript
//////////////////////////////////////////////////////////////////////
//
// Unit test helpers.
//
//////////////////////////////////////////////////////////////////////
import fs from 'fs'
import os from 'os'
import path from 'path'
import http from 'http'
import Configuration from '../Configuration.js'
import LetsEncryptServer from '../LetsEncryptServer.js'
import Throws from '../util/Throws.js'
import log from '../util/log.js'
//
// Server mocks.
//
const throws = new Throws({
[Symbol.for('MockServerCouldNotBeStartedError')]: error => `Mock server could not be started (${error})`
})
export class MockServer {
static #isBeingInstantiatedViaAsyncFactoryMethod = false
static async getInstanceAsync (responseHandler = throws.ifMissing()) {
this.#isBeingInstantiatedViaAsyncFactoryMethod = true
const instance = new MockServer(responseHandler)
await instance.create(responseHandler)
this.#isBeingInstantiatedViaAsyncFactoryMethod = false
return instance
}
#server = null
#responseHandler = null
constructor(responseHandler) {
if (!MockServer.#isBeingInstantiatedViaAsyncFactoryMethod) {
throws.error(Symbol.for('MustBeInstantiatedViaAsyncFactoryMethodError'))
}
this.#responseHandler = responseHandler
}
async create () {
const server = http.createServer(this.#responseHandler)
this.#server = server
await new Promise((resolve, reject) => {
try {
server.listen(9829, () => {
log(' 🎭 ❨auto-encrypt❩ Mock server started.')
resolve()
})
} catch (error) {
reject(throws.createError(Symbol.for('MockServerCouldNotBeStartedError')))
}
})
}
async destroy () {
this.#server.closeAllConnections()
return new Promise((resolve, reject) => {
this.#server.close(error => {
if (error) {
console.error(error)
reject(error)
}
resolve()
})
})
}
}
export async function httpServerWithResponse (mockResponse) {
return new Promise((resolve, _reject) => {
const server = http.createServer((request, response) => {
response.statusCode = mockResponse.statusCode
response.end(mockResponse.body)
})
server.listen(1234, () => {
resolve(server)
})
})
}
//
// Pebble setup and teardown.
//
export class TestContext {
}
//
// Timing.
//
export function timeIt(func) {
const startTime = new Date()
const returnValue = func()
const endTime = new Date()
return { returnValue, duration: endTime - startTime }
}
export async function timeItAsync(func) {
const startTime = new Date()
const returnValue = await func()
const endTime = new Date()
return { returnValue, duration: endTime - startTime }
}
//
// Error validation.
//
export function symbolOfErrorThrownBy(func) {
try {
func()
return false
} catch (error) {
if (error.symbol === undefined) return 'no symbol found for error. Are you sure this is a SymbolicError and you’re using the Throws module?\n${error}'
return error.symbol
}
}
export async function symbolOfErrorThrownByAsync(func) {
try {
await func()
return false
} catch (error) {
if (error.symbol === undefined) return 'no symbol found for error. Are you sure this is a SymbolicError and you’re using the Throws module?\n${error}'
return error.symbol
}
}
export function throwsErrorOfType (func, errorSymbol) {
try {
func()
} catch (error) {
// Is the error of the type requested?
return error.symbol === errorSymbol
}
// Did not throw when it was supposed to.
return false
}
export async function throwsErrorOfTypeAsync (asyncFunc, errorSymbol) {
try {
await asyncFunc()
} catch (error) {
// Is the error of the type requested?
return error.symbol === errorSymbol
}
// Did not throw when it was supposed to.
return false
}
export function dehydrate (string) {
return string.replace(/\s/g, '')
}
export function createTestSettingsPath () {
const testSettingsPath = path.join(os.homedir(), '.small-tech.org', 'auto-encrypt', 'test')
fs.rmSync(testSettingsPath, { recursive: true, force: true })
return testSettingsPath
}
export function initialiseStagingConfigurationWithOneDomainAtTestSettingsPath () {
Configuration.reset()
Configuration.initialise({
domains: ['dev.ar.al'],
server: new LetsEncryptServer(LetsEncryptServer.type.STAGING),
settingsPath: createTestSettingsPath()
})
}
export function setupStagingConfigurationWithOneDomainAtTestSettingsPath () {
initialiseStagingConfigurationWithOneDomainAtTestSettingsPath()
}