Skip to content
Snippets Groups Projects
Commit 974a8ee7 authored by julian.baeume's avatar julian.baeume :pick: Committed by julian.baeume
Browse files

switch to type "module" for this project (ESM)

since it's still kind of small, it makes sense to switch to ESM, now.
parent 66db1fdf
No related branches found
No related tags found
No related merge requests found
{
"root": true,
"env": {
"node": true,
"es2021": true
},
"extends": [
"standard"
]
}
module.exports = {
root: true,
env: {
node: true,
es2021: true
},
extends: [
'standard'
]
}
......@@ -3,7 +3,7 @@
* https://jestjs.io/docs/configuration
*/
module.exports = {
export default {
// All imported modules in your tests should be mocked automatically
// automock: false,
......
......@@ -2,13 +2,14 @@
"name": "manifest-service",
"version": "1.0.0",
"description": "Provides a combined manifest.json",
"type": "module",
"main": "index.js",
"scripts": {
"lint": "eslint .",
"start": "node index.js",
"dev": "nodemon index.js | pino-pretty",
"prepare": "husky install",
"test": "jest --no-cache"
"test": "NODE_OPTIONS=--experimental-vm-modules jest --no-cache"
},
"author": "Open-Xchange",
"license": "CC-BY-NC-SA-2.5",
......@@ -17,13 +18,13 @@
"dotenv-defaults": "^2.0.1",
"eslint-config-standard": "^16.0.2",
"express": "^4.17.1",
"express-prom-bundle": "^6.4.1",
"helmet": "^4.4.1",
"js-yaml": "^4.0.0",
"node-fetch": "^2.6.1",
"pino": "^6.11.2",
"pino-http": "^5.5.0",
"prom-client": "^13.1.0",
"prometheus-api-metrics": "^3.2.0",
"swagger-ui-express": "^4.1.6"
},
"devDependencies": {
......@@ -34,7 +35,6 @@
"eslint-plugin-jest": "^24.4.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.0",
"fetch-mock-jest": "^1.5.1",
"husky": ">=6",
"jest": "^27.1.0",
"jest-extended": "^0.11.5",
......
{
"env": {
"jest/globals": true
},
"plugins": ["jest"]
}
module.exports = {
env: {
'jest/globals': true
},
plugins: ['jest']
}
const { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } = require('@jest/globals')
const mock = require('mock-fs')
const fetchMock = require('node-fetch')
const request = require('supertest')
const createApp = require('../src/createApp')
jest.mock('node-fetch', () => require('fetch-mock-jest').sandbox())
import { describe, it, expect, beforeAll, afterAll, beforeEach, afterEach } from '@jest/globals'
import mockfs from 'mock-fs'
import request from 'supertest'
import { createApp } from '../src/createApp'
import { createMockServer, getRandomPort } from './util.js'
describe('Manifest service', () => {
let app
let mockserver
const port = getRandomPort()
beforeAll(() => {
mock({
mockfs({
'./config/manifests': {
'urls.yaml': `manifests:
- https://some-fake-url.k3s.de/api/manifest.json`
- http://localhost:${port}/api/manifest.json`
}
})
app = createApp()
})
afterAll(() => {
mock.restore()
mockfs.restore()
})
beforeEach(() => {
fetchMock.get('https://some-fake-url.k3s.de/api/manifest.json', JSON.parse('{"some":"thing"}'))
beforeEach(async () => {
mockserver = await createMockServer({ port })
mockserver.respondWith({
'/api/manifest.json': { some: 'thing' }
})
})
afterEach(() => {
fetchMock.restore()
mockserver.close()
app.timeout = 30000
})
it('is healthy', async () => {
return await request(app)
.get('/healthy')
.then(response => {
expect(response.statusCode).toBe(200)
})
const response = await request(app).get('/healthy')
expect(response.statusCode).toBe(200)
})
it('fetches manifest data', async () => {
return await request(app)
.get('/api/manifest.json')
.then(response => {
expect(response.statusCode).toBe(200)
expect(response.body).toEqual([JSON.parse('{"some":"thing"}')])
})
const response = await request(app).get('/api/manifest.json')
expect(response.statusCode).toBe(200)
expect(response.body).toEqual([{ some: 'thing' }])
})
it('caches manifest data', async () => {
......@@ -54,11 +51,12 @@ describe('Manifest service', () => {
.get('/api/manifest.json')
.then(response => {
expect(response.statusCode).toBe(200)
expect(response.body).toEqual([JSON.parse('{"some":"thing"}')])
expect(response.body).toEqual([{ some: 'thing' }])
})
fetchMock.restore()
fetchMock.get('https://some-fake-url.k3s.de/api/manifest.json', JSON.parse('{"some":"different"}'))
mockserver.close()
mockserver = await createMockServer({ port })
mockserver.respondWith({ '/api/manifest.json': { some: 'different' } })
await new Promise((resolve, reject) => setTimeout(resolve, 150))
......@@ -66,7 +64,7 @@ describe('Manifest service', () => {
.get('/api/manifest.json')
.then(response => {
expect(response.statusCode).toBe(200)
expect(response.body).toEqual([JSON.parse('{"some":"thing"}')])
expect(response.body).toEqual([{ some: 'thing' }])
})
})
......@@ -77,11 +75,12 @@ describe('Manifest service', () => {
.get('/api/manifest.json')
.then(response => {
expect(response.statusCode).toBe(200)
expect(response.body).toEqual([JSON.parse('{"some":"thing"}')])
expect(response.body).toEqual([{ some: 'thing' }])
})
fetchMock.restore()
fetchMock.get('https://some-fake-url.k3s.de/api/manifest.json', JSON.parse('{"some":"different"}'))
mockserver.close()
mockserver = await createMockServer({ port })
mockserver.respondWith({ '/api/manifest.json': { some: 'different' } })
await new Promise((resolve, reject) => setTimeout(resolve, 150))
......@@ -89,12 +88,12 @@ describe('Manifest service', () => {
.get('/api/manifest.json')
.then(response => {
expect(response.statusCode).toBe(200)
expect(response.body).toEqual([JSON.parse('{"some":"different"}')])
expect(response.body).toEqual([{ some: 'different' }])
})
})
it.skip('can load multiple configurations', async () => {
mock({
mockfs({
'./config/manifests': {
'urls.yaml': `manifests:
- https://some-fake-url.k3s.de/api/manifest.json
......@@ -102,7 +101,9 @@ describe('Manifest service', () => {
}
})
fetchMock.get('https://some-other-fake-url.k3s.de/api/manifest.json', JSON.parse('{"some":"other"}'))
mockserver.close()
mockserver = await createMockServer({ port })
mockserver.respondWith({ '/api/manifest.json': { some: 'other' } })
const app = createApp()
......@@ -110,7 +111,7 @@ describe('Manifest service', () => {
.get('/api/manifest.json')
.then(response => {
expect(response.statusCode).toBe(200)
expect(response.body).toEqual([JSON.parse('{"some":"thing"}'), JSON.parse('{"some":"other"}')])
expect(response.body).toEqual([{ some: 'thing"}' }, { some: 'other"}' }])
})
})
})
import express from 'express'
export function getRandomPort () {
return 1000 + (Math.random() * 39000) >> 0
}
export async function createMockServer ({ port }) {
const app = express()
const server = await new Promise(resolve => {
const server = app.listen(port, () => resolve(server))
})
server.respondWith = function (routes) {
for (const [route, data] of Object.entries(routes)) {
app.get(route, (req, res) => res.json(data))
}
}
return server
}
// Ignore paths for logging, metrics and docs
const ignorePaths = ['/ready', '/healthy']
// Fast, minimalist web framework for node.
const express = require('express')
import express from 'express'
// Helmet helps you secure your Express app by setting various HTTP headers
const helmet = require('helmet')
import helmet from 'helmet'
// Very low overhead Node.js logger. Logs in json use pino-pretty for dev.
const logger = require('pino')()
import Logger from 'pino'
// Fastest HTTP logger for Node.js in town
const httpLogger = require('pino-http')({ logger, autoLogging: { ignorePaths } })
import pinoHttp from 'pino-http'
// Readiness and liveness checks middleware
const health = require('@cloudnative/health-connect')
import health from '@cloudnative/health-connect'
// Prometheus middleware for standard api metrics
const apiMetrics = require('prometheus-api-metrics')
import promBundle from 'express-prom-bundle'
// Swagger UI for api-docs
const swaggerUi = require('swagger-ui-express')
const yaml = require('js-yaml')
const fs = require('fs')
const fetch = require('node-fetch')
const swaggerDocument = yaml.load(fs.readFileSync('./swagger.yaml', 'utf8'))
import swaggerUi from 'swagger-ui-express'
import yaml from 'js-yaml'
import fs from 'fs'
import fetch from 'node-fetch'
const ignorePaths = ['/ready', '/healthy']
const logger = new Logger()
const httpLogger = pinoHttp({ logger, autoLogging: { ignorePaths } })
const swaggerDocument = yaml.load(fs.readFileSync('./src/swagger.yaml', 'utf8'))
const bypass = (request) => ignorePaths.includes(request.path)
const metricsMiddleware = promBundle({ bypass })
module.exports = () => {
export function createApp () {
// The app returned by express() is in fact a JavaScript Function, designed to be passed to Node’s HTTP servers as a callback to handle requests.
const app = express()
......@@ -38,7 +41,7 @@ module.exports = () => {
app.use(helmet())
app.use('/healthy', health.LivenessEndpoint(healthCheck))
app.use('/ready', health.ReadinessEndpoint(healthCheck))
app.use(apiMetrics({ excludeRoutes: ignorePaths }))
app.use(metricsMiddleware)
app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(swaggerDocument))
app.use('/swagger.json', (req, res) => res.json(swaggerDocument))
......
// Add env vars from files
// Note: actual env vars supersede .env file and .env file supersedes .env.defaults file
require('dotenv-defaults').config()
import { config } from 'dotenv-defaults'
import { logger } from 'pino'
import { createApp } from './createApp'
const logger = require('pino')()
const createApp = require('./src/createApp')
config()
const app = createApp()
......
File moved
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment