Files
auth-portal/apps/api/test/deploy-config.test.ts
T

92 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { readFileSync } from 'node:fs'
import { resolve } from 'node:path'
import { describe, expect, it } from 'vitest'
const root = resolve(import.meta.dirname, '../../..')
const read = (p: string) => readFileSync(resolve(root, p), 'utf-8')
const dockerfile = read('deploy/docker/authportal/Dockerfile')
const composes = {
'docker-compose.yml': read('docker-compose.yml'),
'deploy/docker-compose.traefik.yml': read('deploy/docker-compose.traefik.yml'),
}
describe('Dockerfile', () => {
it('graceful stop и ограничение ресурсов Node', () => {
expect(dockerfile).toMatch(/^STOPSIGNAL SIGTERM$/m)
expect(dockerfile).toMatch(/NODE_OPTIONS=--max-old-space-size=\d+/)
expect(dockerfile).toMatch(/UV_THREADPOOL_SIZE=4/)
})
it('healthcheck без запуска node', () => {
const hc = dockerfile.split('HEALTHCHECK')[1]!.split('\n').slice(0, 2).join(' ')
expect(hc).toContain('wget')
expect(hc).not.toContain('"node"')
})
it('запуск не от root, рантайм без тулчейна и pnpm deploy', () => {
expect(dockerfile).toMatch(/^USER node$/m)
const runtime = dockerfile.split('AS runtime')[1]!
expect(runtime).not.toMatch(/apk add/)
expect(dockerfile).not.toMatch(/pnpm .*deploy/)
})
it('статика сжимается только brotli', () => {
expect(dockerfile).toContain('brotli')
expect(dockerfile).not.toMatch(/gzip -k/)
})
it('preview-маршруты дизайна вырезаются до сборки web', () => {
const rm = dockerfile.indexOf('rm -f apps/web/src/routes/design-preview*.tsx')
const build = dockerfile.indexOf('pnpm turbo build')
expect(rm).toBeGreaterThan(0)
expect(rm).toBeLessThan(build)
})
it('базовый образ закреплён по digest', () => {
expect(dockerfile).toMatch(/ARG BASE_NODE=\S+@sha256:[0-9a-f]{64}/)
expect(read('deploy/docker/docker-bake.hcl')).toMatch(/node:22-alpine@sha256:[0-9a-f]{64}/)
})
it('в образ копируется весь dist API, а tsup не дробит бандл на чанки', () => {
expect(dockerfile).toContain('cp -r apps/api/dist /out/dist')
expect(read('apps/api/tsup.config.ts')).toMatch(/splitting:\s*false/)
})
it('нативные модули проверяются при сборке', () => {
expect(dockerfile).toContain('native modules ok')
})
})
describe.each(Object.entries(composes))('%s', (_name, text) => {
it('init, grace period и лимиты ресурсов', () => {
expect(text).toMatch(/init: true/)
expect(text).toMatch(/stop_grace_period: 15s/)
expect(text).toMatch(/mem_limit: 256m/)
expect(text).toMatch(/pids_limit: \d+/)
expect(text).toMatch(/read_only: true/)
expect(text).toMatch(/cap_drop:\s*\n\s*- ALL/)
expect(text).toMatch(/no-new-privileges:true/)
})
it('healthcheck через wget', () => {
expect(text).toMatch(/"wget", "-q"/)
expect(text).not.toMatch(/fetch\('http:\/\/127\.0\.0\.1:8080\/health'\)/)
})
})
describe('traefik', () => {
it('app ждёт healthy traefik, у traefik есть healthcheck', () => {
const t = composes['deploy/docker-compose.traefik.yml']
expect(t).toMatch(/condition: service_healthy/)
expect(t).toContain('traefik", "healthcheck", "--ping')
expect(t).toContain('--ping=true')
})
it('включено сжатие ответов', () => {
expect(composes['deploy/docker-compose.traefik.yml']).toContain(
'middlewares.auth-portal-compress.compress=true',
)
})
})