Merge branch 'master' into cn
Some checks failed
dependency-updates / prepare (push) Has been cancelled
dependency-updates / update / ${{ matrix.name }} (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled

* master: (546 commits)
  chore(deps): bump gunicorn in /tests/apps/dockerfile-release
  chore(deps): bump github.com/traefik/traefik/v2
  chore(deps): bump gunicorn from 26.0.0 to 26.1.0 in /tests/apps/multi
  chore(deps): bump gunicorn in /tests/apps/python-flask
  chore(deps): bump pygments from 2.20.0 to 2.21.0 in /docs/_build
  chore: bump herokuish to 0.11.16
  chore: bump go modules
  chore(deps): bump golang.org/x/crypto in /plugins/common
  chore(deps): bump sqlparse in /tests/apps/dockerfile-release
  chore(deps): bump helm.sh/helm/v3 in /plugins/scheduler-k3s
  chore(deps): bump golang in /tests/apps/zombies-dockerfile-no-tini
  chore(deps): bump golang in /tests/apps/go-fail-postdeploy
  chore(deps): bump golang in /tests/apps/go-fail-predeploy
  chore(deps): bump golang from 1.26.5 to 1.26.6 in /tests/apps/gogrpc
  chore(deps): bump golang in /tests/apps/zombies-dockerfile-tini
  chore(deps): bump google.golang.org/protobuf in /tests/apps/gogrpc
  fix: retire cron containers past their active deadline
  Release 0.38.27
  fix: report traefik dns-provider env vars as global keys
  fix: do not require a local image for k3s deploys
  ...

# Conflicts:
#	common.mk
#	contrib/dependencies.json
This commit is contained in:
apple
2026-08-22 17:40:33 +08:00
810 changed files with 54461 additions and 7873 deletions

View File

@@ -28,20 +28,20 @@
}
},
"node_modules/body-parser": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz",
"integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz",
"integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==",
"license": "MIT",
"dependencies": {
"bytes": "^3.1.2",
"content-type": "^1.0.5",
"content-type": "^2.0.0",
"debug": "^4.4.3",
"http-errors": "^2.0.0",
"iconv-lite": "^0.7.0",
"http-errors": "^2.0.1",
"iconv-lite": "^0.7.2",
"on-finished": "^2.4.1",
"qs": "^6.14.0",
"raw-body": "^3.0.1",
"type-is": "^2.0.1"
"qs": "^6.15.2",
"raw-body": "^3.0.2",
"type-is": "^2.1.0"
},
"engines": {
"node": ">=18"
@@ -51,6 +51,19 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/body-parser/node_modules/content-type": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
"integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@@ -408,9 +421,9 @@
}
},
"node_modules/iconv-lite": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
"version": "0.7.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz",
"integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==",
"license": "MIT",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
@@ -576,9 +589,9 @@
}
},
"node_modules/qs": {
"version": "6.15.0",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz",
"integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
"version": "6.15.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
"integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==",
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
@@ -790,17 +803,34 @@
}
},
"node_modules/type-is": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz",
"integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==",
"license": "MIT",
"dependencies": {
"content-type": "^1.0.5",
"content-type": "^2.0.0",
"media-typer": "^1.1.0",
"mime-types": "^3.0.0"
},
"engines": {
"node": ">= 0.6"
"node": ">= 18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/type-is/node_modules/content-type": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz",
"integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/express"
}
},
"node_modules/unpipe": {

View File

@@ -1,4 +1,4 @@
FROM node:25-alpine
FROM node:26-alpine
RUN apk add --no-cache bash

View File

@@ -1,4 +1,4 @@
FROM ruby:4.0.3
FROM ruby:4.0.6
RUN mkdir /app
WORKDIR /app

View File

@@ -1,4 +1,4 @@
FROM node:25-alpine
FROM node:26-alpine
RUN apk add --no-cache bash

View File

@@ -1,4 +1,4 @@
FROM node:25-alpine
FROM node:26-alpine
RUN apk add --no-cache bash

View File

@@ -5,8 +5,4 @@
# Procfile for development using the new threaded worker (scheduler, twitter stream and delayed job)
cron: node worker.js
web: node web.js
<<<<<<< HEAD=0
worker: node worker.js
========0
worker: node worker-2.js
>>>>>>> 5bb7ec3e2a8f4f6565432a4fc82c92d4a3603d28=0

View File

@@ -1,4 +1,4 @@
FROM node:25-alpine
FROM node:26-alpine
RUN apk add --no-cache bash

View File

@@ -0,0 +1,21 @@
{
"cron": [
{
"command": "release",
"schedule": "5 5 5 5 5"
}
],
"healthchecks": {
"web": [
{
"attempts": 2,
"content": "nodejs/express",
"name": "check-1",
"path": "/",
"timeout": 5,
"type": "startup",
"wait": 2
}
]
}
}

View File

@@ -0,0 +1,27 @@
{
"cron": [
{
"command": "echo hello-from-cron",
"schedule": "5 5 5 5 5"
}
],
"healthchecks": {
"web": [
{
"attempts": 2,
"content": "nodejs/express",
"name": "check-1",
"path": "/",
"timeout": 5,
"type": "startup",
"wait": 2
}
]
},
"scripts": {
"dokku": {
"postdeploy": "touch /app/postdeploy.test",
"predeploy": "touch /app/predeploy.test"
}
}
}

View File

@@ -1,4 +1,4 @@
FROM python:3.14.3-bookworm
FROM python:3.15.0rc1-bookworm
RUN pip install --user pipenv
ENV PATH="${PATH}:/root/.local/bin"

View File

@@ -18,11 +18,11 @@
"default": {
"asgiref": {
"hashes": [
"sha256:5f184dc43b7e763efe848065441eac62229c9f7b0475f41f80e207a114eda4ce",
"sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133"
"sha256:59dcb51c272ad209d59bed5708a64a333083e86017d7fcdd67498eeab7784340",
"sha256:fe386d1c2bff7259ea95929266d12a8cf9a8b5a1c2598402967d8792e7a7c094"
],
"markers": "python_version >= '3.9'",
"version": "==3.11.1"
"markers": "python_version >= '3.10'",
"version": "==3.12.1"
},
"dj-database-url": {
"hashes": [
@@ -35,38 +35,38 @@
},
"django": {
"hashes": [
"sha256:5788fce61da23788a8ce6f02583765ab060d396720924789f97fa42119d37f7a",
"sha256:a31589db5188d074c63f0945c3888fad104627dfcc236fb2b97f71f89da33bc4"
"sha256:9d4d93be539a18ab80d058eb515900e10951e04c537c5a6b394fc49528d3251f",
"sha256:f04fb3b36ee119e1af4fa1d397d5fd6cf12700f49321e84d4f4c642c5b1973db"
],
"index": "pypi",
"markers": "python_version >= '3.10'",
"version": "==5.2.13"
"version": "==5.2.17"
},
"djangorestframework": {
"hashes": [
"sha256:a6def5f447fe78ff853bff1d47a3c59bf38f5434b031780b351b0c73a62db1a5",
"sha256:c3c74dd3e83a5a3efc37b3c18d92bd6f86a6791c7b7d4dff62bb068500e76457"
"sha256:2323a5111837e0b784dcb8323abc78ecc54fa2a5af7aff2677cf50cdd849477f",
"sha256:381fc44d3249c9565c5f723850855b734e99030eb30957a49f506d3fe11d7dcb"
],
"index": "pypi",
"markers": "python_version >= '3.10'",
"version": "==3.17.1"
"version": "==3.18.0"
},
"gunicorn": {
"hashes": [
"sha256:cacea387dab08cd6776501621c295a904fe8e3b7aae9a1a3cbb26f4e7ed54660",
"sha256:f74e1b2f9f76f6cd1ca01198968bd2dd65830edc24b6e8e4d78de8320e2fe889"
"sha256:1413d777bf99d31ebeb08acd354b01f1ecc44db0aa7b811ae7b86c669232e4f7",
"sha256:9f45bcddec5e9dc7a25a3bdccb0c6832f11fd5d4739b1ee36c8d2fec25f1dc86"
],
"index": "pypi",
"markers": "python_version >= '3.10'",
"version": "==25.3.0"
"version": "==26.1.0"
},
"packaging": {
"hashes": [
"sha256:00243ae351a257117b6a241061796684b084ed1c516a08c48a3f7e147a9d80b4",
"sha256:b36f1fef9334a5588b4166f8bcd26a14e521f2b55e6b9de3aaa80d3ff7a37529"
"sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e",
"sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"
],
"markers": "python_version >= '3.8'",
"version": "==26.0"
"version": "==26.2"
},
"psycopg2-binary": {
"hashes": [
@@ -151,20 +151,21 @@
},
"setuptools": {
"hashes": [
"sha256:c3a9c4211ff4c309edb8b8c4f1cbfa7ae324c4ba9f91ff254e3d305b9fd54561",
"sha256:fcc17fd9cd898242f6b4adfaca46137a9edef687f43e6f78469692a5e70d851d"
"sha256:025bccbbf0fa05b6192bc64ae1e7b16e001fd6d6d4d5de03c97b1c1ade523bef",
"sha256:29b23c360f22f414dc7336bb39178cc7bcbf6021ed2733cde173f09dba19abb3"
],
"index": "pypi",
"markers": "python_version >= '3.9'",
"version": "==78.1.1"
"markers": "python_version >= '3.10'",
"version": "==83.0.0"
},
"sqlparse": {
"hashes": [
"sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba",
"sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e"
"sha256:113c35c75365ab9cc9c7231d68c6428fb11c085fc8e9eb1ad659b7ddbf6cd2b9",
"sha256:b861c0288ce2fa56209a9a6412d2e066ac664b3873b89c26c9d8415e8e32996f"
],
"markers": "python_version >= '3.8'",
"version": "==0.5.5"
"index": "pypi",
"markers": "python_version >= '3.10'",
"version": "==0.6.0"
},
"whitenoise": {
"hashes": [

View File

@@ -1,4 +1,4 @@
FROM node:25-alpine
FROM node:26-alpine
RUN apk add --no-cache bash

View File

@@ -3,11 +3,6 @@
"dokku-postgres",
"dokku-redis"
],
"buildpacks": [
{
"url": "https://github.com/heroku/heroku-buildpack-nodejs"
}
],
"description": "Used in dokku's test suite",
"env": {
"SECRET_TOKEN": {
@@ -16,7 +11,7 @@
},
"WEB_CONCURRENCY": {
"description": "The number of processes to run.",
"generator": "echo 5"
"value": "5"
}
},
"healthchecks": {

View File

@@ -1,4 +1,4 @@
FROM node:25-alpine
FROM node:26-alpine
RUN apk add --no-cache bash

View File

@@ -1,4 +1,4 @@
FROM golang:1.26.2
FROM golang:1.26.6
EXPOSE 3000/tcp

View File

@@ -1,4 +1,4 @@
FROM golang:1.26.2
FROM golang:1.26.6
EXPOSE 3000/tcp

View File

@@ -1,4 +1,4 @@
FROM golang:1.26.2
FROM golang:1.26.6
RUN mkdir /app
WORKDIR /app

View File

@@ -1,17 +1,17 @@
module github.com/dokku/dokko/tests/apps/gorpc
go 1.25.5
go 1.26.2
require (
golang.org/x/net v0.49.0 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/text v0.33.0 // indirect
google.golang.org/grpc v1.80.0
golang.org/x/net v0.55.0 // indirect
golang.org/x/sys v0.45.0 // indirect
golang.org/x/text v0.37.0 // indirect
google.golang.org/grpc v1.83.0
)
require (
google.golang.org/grpc/examples v0.0.0-20240118175532-987df1309236
google.golang.org/protobuf v1.36.11
google.golang.org/protobuf v1.36.12
)
require google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 // indirect
require google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect

View File

@@ -12,29 +12,29 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o=
golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8=
golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ=
golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE=
golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8=
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
go.opentelemetry.io/otel/sdk v1.44.0/go.mod h1:Osuydd3Se74nqjAKxid74N5eC+jfEqfTegHRnq58oK0=
go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRks6si09iEfI=
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY=
golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516 h1:sNrWoksmOyF5bvJUcnmbeAmQi8baNhqg5IWaI3llQqU=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260120221211-b8f7ae30c516/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ=
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
google.golang.org/grpc v1.83.0 h1:JeNZEKJFbQxArAMl+hiytHauacDNqJUllNfmIMmpqnQ=
google.golang.org/grpc v1.83.0/go.mod h1:kDyl6SKsiHKt0uylY5gtn5cEjkrIOhQOGDgIc4JGwzQ=
google.golang.org/grpc/examples v0.0.0-20240118175532-987df1309236 h1:wTUkwrodi4IuWD3kYkMUwCU8BhwFaqDywrXmsthCvQA=
google.golang.org/grpc/examples v0.0.0-20240118175532-987df1309236/go.mod h1:j5uROIAAgi3YmtiETMt1LW0d/lHqQ7wwrIY4uGRXLQ4=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
google.golang.org/protobuf v1.36.12 h1:pJOKDDOyeXErUroCihFAd5LQuwXBSpVnKGrj5o/fwxc=
google.golang.org/protobuf v1.36.12/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=

View File

@@ -23,7 +23,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.10.0</version>
<version>3.11.0</version>
<executions>
<execution>
<id>copy-dependencies</id>

View File

@@ -11,7 +11,7 @@
"license": "ISC",
"dependencies": {
"bootstrap": "^5.3.8",
"sass": "^1.99.0"
"sass": "^1.102.0"
},
"engines": {
"node": "24.x.x",
@@ -141,9 +141,6 @@
"cpu": [
"arm"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -164,9 +161,6 @@
"cpu": [
"arm"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -187,9 +181,6 @@
"cpu": [
"arm64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -210,9 +201,6 @@
"cpu": [
"arm64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -233,9 +221,6 @@
"cpu": [
"x64"
],
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -256,9 +241,6 @@
"cpu": [
"x64"
],
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -363,15 +345,15 @@
}
},
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz",
"integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
"license": "MIT",
"dependencies": {
"readdirp": "^4.0.1"
"readdirp": "^5.0.0"
},
"engines": {
"node": ">= 14.16.0"
"node": ">= 20.19.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
@@ -388,9 +370,9 @@
}
},
"node_modules/immutable": {
"version": "5.1.5",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz",
"integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==",
"version": "5.1.9",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz",
"integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==",
"license": "MIT"
},
"node_modules/is-extglob": {
@@ -437,12 +419,12 @@
}
},
"node_modules/readdirp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz",
"integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
"license": "MIT",
"engines": {
"node": ">= 14.18.0"
"node": ">= 20.19.0"
},
"funding": {
"type": "individual",
@@ -450,12 +432,12 @@
}
},
"node_modules/sass": {
"version": "1.99.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.99.0.tgz",
"integrity": "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==",
"version": "1.102.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.102.0.tgz",
"integrity": "sha512-NSOyTnaQF7rTAEOtI2fwb386vL+akyiQLBZu8Na7hXCb+umJy0GAqlcMIaqACZ6Z1VgTBS4K9PG6B3IdjHGJsw==",
"license": "MIT",
"dependencies": {
"chokidar": "^4.0.0",
"chokidar": "^5.0.0",
"immutable": "^5.1.5",
"source-map-js": ">=0.6.2 <2.0.0"
},
@@ -463,7 +445,7 @@
"sass": "sass.js"
},
"engines": {
"node": ">=14.0.0"
"node": ">=20.19.0"
},
"optionalDependencies": {
"@parcel/watcher": "^2.4.1"

View File

@@ -2,7 +2,7 @@
"author": "Al Johri",
"dependencies": {
"bootstrap": "^5.3.8",
"sass": "^1.99.0"
"sass": "^1.102.0"
},
"description": "Test application for heroku multi buildpack.",
"engines": {

View File

@@ -1,2 +1,2 @@
Flask==3.1.3
gunicorn==25.3.0
gunicorn==26.1.0

View File

@@ -16,7 +16,7 @@
},
"WEB_CONCURRENCY": {
"description": "The number of processes to run.",
"generator": "echo 5"
"value": "5"
}
},
"healthchecks": {

View File

@@ -485,16 +485,16 @@
},
{
"name": "slim/slim",
"version": "4.15.1",
"version": "4.15.2",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
"reference": "887893516557506f254d950425ce7f5387a26970"
"reference": "e12cb05ca2a14e8f459d019e87a31dc915b80470"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/887893516557506f254d950425ce7f5387a26970",
"reference": "887893516557506f254d950425ce7f5387a26970",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/e12cb05ca2a14e8f459d019e87a31dc915b80470",
"reference": "e12cb05ca2a14e8f459d019e87a31dc915b80470",
"shasum": ""
},
"require": {
@@ -597,22 +597,22 @@
"type": "tidelift"
}
],
"time": "2025-11-21T12:23:44+00:00"
"time": "2026-05-22T08:00:12+00:00"
}
],
"packages-dev": [
{
"name": "heroku/heroku-buildpack-php",
"version": "v287",
"version": "v294",
"source": {
"type": "git",
"url": "https://github.com/heroku/heroku-buildpack-php.git",
"reference": "4f53d131bd04d41a1c6ab861d74fd1a16dbbf2cb"
"reference": "2a8f9567a34acc79b6ebc1118196cfeda031ca2a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/heroku/heroku-buildpack-php/zipball/4f53d131bd04d41a1c6ab861d74fd1a16dbbf2cb",
"reference": "4f53d131bd04d41a1c6ab861d74fd1a16dbbf2cb",
"url": "https://api.github.com/repos/heroku/heroku-buildpack-php/zipball/2a8f9567a34acc79b6ebc1118196cfeda031ca2a",
"reference": "2a8f9567a34acc79b6ebc1118196cfeda031ca2a",
"shasum": ""
},
"bin": [
@@ -642,9 +642,9 @@
],
"support": {
"issues": "https://github.com/heroku/heroku-buildpack-php/issues",
"source": "https://github.com/heroku/heroku-buildpack-php/tree/v287"
"source": "https://github.com/heroku/heroku-buildpack-php/tree/v294"
},
"time": "2026-04-17T14:51:42+00:00"
"time": "2026-07-31T14:30:30+00:00"
}
],
"aliases": [],

View File

@@ -1,5 +1,5 @@
Flask==3.1.3
Jinja2==3.1.6
Werkzeug==3.1.8
gunicorn==25.3.0
gunicorn==26.1.0

View File

@@ -0,0 +1,21 @@
{
"cron": [
{
"command": "task",
"schedule": "5 5 5 5 5"
}
],
"healthchecks": {
"web": [
{
"attempts": 2,
"content": "python/http.server",
"name": "check-1",
"path": "/",
"timeout": 5,
"type": "startup",
"wait": 2
}
]
}
}

View File

@@ -0,0 +1,21 @@
{
"cron": [
{
"command": "task",
"schedule": "5 5 5 5 5"
}
],
"healthchecks": {
"web": [
{
"attempts": 2,
"content": "python/http.server",
"name": "check-1",
"path": "/",
"timeout": 5,
"type": "startup",
"wait": 2
}
]
}
}

View File

@@ -0,0 +1,8 @@
{
"env": {
"REQUIRED_VAR": {
"description": "A required variable with no default",
"required": true
}
}
}

View File

@@ -0,0 +1,27 @@
{
"env": {
"SIMPLE_VAR": "simple_value",
"OBJECT_VAR": {
"description": "A variable with a default value",
"value": "object_default"
},
"SECRET_VAR": {
"description": "A generated secret",
"generator": "secret"
},
"OPTIONAL_VAR": {
"description": "An optional variable",
"required": false
},
"SYNC_VAR": {
"description": "A variable that syncs on every deploy",
"value": "sync_value",
"sync": true
}
},
"scripts": {
"dokku": {
"predeploy": "echo ENV_CHECK: SIMPLE_VAR=$SIMPLE_VAR OBJECT_VAR=$OBJECT_VAR"
}
}
}

View File

@@ -0,0 +1,16 @@
import sys
import time
def main(args):
# a log shipper attaches to a container after it receives the start event,
# and a cron container is removed the moment it exits. sleep on either side
# of the output so that the shipper has time to attach before the line is
# written and time to read it before the container is gone.
time.sleep(5)
print(' '.join(args[1:]), flush=True)
time.sleep(3)
if __name__ == '__main__':
main(sys.argv)

View File

@@ -1,3 +1,3 @@
module dokku.me/web
go 1.25.5
go 1.26.2

View File

@@ -1,4 +1,4 @@
FROM golang:1.26.2
FROM golang:1.26.6
ADD . /go/src/github.com/dokku/apps/web
WORKDIR /go/src/github.com/dokku/apps/web

View File

@@ -1,3 +1,3 @@
module dokku.me/web
go 1.25.5
go 1.26.2

View File

@@ -1,4 +1,4 @@
FROM golang:1.26.2
FROM golang:1.26.6
ADD . /go/src/github.com/dokku/apps/web
WORKDIR /go/src/github.com/dokku/apps/web

View File

@@ -1,3 +1,3 @@
module dokku.me/web
go 1.25.5
go 1.26.2

128
tests/image/healthcheck.sh Executable file
View File

@@ -0,0 +1,128 @@
#!/usr/bin/env bash
set -euo pipefail
IMAGE_TAG="${IMAGE_TAG:-dokku/dokku:latest}"
CONTAINER_NAME="${CONTAINER_NAME:-dokku-healthcheck-smoke}"
START_TIMEOUT_SECONDS="${START_TIMEOUT_SECONDS:-360}"
UNHEALTHY_TIMEOUT_SECONDS="${UNHEALTHY_TIMEOUT_SECONDS:-180}"
log-info() {
echo "-----> $*"
}
log-fail() {
echo " ! $*" >&2
exit 1
}
cleanup() {
docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true
}
trap cleanup EXIT
require-image() {
if ! docker image inspect "$IMAGE_TAG" >/dev/null 2>&1; then
log-fail "Image '$IMAGE_TAG' not found in local docker daemon. Build it first (eg. 'docker build -t $IMAGE_TAG .')."
fi
}
start-container() {
log-info "Starting container '$CONTAINER_NAME' from image '$IMAGE_TAG'"
docker rm -f "$CONTAINER_NAME" >/dev/null 2>&1 || true
docker run -d \
--name "$CONTAINER_NAME" \
--env DOKKU_HOSTNAME=dokku.me \
-v /var/run/docker.sock:/var/run/docker.sock \
"$IMAGE_TAG" >/dev/null
}
wait-for-catchall-vhost() {
local deadline=$((SECONDS + 30))
while ((SECONDS < deadline)); do
if docker exec "$CONTAINER_NAME" test -f /etc/nginx/conf.d/00-default-vhost.conf; then
return 0
fi
sleep 1
done
log-fail "Catch-all default vhost /etc/nginx/conf.d/00-default-vhost.conf was never created. \
Likely cause: a stale build/package/dokku-*.deb that predates the catch-all template shipped in \
plugins/nginx-vhosts/templates/default-site.conf. Rebuild the deb before running this test."
}
wait-for-healthy() {
local deadline=$((SECONDS + START_TIMEOUT_SECONDS))
local status
while ((SECONDS < deadline)); do
status=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "missing")
if [[ "$status" == "healthy" ]]; then
log-info "Container reached healthy status"
return 0
fi
sleep 5
done
log-info "Container failed to become healthy within ${START_TIMEOUT_SECONDS}s. Last logs:"
docker logs --tail 100 "$CONTAINER_NAME" || true
log-fail "Container '$CONTAINER_NAME' did not reach healthy status (last status: ${status:-unknown})"
}
assert-endpoint-ok() {
log-info "Verifying /_dokku/health returns ok from inside the container"
local body
body=$(docker exec "$CONTAINER_NAME" curl -fsS http://127.0.0.1:18080/_dokku/health)
if [[ "$body" != "ok" ]]; then
log-fail "Expected health endpoint body 'ok', got: ${body}"
fi
}
assert-port-not-published() {
log-info "Verifying port 18080 is not published to the host"
local ports
ports=$(docker inspect --format='{{json .NetworkSettings.Ports}}' "$CONTAINER_NAME")
if echo "$ports" | grep -q "18080/tcp"; then
log-fail "Port 18080/tcp should not be published to the host. Inspect output: $ports"
fi
if curl --max-time 2 -fsS http://127.0.0.1:18080/_dokku/health >/dev/null 2>&1; then
log-fail "Health endpoint is reachable from the host on 127.0.0.1:18080 - it must be loopback-only inside the container."
fi
}
assert-unhealthy-after-sentinel-removed() {
log-info "Removing /var/run/dokku/ready and confirming endpoint returns failure"
docker exec "$CONTAINER_NAME" rm -f /var/run/dokku/ready
local exit_code=0
docker exec "$CONTAINER_NAME" curl -fsS http://127.0.0.1:18080/_dokku/health >/dev/null 2>&1 || exit_code=$?
if ((exit_code == 0)); then
log-fail "Health endpoint still returned success after the readiness sentinel was removed"
fi
log-info "Waiting for docker to flip the health status to unhealthy"
local deadline=$((SECONDS + UNHEALTHY_TIMEOUT_SECONDS))
local status
while ((SECONDS < deadline)); do
status=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "missing")
if [[ "$status" == "unhealthy" ]]; then
log-info "Container flipped to unhealthy"
return 0
fi
sleep 5
done
log-fail "Container did not flip to unhealthy within ${UNHEALTHY_TIMEOUT_SECONDS}s (last status: ${status:-unknown})"
}
main() {
require-image
start-container
wait-for-catchall-vhost
wait-for-healthy
assert-endpoint-ok
assert-port-not-published
assert-unhealthy-after-sentinel-removed
log-info "All healthcheck smoke tests passed."
}
main "$@"

198
tests/unit/app-json-5.bats Normal file
View File

@@ -0,0 +1,198 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
create_app
}
teardown() {
destroy_app
global_teardown
}
@test "(app-json) app.json env simple value" {
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app-env.json"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Processing app.json env vars"
assert_output_contains "Setting 4 env var(s) from app.json"
run /bin/bash -c "dokku config:get $TEST_APP SIMPLE_VAR"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "simple_value"
run /bin/bash -c "dokku config:get $TEST_APP OBJECT_VAR"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "object_default"
}
@test "(app-json) app.json env secret generator" {
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app-env.json"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP SECRET_VAR"
echo "output: $output"
echo "status: $status"
assert_success
# Secret should be 64 characters (hex encoded 32 bytes)
[[ ${#output} -eq 64 ]]
}
@test "(app-json) app.json env does not overwrite on redeploy" {
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app-env.json"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
# Get the original secret
run /bin/bash -c "dokku config:get $TEST_APP SECRET_VAR"
echo "output: $output"
echo "status: $status"
assert_success
local original_secret="$output"
# Change SIMPLE_VAR manually
run /bin/bash -c "dokku config:set --no-restart $TEST_APP SIMPLE_VAR=changed_value"
echo "output: $output"
echo "status: $status"
assert_success
# Rebuild the app
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
# Verify SIMPLE_VAR was NOT overwritten
run /bin/bash -c "dokku config:get $TEST_APP SIMPLE_VAR"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "changed_value"
# Verify SECRET_VAR was NOT regenerated
run /bin/bash -c "dokku config:get $TEST_APP SECRET_VAR"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "$original_secret"
}
@test "(app-json) app.json env sync overwrites on redeploy" {
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app-env.json"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
# Verify SYNC_VAR is set
run /bin/bash -c "dokku config:get $TEST_APP SYNC_VAR"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "sync_value"
# Change SYNC_VAR manually
run /bin/bash -c "dokku config:set --no-restart $TEST_APP SYNC_VAR=manual_value"
echo "output: $output"
echo "status: $status"
assert_success
# Rebuild the app
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
# Verify SYNC_VAR WAS overwritten back to sync_value
run /bin/bash -c "dokku config:get $TEST_APP SYNC_VAR"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "sync_value"
}
@test "(app-json) app.json env required without value fails" {
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app-env-required.json"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "required env var REQUIRED_VAR has no value"
}
@test "(app-json) app.json env skips optional without value" {
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app-env.json"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
# OPTIONAL_VAR should not be set since it has no default and is optional
# config:get returns exit code 1 when a variable is not set
run /bin/bash -c "dokku config:get $TEST_APP OPTIONAL_VAR"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output ""
}
@test "(app-json) app.json env respects pre-set values on first deploy" {
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app-env.json"
echo "output: $output"
echo "status: $status"
assert_success
# Pre-set SIMPLE_VAR before first deploy
run /bin/bash -c "dokku config:set --no-restart $TEST_APP SIMPLE_VAR=preset_value"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
# Verify SIMPLE_VAR was NOT overwritten
run /bin/bash -c "dokku config:get $TEST_APP SIMPLE_VAR"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "preset_value"
}

View File

@@ -139,7 +139,7 @@ teardown() {
assert_success
fi
run /bin/bash -c "dokku config:set $TEST_APP SECRET_KEY_BASE=derp OTP_SECRET=1234"
run /bin/bash -c "dokku config:set $TEST_APP SECRET_KEY_BASE=derp OTP_SECRET=1234 LOCAL_DOMAIN=dokku.me"
echo "output: $output"
echo "status: $status"
assert_success
@@ -256,6 +256,115 @@ teardown() {
assert_output_contains "touch /app/predeploy3.test"
}
@test "(app-json:report) appjson-path round-trip" {
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app2.json"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-appjson-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "app2.json"
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-computed-appjson-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "app2.json"
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-global-appjson-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku app-json:report $TEST_APP --format json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains '"app-json-appjson-path":"app2.json"'
assert_output_contains '"app-json-computed-appjson-path":"app2.json"'
assert_output_contains '"app-json-global-appjson-path":""'
assert_output_contains '"appjson-path":"app2.json"'
assert_output_contains '"computed-appjson-path":"app2.json"'
assert_output_contains '"global-appjson-path":""'
assert_output_contains "app-json-selected" 0
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-selected"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-appjson-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-computed-appjson-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "app.json"
}
@test "(app-json:report) appjson-path raw vs computed vs global" {
run /bin/bash -c "dokku app-json:set --global appjson-path"
assert_success
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-appjson-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-global-appjson-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-computed-appjson-path"
assert_success
assert_output "app.json"
run /bin/bash -c "dokku app-json:set --global appjson-path app.global.json"
assert_success
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-global-appjson-path"
assert_success
assert_output "app.global.json"
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-computed-appjson-path"
assert_success
assert_output "app.global.json"
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path app.app.json"
assert_success
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-appjson-path"
assert_success
assert_output "app.app.json"
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-global-appjson-path"
assert_success
assert_output "app.global.json"
run /bin/bash -c "dokku app-json:report $TEST_APP --app-json-computed-appjson-path"
assert_success
assert_output "app.app.json"
run /bin/bash -c "dokku app-json:set $TEST_APP appjson-path"
assert_success
run /bin/bash -c "dokku app-json:set --global appjson-path"
assert_success
}
copy_app_json_to_sub_app() {
local APP="$1"
local APP_REPO_DIR="$2"

View File

@@ -50,6 +50,36 @@ teardown() {
assert_success
}
@test "(apps) apps:list --format json" {
run /bin/bash -c "dokku apps:list --format json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "[]"
run /bin/bash -c "dokku apps:create $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku apps:list --format json | jq '. | length'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "1"
run /bin/bash -c "dokku apps:list --format json | jq -r '.[0]'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "$TEST_APP"
run /bin/bash -c "dokku --force apps:destroy $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(apps) apps:create" {
run /bin/bash -c "dokku apps:create $TEST_APP"
echo "output: $output"
@@ -96,6 +126,26 @@ teardown() {
echo "status: $status"
assert_failure
run /bin/bash -c "dokku apps:create 'test;id'"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku apps:create 'test\$cmd'"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku apps:create 'test|cmd'"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku apps:create 'test&cmd'"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku --app $TEST_APP apps:create"
echo "output: $output"
echo "status: $status"
@@ -113,7 +163,7 @@ teardown() {
}
@test "(apps) app autocreate disabled" {
run /bin/bash -c "dokku config:set --no-restart --global DOKKU_DISABLE_APP_AUTOCREATION='true'"
run /bin/bash -c "dokku apps:set --global disable-autocreation true"
echo "output: $output"
echo "status: $status"
assert_success
@@ -122,7 +172,7 @@ teardown() {
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku config:unset --no-restart --global DOKKU_DISABLE_APP_AUTOCREATION"
run /bin/bash -c "dokku apps:set --global disable-autocreation"
}
@test "(apps) apps:destroy" {
@@ -156,7 +206,7 @@ teardown() {
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "git-hook $TEST_APP"
assert_output_contains "git-hook \"$TEST_APP\""
run /bin/bash -c "dokku apps:rename $TEST_APP great-test-name"
echo "output: $output"
echo "status: $status"
@@ -165,7 +215,7 @@ teardown() {
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "git-hook great-test-name"
assert_output_contains "git-hook \"great-test-name\""
run /bin/bash -c "dokku apps:list | grep $TEST_APP"
echo "output: $output"
echo "status: $status"
@@ -347,3 +397,95 @@ teardown() {
destroy_app
}
@test "(apps:report) emits new stripped JSON keys alongside legacy" {
create_app
run /bin/bash -c "dokku apps:report $TEST_APP --format json | jq -r 'has(\"dir\") and has(\"app-dir\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku apps:report $TEST_APP --format json | jq -r 'has(\"locked\") and has(\"app-locked\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku apps:report $TEST_APP --format json | jq -r 'has(\"deploy-source\") and has(\"app-deploy-source\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku apps:report $TEST_APP --format json | jq -r 'has(\"global-disable-autocreation\") and has(\"app-global-disable-autocreation\")'"
assert_success
assert_output "true"
destroy_app
}
@test "(apps:report --global) emits global-disable-autocreation" {
run /bin/bash -c "dokku apps:report --global --app-global-disable-autocreation"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku apps:set --global disable-autocreation true"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku apps:report --global --app-global-disable-autocreation"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku apps:report --global --format json | jq -r '.\"global-disable-autocreation\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku apps:report --global --format json | jq -r '.\"app-global-disable-autocreation\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
create_app
run /bin/bash -c "dokku apps:report $TEST_APP --format json | jq -r '.\"global-disable-autocreation\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
destroy_app
run /bin/bash -c "dokku apps:set --global disable-autocreation"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(apps:set) rejects dead writes" {
run /bin/bash -c "dokku apps:set --global deploy-source git"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Property cannot be specified globally"
run /bin/bash -c "dokku apps:set --global deploy-source-metadata foo"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Property cannot be specified globally"
create_app
run /bin/bash -c "dokku apps:set $TEST_APP disable-autocreation true"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Property can only be specified globally"
destroy_app
}

View File

@@ -116,7 +116,7 @@ teardown() {
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:set --no-restart $TEST_APP DOKKU_PROXY_SSL_PORT=443"
run /bin/bash -c "dokku proxy:set $TEST_APP proxy-ssl-port 443"
echo "output: $output"
echo "status: $status"
assert_success
@@ -132,10 +132,6 @@ teardown() {
echo "output: $output"
echo "status: $status"
assert_output "http 80 5000"
run /bin/bash -c "dokku config:get app-without-ssl DOKKU_PROXY_SSL_PORT"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
run /bin/bash -c "dokku --force apps:destroy app-without-ssl"
echo "output: $output"
echo "status: $status"
@@ -166,7 +162,7 @@ teardown() {
assert_success
assert_output "http://$TEST_APP.$DOKKU_DOMAIN"
assert_http_localhost_response "http" "$TEST_APP.$DOKKU_DOMAIN" "80" "/hello"
assert_http_localhost_response "http" "great-test-name.dokku.me" "80" "/hello" "" "404"
assert_http_localhost_response "http" "great-test-name.dokku.me" "80" "/hello" "" "502"
run /bin/bash -c "dokku --force apps:destroy great-test-name"
echo "output: $output"
echo "status: $status"

View File

@@ -0,0 +1,267 @@
#!/usr/bin/env bats
load test_helper
ARCHIVE_TMP_DIR="${BATS_TMPDIR}/archive-security"
setup() {
global_setup
create_app
mkdir -p "$ARCHIVE_TMP_DIR"
}
teardown() {
rm -rf "$ARCHIVE_TMP_DIR"
rm -f /tmp/dokku-archive-security-canary.txt
dokku git:set --global archive-max-size "" >/dev/null 2>&1 || true
dokku git:set --global archive-max-files "" >/dev/null 2>&1 || true
destroy_app
global_teardown
}
create_absolute_symlink_tar() {
local OUTPUT="$1" FORMAT="${2:-tar}"
python3 - "$OUTPUT" "$FORMAT" <<'PY'
import io, sys, tarfile
output, fmt = sys.argv[1], sys.argv[2]
mode = "w:gz" if fmt == "tar.gz" else "w"
with tarfile.open(output, mode) as t:
link = tarfile.TarInfo("pwn")
link.type = tarfile.SYMTYPE
link.linkname = "/tmp"
t.addfile(link)
payload = b"canary content\n"
fi = tarfile.TarInfo("pwn/dokku-archive-security-canary.txt")
fi.size = len(payload)
t.addfile(fi, io.BytesIO(payload))
readme = b"# dummy\n"
ri = tarfile.TarInfo("README.md")
ri.size = len(readme)
t.addfile(ri, io.BytesIO(readme))
PY
}
create_relative_traversal_symlink_tar() {
local OUTPUT="$1" FORMAT="${2:-tar}"
python3 - "$OUTPUT" "$FORMAT" <<'PY'
import io, sys, tarfile
output, fmt = sys.argv[1], sys.argv[2]
mode = "w:gz" if fmt == "tar.gz" else "w"
with tarfile.open(output, mode) as t:
link = tarfile.TarInfo("pwn")
link.type = tarfile.SYMTYPE
link.linkname = "../../../../tmp"
t.addfile(link)
payload = b"canary content\n"
fi = tarfile.TarInfo("pwn/dokku-archive-security-canary.txt")
fi.size = len(payload)
t.addfile(fi, io.BytesIO(payload))
PY
}
create_absolute_path_tar() {
local OUTPUT="$1" FORMAT="${2:-tar}"
python3 - "$OUTPUT" "$FORMAT" <<'PY'
import io, sys, tarfile
output, fmt = sys.argv[1], sys.argv[2]
mode = "w:gz" if fmt == "tar.gz" else "w"
with tarfile.open(output, mode) as t:
payload = b"absolute path payload\n"
fi = tarfile.TarInfo("/tmp/dokku-archive-security-canary.txt")
fi.size = len(payload)
t.addfile(fi, io.BytesIO(payload))
PY
}
create_traversal_path_tar() {
local OUTPUT="$1" FORMAT="${2:-tar}"
python3 - "$OUTPUT" "$FORMAT" <<'PY'
import io, sys, tarfile
output, fmt = sys.argv[1], sys.argv[2]
mode = "w:gz" if fmt == "tar.gz" else "w"
with tarfile.open(output, mode) as t:
payload = b"traversal payload\n"
fi = tarfile.TarInfo("../../../tmp/dokku-archive-security-canary.txt")
fi.size = len(payload)
t.addfile(fi, io.BytesIO(payload))
PY
}
create_safe_multi_file_tar() {
local OUTPUT="$1"
python3 - "$OUTPUT" <<'PY'
import io, sys, tarfile
output = sys.argv[1]
with tarfile.open(output, "w") as t:
for name in ("README.md", "Procfile", "app.py", "requirements.txt"):
payload = (name + " contents\n").encode()
ti = tarfile.TarInfo(name)
ti.size = len(payload)
t.addfile(ti, io.BytesIO(payload))
PY
}
create_evil_certs_tar() {
local OUTPUT="$1"
python3 - "$OUTPUT" <<'PY'
import io, sys, tarfile
output = sys.argv[1]
with tarfile.open(output, "w") as t:
link = tarfile.TarInfo("pwn")
link.type = tarfile.SYMTYPE
link.linkname = "/tmp"
t.addfile(link)
payload = b"canary content\n"
fi = tarfile.TarInfo("pwn/dokku-archive-security-canary.txt")
fi.size = len(payload)
t.addfile(fi, io.BytesIO(payload))
crt = b"-----BEGIN CERTIFICATE-----\nfake\n-----END CERTIFICATE-----\n"
key = b"-----BEGIN PRIVATE KEY-----\nfake\n-----END PRIVATE KEY-----\n"
tcrt = tarfile.TarInfo("server.crt")
tcrt.size = len(crt)
t.addfile(tcrt, io.BytesIO(crt))
tkey = tarfile.TarInfo("server.key")
tkey.size = len(key)
t.addfile(tkey, io.BytesIO(key))
PY
}
@test "(archive-security) git:from-archive rejects tar with absolute symlink target" {
create_absolute_symlink_tar "$ARCHIVE_TMP_DIR/evil.tar" "tar"
run /bin/bash -c "cat $ARCHIVE_TMP_DIR/evil.tar | dokku git:from-archive $TEST_APP --"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "absolute targets"
[[ ! -f /tmp/dokku-archive-security-canary.txt ]]
}
@test "(archive-security) git:from-archive rejects tar.gz with absolute symlink target" {
create_absolute_symlink_tar "$ARCHIVE_TMP_DIR/evil.tar.gz" "tar.gz"
run /bin/bash -c "cat $ARCHIVE_TMP_DIR/evil.tar.gz | dokku git:from-archive --archive-type tar.gz $TEST_APP --"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "absolute targets"
[[ ! -f /tmp/dokku-archive-security-canary.txt ]]
}
@test "(archive-security) git:from-archive rejects tar with relative traversal symlink" {
create_relative_traversal_symlink_tar "$ARCHIVE_TMP_DIR/evil.tar" "tar"
run /bin/bash -c "cat $ARCHIVE_TMP_DIR/evil.tar | dokku git:from-archive $TEST_APP --"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "symlinks pointing outside extraction directory"
[[ ! -f /tmp/dokku-archive-security-canary.txt ]]
}
@test "(archive-security) git:from-archive rejects tar with absolute paths" {
create_absolute_path_tar "$ARCHIVE_TMP_DIR/evil.tar" "tar"
run /bin/bash -c "cat $ARCHIVE_TMP_DIR/evil.tar | dokku git:from-archive $TEST_APP --"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "absolute paths"
[[ ! -f /tmp/dokku-archive-security-canary.txt ]]
}
@test "(archive-security) git:from-archive rejects tar with parent traversal" {
create_traversal_path_tar "$ARCHIVE_TMP_DIR/evil.tar" "tar"
run /bin/bash -c "cat $ARCHIVE_TMP_DIR/evil.tar | dokku git:from-archive $TEST_APP --"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Archive contains entries with parent directory traversal"
[[ ! -f /tmp/dokku-archive-security-canary.txt ]]
}
@test "(archive-security) certs:add rejects tar with absolute symlink target" {
create_evil_certs_tar "$ARCHIVE_TMP_DIR/evil-certs.tar"
run /bin/bash -c "cat $ARCHIVE_TMP_DIR/evil-certs.tar | dokku certs:add $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "absolute targets"
[[ ! -f /tmp/dokku-archive-security-canary.txt ]]
}
@test "(archive-security) certs:add still works with legitimate tarball" {
run /bin/bash -c "dokku certs:add $TEST_APP < $BATS_TEST_DIRNAME/server_ssl.tar"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(archive-security) git:from-archive enforces archive-max-size property" {
create_safe_multi_file_tar "$ARCHIVE_TMP_DIR/safe.tar"
run /bin/bash -c "dokku git:set --global archive-max-size 1"
assert_success
run /bin/bash -c "cat $ARCHIVE_TMP_DIR/safe.tar | dokku git:from-archive $TEST_APP --"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Archive exceeds maximum allowed size of 1 bytes"
run /bin/bash -c "dokku git:set --global archive-max-size"
assert_success
}
@test "(archive-security) git:from-archive enforces archive-max-files property" {
create_safe_multi_file_tar "$ARCHIVE_TMP_DIR/safe.tar"
run /bin/bash -c "dokku git:set --global archive-max-files 1"
assert_success
run /bin/bash -c "cat $ARCHIVE_TMP_DIR/safe.tar | dokku git:from-archive $TEST_APP --"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "exceeds the maximum of 1"
run /bin/bash -c "dokku git:set --global archive-max-files"
assert_success
}
@test "(archive-security) git:report exposes archive-max-size and archive-max-files" {
run /bin/bash -c "dokku git:report --global --git-global-archive-max-size"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report --global --git-computed-archive-max-size"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "1073741824"
run /bin/bash -c "dokku git:report --global --git-global-archive-max-files"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report --global --git-computed-archive-max-files"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10000"
run /bin/bash -c "dokku git:set --global archive-max-size 2147483648"
assert_success
run /bin/bash -c "dokku git:report --global --git-global-archive-max-size"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "2147483648"
run /bin/bash -c "dokku git:report --global --git-computed-archive-max-size"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "2147483648"
run /bin/bash -c "dokku git:set --global archive-max-size"
assert_success
}

View File

@@ -12,6 +12,130 @@ teardown() {
destroy_app
}
@test "(builder-dockerfile:report) info-flag works before deploy" {
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-dockerfile-path"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-dockerfile:set $TEST_APP dockerfile-path second.Dockerfile"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-dockerfile-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "second.Dockerfile"
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(builder-dockerfile:report) --global --format json" {
run /bin/bash -c "dokku builder-dockerfile:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-dockerfile:report --global --format json | jq -r '.\"global-dockerfile-path\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku builder-dockerfile:report --global --format json | jq -r 'has(\"dockerfile-path\")'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder-dockerfile:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global builder-dockerfile information"
run /bin/bash -c "dokku builder-dockerfile:report --global --builder-dockerfile-global-dockerfile-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku builder-dockerfile:set --global dockerfile-path Dockerfile.custom"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-dockerfile:report --global --builder-dockerfile-global-dockerfile-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "Dockerfile.custom"
run /bin/bash -c "dokku builder-dockerfile:set --global dockerfile-path"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(builder-dockerfile:report) dockerfile-path raw vs computed vs global" {
run /bin/bash -c "dokku builder-dockerfile:set --global dockerfile-path"
assert_success
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-dockerfile-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-global-dockerfile-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-computed-dockerfile-path"
assert_success
assert_output "Dockerfile"
run /bin/bash -c "dokku builder-dockerfile:set --global dockerfile-path Dockerfile.global"
assert_success
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-global-dockerfile-path"
assert_success
assert_output "Dockerfile.global"
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-computed-dockerfile-path"
assert_success
assert_output "Dockerfile.global"
run /bin/bash -c "dokku builder-dockerfile:set $TEST_APP dockerfile-path Dockerfile.app"
assert_success
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-dockerfile-path"
assert_success
assert_output "Dockerfile.app"
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-global-dockerfile-path"
assert_success
assert_output "Dockerfile.global"
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-computed-dockerfile-path"
assert_success
assert_output "Dockerfile.app"
run /bin/bash -c "dokku builder-dockerfile:set $TEST_APP dockerfile-path"
assert_success
run /bin/bash -c "dokku builder-dockerfile:set --global dockerfile-path"
assert_success
run /bin/bash -c "dokku builder-dockerfile:report $TEST_APP --builder-dockerfile-computed-dockerfile-path"
assert_success
assert_output "Dockerfile"
}
@test "(builder-dockerfile:set)" {
run deploy_app dockerfile
echo "output: $output"
@@ -124,6 +248,26 @@ EOF
assert_output "3001/udp 3000/tcp 3003"
}
@test "(builder-dockerfile) core-post-extract renames the configured dockerfile" {
echo "FROM scratch" >"$BATS_TEST_TMPDIR/second.Dockerfile"
run /bin/bash -c "dokku builder-dockerfile:set $TEST_APP dockerfile-path second.Dockerfile"
echo "output: $output"
echo "status: $status"
assert_success
run_plugin_script builder-dockerfile core-post-extract "$TEST_APP" "$BATS_TEST_TMPDIR" HEAD
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $BATS_TEST_TMPDIR/Dockerfile"
assert_success
run /bin/bash -c "test ! -e $BATS_TEST_TMPDIR/second.Dockerfile"
assert_success
}
@test "(builder-dockerfile) ps:rebuild fetches files from image" {
run /bin/bash -c "dokku --trace git:from-image $TEST_APP dokku/smoke-test-app:dockerfile"
echo "output: $output"

View File

@@ -10,7 +10,106 @@ teardown() {
destroy_app
}
@test "(builder-herokuish:report) info-flag works before deploy" {
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-allowed"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-herokuish:set $TEST_APP allowed false"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-allowed"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(builder-herokuish:report) --global --builder-herokuish-global-allowed" {
run /bin/bash -c "dokku builder-herokuish:set --global allowed false"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-herokuish:report --global --builder-herokuish-global-allowed"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder-herokuish:set --global allowed"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(builder-herokuish:report) allowed raw vs computed vs global" {
local default_allowed="true"
[[ "$(dpkg --print-architecture 2>/dev/null || true)" != "amd64" ]] && default_allowed="false"
run /bin/bash -c "dokku builder-herokuish:set --global allowed"
assert_success
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-allowed"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-global-allowed"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-computed-allowed"
assert_success
assert_output "$default_allowed"
run /bin/bash -c "dokku builder-herokuish:set --global allowed false"
assert_success
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-global-allowed"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-computed-allowed"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder-herokuish:set $TEST_APP allowed true"
assert_success
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-allowed"
assert_success
assert_output "true"
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-global-allowed"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder-herokuish:report $TEST_APP --builder-herokuish-computed-allowed"
assert_success
assert_output "true"
run /bin/bash -c "dokku builder-herokuish:set $TEST_APP allowed"
assert_success
run /bin/bash -c "dokku builder-herokuish:set --global allowed"
assert_success
}
@test "(builder-herouish:build .env)" {
run /bin/bash -c "dokku docker-options:add $TEST_APP build '--label=com.dokku.build-test=safe'"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"

View File

@@ -10,6 +10,97 @@ teardown() {
destroy_app
}
@test "(builder-lambda:report) info-flag works before deploy" {
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-lambdayml-path"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-lambda:set $TEST_APP lambdayml-path lambda.alt.yml"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-lambdayml-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "lambda.alt.yml"
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(builder-lambda:report) --global --builder-lambda-global-lambdayml-path" {
run /bin/bash -c "dokku builder-lambda:set --global lambdayml-path lambda.alt.yml"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-lambda:report --global --builder-lambda-global-lambdayml-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "lambda.alt.yml"
run /bin/bash -c "dokku builder-lambda:set --global lambdayml-path"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(builder-lambda:report) lambdayml-path raw vs computed vs global" {
run /bin/bash -c "dokku builder-lambda:set --global lambdayml-path"
assert_success
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-lambdayml-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-global-lambdayml-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-computed-lambdayml-path"
assert_success
assert_output "lambda.yml"
run /bin/bash -c "dokku builder-lambda:set --global lambdayml-path lambda.global.yml"
assert_success
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-global-lambdayml-path"
assert_success
assert_output "lambda.global.yml"
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-computed-lambdayml-path"
assert_success
assert_output "lambda.global.yml"
run /bin/bash -c "dokku builder-lambda:set $TEST_APP lambdayml-path lambda.app.yml"
assert_success
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-lambdayml-path"
assert_success
assert_output "lambda.app.yml"
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-global-lambdayml-path"
assert_success
assert_output "lambda.global.yml"
run /bin/bash -c "dokku builder-lambda:report $TEST_APP --builder-lambda-computed-lambdayml-path"
assert_success
assert_output "lambda.app.yml"
run /bin/bash -c "dokku builder-lambda:set $TEST_APP lambdayml-path"
assert_success
run /bin/bash -c "dokku builder-lambda:set --global lambdayml-path"
assert_success
}
@test "(builder-lambda:set)" {
run /bin/bash -c "dokku config:set $TEST_APP SECRET_KEY=fjdkslafjdk"
echo "output: $output"
@@ -134,6 +225,26 @@ teardown() {
assert_success
}
@test "(builder-lambda) core-post-extract renames the configured lambda.yml" {
echo "---" >"$BATS_TEST_TMPDIR/lambda2.yml"
run /bin/bash -c "dokku builder-lambda:set $TEST_APP lambdayml-path lambda2.yml"
echo "output: $output"
echo "status: $status"
assert_success
run_plugin_script builder-lambda core-post-extract "$TEST_APP" "$BATS_TEST_TMPDIR" HEAD
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $BATS_TEST_TMPDIR/lambda.yml"
assert_success
run /bin/bash -c "test ! -e $BATS_TEST_TMPDIR/lambda2.yml"
assert_success
}
inject_lambda_yml() {
local APP="$1"
local APP_REPO_DIR="$2"

View File

@@ -14,6 +14,97 @@ teardown() {
destroy_app
}
@test "(builder-nixpacks:report) info-flag works before deploy" {
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-nixpackstoml-path"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-nixpacks:set $TEST_APP nixpackstoml-path nixpacks.alt.toml"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-nixpackstoml-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "nixpacks.alt.toml"
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(builder-nixpacks:report) --global --builder-nixpacks-global-nixpackstoml-path" {
run /bin/bash -c "dokku builder-nixpacks:set --global nixpackstoml-path nixpacks.alt.toml"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-nixpacks:report --global --builder-nixpacks-global-nixpackstoml-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "nixpacks.alt.toml"
run /bin/bash -c "dokku builder-nixpacks:set --global nixpackstoml-path"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(builder-nixpacks:report) nixpackstoml-path raw vs computed vs global" {
run /bin/bash -c "dokku builder-nixpacks:set --global nixpackstoml-path"
assert_success
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-nixpackstoml-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-global-nixpackstoml-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-computed-nixpackstoml-path"
assert_success
assert_output "nixpacks.toml"
run /bin/bash -c "dokku builder-nixpacks:set --global nixpackstoml-path nixpacks.global.toml"
assert_success
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-global-nixpackstoml-path"
assert_success
assert_output "nixpacks.global.toml"
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-computed-nixpackstoml-path"
assert_success
assert_output "nixpacks.global.toml"
run /bin/bash -c "dokku builder-nixpacks:set $TEST_APP nixpackstoml-path nixpacks.app.toml"
assert_success
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-nixpackstoml-path"
assert_success
assert_output "nixpacks.app.toml"
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-global-nixpackstoml-path"
assert_success
assert_output "nixpacks.global.toml"
run /bin/bash -c "dokku builder-nixpacks:report $TEST_APP --builder-nixpacks-computed-nixpackstoml-path"
assert_success
assert_output "nixpacks.app.toml"
run /bin/bash -c "dokku builder-nixpacks:set $TEST_APP nixpackstoml-path"
assert_success
run /bin/bash -c "dokku builder-nixpacks:set --global nixpackstoml-path"
assert_success
}
@test "(builder-nixpacks:set)" {
run /bin/bash -c "dokku config:set $TEST_APP SECRET_KEY=fjdkslafjdk"
echo "output: $output"
@@ -55,6 +146,11 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP build '--label=com.dokku.build-test=safe'"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP add_requirements_txt
echo "output: $output"
echo "status: $status"
@@ -113,6 +209,26 @@ teardown() {
assert_output "['task.py', 'some', 'cron', 'task']"
}
@test "(builder-nixpacks) core-post-extract renames the configured nixpacks.toml" {
echo "" >"$BATS_TEST_TMPDIR/nixpacks.alt.toml"
run /bin/bash -c "dokku builder-nixpacks:set $TEST_APP nixpackstoml-path nixpacks.alt.toml"
echo "output: $output"
echo "status: $status"
assert_success
run_plugin_script builder-nixpacks core-post-extract "$TEST_APP" "$BATS_TEST_TMPDIR" HEAD
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $BATS_TEST_TMPDIR/nixpacks.toml"
assert_success
run /bin/bash -c "test ! -e $BATS_TEST_TMPDIR/nixpacks.alt.toml"
assert_success
}
cron_run_wrapper() {
local APP="$1"
local APP_REPO_DIR="$2"

View File

@@ -16,6 +16,97 @@ teardown() {
global_teardown
}
@test "(builder-pack:report) info-flag works before deploy" {
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-projecttoml-path"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-pack:set $TEST_APP projecttoml-path project.alt.toml"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-projecttoml-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "project.alt.toml"
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(builder-pack:report) --global --builder-pack-global-projecttoml-path" {
run /bin/bash -c "dokku builder-pack:set --global projecttoml-path project.alt.toml"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-pack:report --global --builder-pack-global-projecttoml-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "project.alt.toml"
run /bin/bash -c "dokku builder-pack:set --global projecttoml-path"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(builder-pack:report) projecttoml-path raw vs computed vs global" {
run /bin/bash -c "dokku builder-pack:set --global projecttoml-path"
assert_success
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-projecttoml-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-global-projecttoml-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-computed-projecttoml-path"
assert_success
assert_output "project.toml"
run /bin/bash -c "dokku builder-pack:set --global projecttoml-path project.global.toml"
assert_success
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-global-projecttoml-path"
assert_success
assert_output "project.global.toml"
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-computed-projecttoml-path"
assert_success
assert_output "project.global.toml"
run /bin/bash -c "dokku builder-pack:set $TEST_APP projecttoml-path project.app.toml"
assert_success
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-projecttoml-path"
assert_success
assert_output "project.app.toml"
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-global-projecttoml-path"
assert_success
assert_output "project.global.toml"
run /bin/bash -c "dokku builder-pack:report $TEST_APP --builder-pack-computed-projecttoml-path"
assert_success
assert_output "project.app.toml"
run /bin/bash -c "dokku builder-pack:set $TEST_APP projecttoml-path"
assert_success
run /bin/bash -c "dokku builder-pack:set --global projecttoml-path"
assert_success
}
@test "(builder-pack:set)" {
run /bin/bash -c "dokku config:set $TEST_APP SECRET_KEY=fjdkslafjdk"
echo "output: $output"
@@ -87,6 +178,11 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP build '--label=com.dokku.build-test=safe'"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP add_requirements_txt_cnb
echo "output: $output"
echo "status: $status"
@@ -177,6 +273,59 @@ teardown() {
assert_output "['task.py', 'some', 'cron', 'task']"
}
@test "(builder-pack) cron:run with Procfile reference" {
run /bin/bash -c "dokku config:set $TEST_APP SECRET_KEY=fjdkslafjdk"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder:set $TEST_APP selected pack"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP cron_run_procfile_wrapper
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains 'from cnb stack'
assert_output_contains 'Building with buildpack 1' 0
assert_output_contains 'Installing dependencies using pip'
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "echo $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku --quiet cron:run $TEST_APP $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "['task.py', 'test']"
}
@test "(builder-pack) core-post-extract renames the configured project.toml" {
echo "" >"$BATS_TEST_TMPDIR/project2.toml"
run /bin/bash -c "dokku builder-pack:set $TEST_APP projecttoml-path project2.toml"
echo "output: $output"
echo "status: $status"
assert_success
run_plugin_script builder-pack core-post-extract "$TEST_APP" "$BATS_TEST_TMPDIR" HEAD
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $BATS_TEST_TMPDIR/project.toml"
assert_success
run /bin/bash -c "test ! -e $BATS_TEST_TMPDIR/project2.toml"
assert_success
}
cron_run_wrapper() {
local APP="$1"
local APP_REPO_DIR="$2"
@@ -187,3 +336,14 @@ cron_run_wrapper() {
ls -lah "$APP_REPO_DIR"
mv -f "$APP_REPO_DIR/app-cnb-cron.json" "$APP_REPO_DIR/app.json"
}
cron_run_procfile_wrapper() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
APP_REPO_DIR="$(realpath "$APP_REPO_DIR")"
add_requirements_txt "$APP" "$APP_REPO_DIR"
ls -lah "$APP_REPO_DIR"
mv -f "$APP_REPO_DIR/app-cnb-cron-procfile.json" "$APP_REPO_DIR/app.json"
}

View File

@@ -25,6 +25,97 @@ teardown() {
global_teardown
}
@test "(builder-railpack:report) info-flag works before deploy" {
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-railpackjson-path"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-railpack:set $TEST_APP railpackjson-path railpack.alt.json"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-railpackjson-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "railpack.alt.json"
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(builder-railpack:report) --global --builder-railpack-global-railpackjson-path" {
run /bin/bash -c "dokku builder-railpack:set --global railpackjson-path railpack.alt.json"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder-railpack:report --global --builder-railpack-global-railpackjson-path"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "railpack.alt.json"
run /bin/bash -c "dokku builder-railpack:set --global railpackjson-path"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(builder-railpack:report) railpackjson-path raw vs computed vs global" {
run /bin/bash -c "dokku builder-railpack:set --global railpackjson-path"
assert_success
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-railpackjson-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-global-railpackjson-path"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-computed-railpackjson-path"
assert_success
assert_output "railpack.json"
run /bin/bash -c "dokku builder-railpack:set --global railpackjson-path railpack.global.json"
assert_success
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-global-railpackjson-path"
assert_success
assert_output "railpack.global.json"
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-computed-railpackjson-path"
assert_success
assert_output "railpack.global.json"
run /bin/bash -c "dokku builder-railpack:set $TEST_APP railpackjson-path railpack.app.json"
assert_success
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-railpackjson-path"
assert_success
assert_output "railpack.app.json"
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-global-railpackjson-path"
assert_success
assert_output "railpack.global.json"
run /bin/bash -c "dokku builder-railpack:report $TEST_APP --builder-railpack-computed-railpackjson-path"
assert_success
assert_output "railpack.app.json"
run /bin/bash -c "dokku builder-railpack:set $TEST_APP railpackjson-path"
assert_success
run /bin/bash -c "dokku builder-railpack:set --global railpackjson-path"
assert_success
}
@test "(builder-railpack:set)" {
run /bin/bash -c "dokku config:set $TEST_APP SECRET_KEY=fjdkslafjdk"
echo "output: $output"
@@ -66,6 +157,11 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP build '--label=com.dokku.build-test=safe'"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP add_requirements_txt
echo "output: $output"
echo "status: $status"
@@ -124,6 +220,26 @@ teardown() {
assert_output "['task.py', 'some', 'cron', 'task']"
}
@test "(builder-railpack) core-post-extract renames the configured railpack.json" {
echo "{}" >"$BATS_TEST_TMPDIR/railpack.alt.json"
run /bin/bash -c "dokku builder-railpack:set $TEST_APP railpackjson-path railpack.alt.json"
echo "output: $output"
echo "status: $status"
assert_success
run_plugin_script builder-railpack core-post-extract "$TEST_APP" "$BATS_TEST_TMPDIR" HEAD
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $BATS_TEST_TMPDIR/railpack.json"
assert_success
run /bin/bash -c "test ! -e $BATS_TEST_TMPDIR/railpack.alt.json"
assert_success
}
cron_run_wrapper() {
local APP="$1"
local APP_REPO_DIR="$2"

View File

@@ -7,6 +7,7 @@ setup() {
}
teardown() {
dokku builder:set --global skip-cleanup >/dev/null 2>/dev/null || true
destroy_app
}
@@ -175,6 +176,205 @@ teardown() {
assert_line 0 "herokuish"
}
@test "(builder:report) --global --format json" {
run /bin/bash -c "dokku builder:set --global selected dockerfile"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder:report --global --format json | jq -r '.\"builder-global-selected\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dockerfile"
run /bin/bash -c "dokku builder:report --global --format json | jq -r '.\"global-selected\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dockerfile"
run /bin/bash -c "dokku builder:report --global --format json | jq -r 'has(\"builder-selected\")'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder:report --global --format json | jq -r 'has(\"selected\") and has(\"builder-global-selected\")'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder:report --global --format json | jq -r 'has(\"computed-skip-cleanup\") and has(\"builder-computed-skip-cleanup\")'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku builder:report --global"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builder:set --global selected"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(builder:report) selected raw vs computed vs global" {
run /bin/bash -c "dokku builder:set --global selected"
assert_success
run /bin/bash -c "dokku builder:report $TEST_APP --builder-selected"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder:report $TEST_APP --builder-global-selected"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder:report $TEST_APP --builder-computed-selected"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder:set --global selected dockerfile"
assert_success
run /bin/bash -c "dokku builder:report $TEST_APP --builder-global-selected"
assert_success
assert_output "dockerfile"
run /bin/bash -c "dokku builder:report $TEST_APP --builder-computed-selected"
assert_success
assert_output "dockerfile"
run /bin/bash -c "dokku builder:set $TEST_APP selected herokuish"
assert_success
run /bin/bash -c "dokku builder:report $TEST_APP --builder-selected"
assert_success
assert_output "herokuish"
run /bin/bash -c "dokku builder:report $TEST_APP --builder-global-selected"
assert_success
assert_output "dockerfile"
run /bin/bash -c "dokku builder:report $TEST_APP --builder-computed-selected"
assert_success
assert_output "herokuish"
run /bin/bash -c "dokku builder:set $TEST_APP selected"
assert_success
run /bin/bash -c "dokku builder:set --global selected"
assert_success
}
@test "(builder:report) build-dir raw vs computed vs global" {
run /bin/bash -c "dokku builder:set --global build-dir"
assert_success
run /bin/bash -c "dokku builder:report $TEST_APP --builder-build-dir"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder:report $TEST_APP --builder-global-build-dir"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder:report $TEST_APP --builder-computed-build-dir"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder:set --global build-dir global/subdir"
assert_success
run /bin/bash -c "dokku builder:report $TEST_APP --builder-global-build-dir"
assert_success
assert_output "global/subdir"
run /bin/bash -c "dokku builder:report $TEST_APP --builder-computed-build-dir"
assert_success
assert_output "global/subdir"
run /bin/bash -c "dokku builder:set $TEST_APP build-dir app/subdir"
assert_success
run /bin/bash -c "dokku builder:report $TEST_APP --builder-build-dir"
assert_success
assert_output "app/subdir"
run /bin/bash -c "dokku builder:report $TEST_APP --builder-global-build-dir"
assert_success
assert_output "global/subdir"
run /bin/bash -c "dokku builder:report $TEST_APP --builder-computed-build-dir"
assert_success
assert_output "app/subdir"
run /bin/bash -c "dokku builder:set $TEST_APP build-dir"
assert_success
run /bin/bash -c "dokku builder:set --global build-dir"
assert_success
}
@test "(builder:report) skip-cleanup raw vs computed vs global" {
run /bin/bash -c "dokku builder:set --global skip-cleanup"
assert_success
run /bin/bash -c "dokku builder:report $TEST_APP --builder-skip-cleanup"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder:report $TEST_APP --builder-global-skip-cleanup"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku builder:report $TEST_APP --builder-computed-skip-cleanup"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder:set --global skip-cleanup true"
assert_success
run /bin/bash -c "dokku builder:report $TEST_APP --builder-global-skip-cleanup"
assert_success
assert_output "true"
run /bin/bash -c "dokku builder:report $TEST_APP --builder-computed-skip-cleanup"
assert_success
assert_output "true"
run /bin/bash -c "dokku builder:set $TEST_APP skip-cleanup false"
assert_success
run /bin/bash -c "dokku builder:report $TEST_APP --builder-skip-cleanup"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder:report $TEST_APP --builder-global-skip-cleanup"
assert_success
assert_output "true"
run /bin/bash -c "dokku builder:report $TEST_APP --builder-computed-skip-cleanup"
assert_success
assert_output "false"
run /bin/bash -c "dokku builder:set $TEST_APP skip-cleanup"
assert_success
run /bin/bash -c "dokku builder:set --global skip-cleanup"
assert_success
}
@test "(builder:set)" {
run deploy_app python
echo "output: $output"

View File

@@ -184,6 +184,75 @@ teardown() {
assert_output "https://github.com/heroku/heroku-buildpack-golang.git https://github.com/heroku/heroku-buildpack-python.git https://github.com/heroku/heroku-buildpack-php.git"
}
@test "(buildpacks) buildpacks:set --replace - failure" {
run /bin/bash -c "dokku buildpacks:set --replace $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "buildpacks:clear"
run /bin/bash -c "dokku buildpacks:set --replace --index 1 $TEST_APP heroku/nodejs"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "--index"
run /bin/bash -c "dokku buildpacks:set $TEST_APP heroku/nodejs heroku/ruby"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "--replace"
}
@test "(buildpacks) buildpacks:set --replace - atomicity" {
run /bin/bash -c "dokku buildpacks:add $TEST_APP heroku/nodejs"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku buildpacks:set --replace $TEST_APP heroku/ruby nodejs"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku --quiet buildpacks:list $TEST_APP | xargs"
echo "output: $output"
echo "status: $status"
assert_output "https://github.com/heroku/heroku-buildpack-nodejs.git"
}
@test "(buildpacks) buildpacks:set --replace - success" {
run /bin/bash -c "dokku buildpacks:add $TEST_APP heroku/nodejs"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku buildpacks:add $TEST_APP heroku/python"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku buildpacks:set --replace $TEST_APP heroku/ruby heroku/golang heroku/php"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku --quiet buildpacks:list $TEST_APP | xargs"
echo "output: $output"
echo "status: $status"
assert_output "https://github.com/heroku/heroku-buildpack-ruby.git https://github.com/heroku/heroku-buildpack-golang.git https://github.com/heroku/heroku-buildpack-php.git"
run /bin/bash -c "dokku buildpacks:set --replace $TEST_APP heroku/nodejs"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku --quiet buildpacks:list $TEST_APP | xargs"
echo "output: $output"
echo "status: $status"
assert_output "https://github.com/heroku/heroku-buildpack-nodejs.git"
}
@test "(buildpacks) buildpacks:set-property" {
run /bin/bash -c "dokku buildpacks:set-property --global stack gliderlabs/herokuish:latest"
echo "output: $output"
@@ -191,6 +260,69 @@ teardown() {
assert_success
}
@test "(buildpacks:report) stack raw vs computed vs global" {
run /bin/bash -c "dokku buildpacks:set-property --global stack"
assert_success
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r '.\"buildpacks-stack\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r '.\"buildpacks-global-stack\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku buildpacks:set-property --global stack gliderlabs/herokuish:global"
assert_success
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r '.\"buildpacks-global-stack\"'"
assert_success
assert_output "gliderlabs/herokuish:global"
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r '.\"buildpacks-computed-stack\"'"
assert_success
assert_output "gliderlabs/herokuish:global"
run /bin/bash -c "dokku buildpacks:set-property $TEST_APP stack gliderlabs/herokuish:app"
assert_success
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r '.\"buildpacks-stack\"'"
assert_success
assert_output "gliderlabs/herokuish:app"
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r '.\"buildpacks-global-stack\"'"
assert_success
assert_output "gliderlabs/herokuish:global"
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r '.\"buildpacks-computed-stack\"'"
assert_success
assert_output "gliderlabs/herokuish:app"
run /bin/bash -c "dokku buildpacks:set-property $TEST_APP stack"
assert_success
run /bin/bash -c "dokku buildpacks:set-property --global stack"
assert_success
}
@test "(buildpacks:report) emits new stripped JSON keys alongside legacy" {
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r 'has(\"stack\") and has(\"buildpacks-stack\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r 'has(\"global-stack\") and has(\"buildpacks-global-stack\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r 'has(\"computed-stack\") and has(\"buildpacks-computed-stack\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku buildpacks:report $TEST_APP --format json | jq -r 'has(\"list\") and has(\"buildpacks-list\")'"
assert_success
assert_output "true"
}
@test "(buildpacks) buildpacks:remove" {
run /bin/bash -c "dokku buildpacks:set $TEST_APP heroku/nodejs"
echo "output: $output"
@@ -336,6 +468,33 @@ teardown() {
assert_output_contains "heroku-buildpack-python"
}
@test "(buildpacks) deploy with buildpacks from app.json" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_buildpacks_appjson
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "heroku-buildpack-python"
}
template_buildpacks_appjson() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting app.json with buildpacks -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"buildpacks": [
{
"url": "heroku/python"
}
]
}
EOF
echo "injecting requirements.txt -> $APP_REPO_DIR/requirements.txt"
touch "$APP_REPO_DIR/requirements.txt"
}
template_buildpacks_cleanup() {
local APP="$1"
local APP_REPO_DIR="$2"

352
tests/unit/builds.bats Normal file
View File

@@ -0,0 +1,352 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
create_app
}
teardown() {
rm -rf "$DOKKU_LIB_ROOT/data/builds/$TEST_APP" || true
destroy_app
global_teardown
}
write_finished_record() {
local app="$1" id="$2" status="$3" source="${4:-git-hook}" pid="${5:-99999}" kind="${6:-build}" exit_code="${7:-0}"
local dir="$DOKKU_LIB_ROOT/data/builds/$app"
mkdir -p "$dir"
local now
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
cat >"$dir/$id.json" <<EOF
{
"id": "$id",
"app": "$app",
"kind": "$kind",
"pid": $pid,
"started_at": "$now",
"finished_at": "$now",
"status": "$status",
"source": "$source",
"exit_code": $exit_code
}
EOF
: >"$dir/$id.log"
chown -R dokku:dokku "$DOKKU_LIB_ROOT/data/builds"
}
write_running_record() {
local app="$1" id="$2" pid="$3" source="${4:-git-hook}" kind="${5:-build}"
local dir="$DOKKU_LIB_ROOT/data/builds/$app"
mkdir -p "$dir"
local now
now="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
cat >"$dir/$id.json" <<EOF
{
"id": "$id",
"app": "$app",
"kind": "$kind",
"pid": $pid,
"started_at": "$now",
"status": "running",
"source": "$source"
}
EOF
: >"$dir/$id.log"
chown -R dokku:dokku "$DOKKU_LIB_ROOT/data/builds"
}
@test "(builds) builds:help" {
run /bin/bash -c "dokku builds"
echo "output: $output"
echo "status: $status"
assert_output_contains "Manage running and historical builds"
run /bin/bash -c "dokku builds:help"
echo "output: $output"
echo "status: $status"
assert_output_contains "Manage running and historical builds"
}
@test "(builds:list) returns empty list when no builds have run" {
run /bin/bash -c "dokku builds:list $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "No builds recorded"
}
@test "(builds:list) shows a finished record after a successful deploy" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builds:list $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "succeeded"
assert_output_contains "git-hook"
}
@test "(builds:list) shows an abandoned record when the PID is gone but the record is still running" {
write_running_record "$TEST_APP" "ghost001" 99999 "git-hook"
run /bin/bash -c "dokku builds:list $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "abandoned"
}
@test "(builds:list --kind=build) filters to build-kind records" {
write_finished_record "$TEST_APP" "b1" "succeeded" "git-hook" 1001 "build"
write_finished_record "$TEST_APP" "d1" "succeeded" "ps:restart" 1002 "deploy"
run /bin/bash -c "dokku builds:list $TEST_APP --kind build"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "b1"
assert_output_not_contains "d1"
}
@test "(builds:list --kind=deploy) filters to deploy-kind records" {
write_finished_record "$TEST_APP" "b1" "succeeded" "git-hook" 1001 "build"
write_finished_record "$TEST_APP" "d1" "succeeded" "ps:restart" 1002 "deploy"
run /bin/bash -c "dokku builds:list $TEST_APP --kind deploy"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "d1"
assert_output_not_contains "b1"
}
@test "(builds:list --kind=invalid) fails with a usage error" {
run /bin/bash -c "dokku builds:list $TEST_APP --kind=garbage"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid --kind"
}
@test "(builds:set) writes a per-app retention" {
run /bin/bash -c "dokku builds:set $TEST_APP retention 5"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builds:report $TEST_APP --builds-retention"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "5"
}
@test "(builds:set --global) writes the global retention" {
run /bin/bash -c "dokku builds:set --global retention 7"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builds:report $TEST_APP --builds-computed-retention"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "7"
dokku builds:set --global retention "" || true
}
@test "(builds:set) clears the override when called with no value" {
dokku builds:set "$TEST_APP" retention 5
run /bin/bash -c "dokku builds:set $TEST_APP retention"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builds:report $TEST_APP --builds-retention"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
}
@test "(builds:set) rejects non-positive-integer values" {
run /bin/bash -c "dokku builds:set $TEST_APP retention 0"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku builds:set $TEST_APP retention abc"
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(builds:info) returns non-zero for a missing build-id" {
run /bin/bash -c "dokku builds:info $TEST_APP nonexistent"
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(builds:info) returns the recorded fields including --format json" {
write_finished_record "$TEST_APP" "info001" "succeeded" "git-hook" 1234 "build"
run /bin/bash -c "dokku builds:info $TEST_APP info001"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "info001" -1
assert_output_contains "succeeded"
assert_output_contains "Log:"
run /bin/bash -c "dokku builds:info $TEST_APP info001 --format json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "\"id\":\"info001\""
assert_output_contains "\"log_path\":"
}
@test "(builds:cancel) returns 0 with a friendly message when no lock is present" {
run /bin/bash -c "dokku builds:cancel $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "App not currently deploying"
}
@test "(builds:cancel) refuses to cancel a record whose status is not running" {
write_finished_record "$TEST_APP" "done01" "succeeded" "git-hook" 1234 "build"
mkdir -p "$DOKKU_LIB_ROOT/data/apps/$TEST_APP"
echo "done01" >"$DOKKU_LIB_ROOT/data/apps/$TEST_APP/.deploy.lock"
chown dokku:dokku "$DOKKU_LIB_ROOT/data/apps/$TEST_APP/.deploy.lock"
run /bin/bash -c "dokku builds:cancel $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "no longer running"
rm -f "$DOKKU_LIB_ROOT/data/apps/$TEST_APP/.deploy.lock"
}
@test "(builds:cancel) marks an abandoned record as failed instead of canceled" {
write_running_record "$TEST_APP" "abnd01" 99999 "git-hook"
mkdir -p "$DOKKU_LIB_ROOT/data/apps/$TEST_APP"
echo "abnd01" >"$DOKKU_LIB_ROOT/data/apps/$TEST_APP/.deploy.lock"
chown dokku:dokku "$DOKKU_LIB_ROOT/data/apps/$TEST_APP/.deploy.lock"
run /bin/bash -c "dokku builds:cancel $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "already terminated"
run /bin/bash -c "dokku builds:info $TEST_APP abnd01"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "failed"
}
@test "(builds:output) cats the log file for a finished build" {
write_finished_record "$TEST_APP" "out001" "succeeded" "git-hook" 1234 "build"
echo "build log line" >"$DOKKU_LIB_ROOT/data/builds/$TEST_APP/out001.log"
chown dokku:dokku "$DOKKU_LIB_ROOT/data/builds/$TEST_APP/out001.log"
run /bin/bash -c "dokku builds:output $TEST_APP out001"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "build log line"
}
@test "(builds:prune) prunes an app's records to retention" {
dokku builds:set "$TEST_APP" retention 2
for i in 1 2 3 4 5; do
write_finished_record "$TEST_APP" "p$i" "succeeded" "git-hook" $((1000 + i)) "build"
sleep 1
done
run /bin/bash -c "dokku builds:prune $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
count="$(ls $DOKKU_LIB_ROOT/data/builds/$TEST_APP/*.json 2>/dev/null | wc -l)"
echo "remaining: $count"
[[ "$count" -le 2 ]] || (echo "expected <=2 records, got $count" && false)
}
@test "(builds:prune) reaps an abandoned record and finalizes it as failed" {
write_running_record "$TEST_APP" "ghost02" 99999 "git-hook"
run /bin/bash -c "dokku builds:prune $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builds:info $TEST_APP ghost02"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "failed"
}
@test "(builds:prune) skips live-running records" {
local pid=$$
write_running_record "$TEST_APP" "alive02" "$pid" "git-hook"
run /bin/bash -c "dokku builds:prune $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku builds:info $TEST_APP alive02"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "running"
}
@test "(builds) [storage] directory is removed on apps:destroy" {
write_finished_record "$TEST_APP" "del01" "succeeded" "git-hook" 1234 "build"
[[ -d "$DOKKU_LIB_ROOT/data/builds/$TEST_APP" ]]
run /bin/bash -c "dokku --force apps:destroy $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
[[ ! -d "$DOKKU_LIB_ROOT/data/builds/$TEST_APP" ]]
# Recreate so teardown can run cleanly.
create_app
}
@test "(builds:report) emits new stripped JSON keys alongside legacy" {
run /bin/bash -c "dokku builds:report $TEST_APP --format json | jq -r 'has(\"retention\") and has(\"builds-retention\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku builds:report $TEST_APP --format json | jq -r 'has(\"global-retention\") and has(\"builds-global-retention\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku builds:report $TEST_APP --format json | jq -r 'has(\"computed-retention\") and has(\"builds-computed-retention\")'"
assert_success
assert_output "true"
# build-* status keys have no plugin-prefix collision, so they pass through unchanged
run /bin/bash -c "dokku builds:report $TEST_APP --format json | jq -r 'has(\"build-id\")'"
assert_success
assert_output "true"
}

View File

@@ -0,0 +1,84 @@
#!/usr/bin/env bats
load test_helper
setup() {
create_app
}
teardown() {
destroy_app
dokku caddy:set --global log-level >/dev/null 2>&1 || true
dokku caddy:set --global tls-internal >/dev/null 2>&1 || true
}
@test "(caddy:report) info-flag works before deploy" {
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-computed-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(caddy:report) --format json" {
run /bin/bash -c "dokku caddy:set --global log-level"
assert_success
run /bin/bash -c "dokku caddy:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku caddy:report --global --format json | jq -r '.\"computed-log-level\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "ERROR"
run /bin/bash -c "dokku caddy:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global caddy information"
}
@test "(caddy:report) tls-internal raw global computed" {
run /bin/bash -c "dokku caddy:set --global tls-internal"
assert_success
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-tls-internal"
assert_success
assert_output ""
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-computed-tls-internal"
assert_success
assert_output "false"
run /bin/bash -c "dokku caddy:set --global tls-internal true"
assert_success
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-global-tls-internal"
assert_success
assert_output "true"
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-computed-tls-internal"
assert_success
assert_output "true"
run /bin/bash -c "dokku caddy:set $TEST_APP tls-internal false"
assert_success
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-tls-internal"
assert_success
assert_output "false"
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-computed-tls-internal"
assert_success
assert_output "false"
}

View File

@@ -18,6 +18,219 @@ teardown() {
dokku nginx:start
}
@test "(caddy:report) --global global vs computed log-level" {
run /bin/bash -c "dokku caddy:report --global --caddy-global-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku caddy:report --global --caddy-computed-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "ERROR"
run /bin/bash -c "dokku caddy:set --global log-level DEBUG"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku caddy:report --global --caddy-global-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "DEBUG"
run /bin/bash -c "dokku caddy:report --global --caddy-computed-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "DEBUG"
run /bin/bash -c "dokku caddy:set --global log-level"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku caddy:report --global --caddy-global-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku caddy:report --global --caddy-computed-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "ERROR"
}
@test "(caddy:report) --global raw and computed keys in --format json" {
run /bin/bash -c "dokku caddy:report --global --format json | jq -r '.\"global-image\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku caddy:report --global --format json | jq -r '.\"computed-image\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku caddy:report --global --format json | jq -r '.\"global-polling-interval\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku caddy:report --global --format json | jq -r '.\"computed-polling-interval\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "5s"
}
@test "(caddy) global-only keys" {
for key in image letsencrypt-email letsencrypt-server log-level polling-interval; do
run /bin/bash -c "dokku caddy:set $TEST_APP $key somevalue"
echo "key: $key"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "can only be set globally"
done
run /bin/bash -c "dokku caddy:set $TEST_APP tls-internal true"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku caddy:set $TEST_APP tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(caddy:report) tls-internal raw vs computed vs global" {
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-computed-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-global-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku caddy:set $TEST_APP tls-internal true"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-computed-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku caddy:set $TEST_APP tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-computed-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
}
@test "(caddy:set) --global tls-internal" {
run /bin/bash -c "dokku caddy:set --global tls-internal true"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku caddy:report --global --caddy-global-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-computed-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-global-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku caddy:set $TEST_APP tls-internal false"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku caddy:report $TEST_APP --caddy-computed-tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku caddy:set $TEST_APP tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku caddy:set --global tls-internal"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(caddy) caddy:help" {
run /bin/bash -c "dokku caddy"
echo "output: $output"
@@ -137,12 +350,12 @@ teardown() {
assert_success
assert_output "$TEST_APP.${DOKKU_DOMAIN}"
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map"
run /bin/bash -c "dokku ports:report $TEST_APP --ports-map"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-detected"
run /bin/bash -c "dokku ports:report $TEST_APP --ports-map-detected"
echo "output: $output"
echo "status: $status"
assert_output "http:80:5000 https:443:5000"

View File

@@ -41,6 +41,141 @@ teardown() {
assert_output "$help_output"
}
@test "(certs:report) info-flag works before deploy" {
run /bin/bash -c "dokku certs:report $TEST_APP --ssl-hostnames"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku certs:report $TEST_APP --ssl-dir"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "/$TEST_APP/tls"
run /bin/bash -c "dokku certs:report $TEST_APP --ssl-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(certs:report) --global --format json" {
run /bin/bash -c "dokku certs:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
assert_output "{}"
run /bin/bash -c "dokku certs:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global ssl information"
run /bin/bash -c "dokku certs:report --global --ssl-bogus"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(certs:report) reports hostnames and subject for a CN-only certificate" {
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/server.crt $BATS_TMPDIR/tls/server.key"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku certs:report $TEST_APP --ssl-hostnames"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku.me"
run /bin/bash -c "dokku certs:report $TEST_APP --ssl-subject"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "CN=dokku.me"
}
@test "(certs:report) preserves multi-field subject order" {
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/domain.com.crt $BATS_TMPDIR/tls/domain.com.key"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku certs:report $TEST_APP --ssl-subject"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "C=US; ST=California; L=San Francisco; O=Expa; OU=Operations; CN=node-js-app.dokku.me"
run /bin/bash -c "dokku certs:report $TEST_APP --ssl-hostnames"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "node-js-app.dokku.me"
}
@test "(certs:report) reports the CN and all SANs as hostnames" {
local SANS_TLS="$BATS_TMPDIR/tls-sans"
mkdir -p "$SANS_TLS"
tar xf "$BATS_TEST_DIRNAME/server_ssl_sans.tar" -C "$SANS_TLS"
sudo chown -R dokku:dokku "$SANS_TLS"
run /bin/bash -c "dokku certs:add $TEST_APP $SANS_TLS/server.crt $SANS_TLS/server.key"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku certs:report $TEST_APP --ssl-hostnames"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "test.dokku.me www.test.app.dokku.me www.test.dokku.me"
rm -rf "$SANS_TLS"
}
@test "(certs) get_ssl_hostnames parses a CN-only certificate" {
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/server.crt $BATS_TMPDIR/tls/server.key"
echo "output: $output"
echo "status: $status"
assert_success
source "$PLUGIN_CORE_AVAILABLE_PATH/certs/functions"
run get_ssl_hostnames "$TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku.me"
}
@test "(certs) get_ssl_hostnames includes the CN and SANs" {
local SANS_TLS="$BATS_TMPDIR/tls-sans"
mkdir -p "$SANS_TLS"
tar xf "$BATS_TEST_DIRNAME/server_ssl_sans.tar" -C "$SANS_TLS"
sudo chown -R dokku:dokku "$SANS_TLS"
run /bin/bash -c "dokku certs:add $TEST_APP $SANS_TLS/server.crt $SANS_TLS/server.key"
echo "output: $output"
echo "status: $status"
assert_success
source "$PLUGIN_CORE_AVAILABLE_PATH/certs/functions"
run get_ssl_hostnames "$TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_line "test.dokku.me"
assert_line "www.test.dokku.me"
assert_line "www.test.app.dokku.me"
assert_line_count 3
rm -rf "$SANS_TLS"
}
@test "(certs) certs:add" {
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/server.crt $BATS_TMPDIR/tls/server.key"
echo "output: $output"
@@ -48,6 +183,40 @@ teardown() {
assert_success
}
@test "(certs:add) preserves explicit https:443 port mapping" {
run /bin/bash -c "dokku ports:set $TEST_APP http:80:80 https:443:443"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/server.crt $BATS_TMPDIR/tls/server.key"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map"
echo "output: $output"
echo "status: $status"
assert_output "http:80:80 https:443:443"
}
@test "(certs:add) adds default https:443 mapping when none exists" {
run /bin/bash -c "dokku ports:set $TEST_APP http:80:5000"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/server.crt $BATS_TMPDIR/tls/server.key"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map"
echo "output: $output"
echo "status: $status"
assert_output "http:80:5000 https:443:5000"
}
@test "(certs) certs:add with multiple dots in the filename" {
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/domain.com.crt $BATS_TMPDIR/tls/domain.com.key"
echo "output: $output"
@@ -92,6 +261,44 @@ teardown() {
assert_success
}
@test "(certs) certs-set plugin trigger" {
run_plugn_trigger certs-set "$TEST_APP" "$BATS_TMPDIR/tls/server.crt" "$BATS_TMPDIR/tls/server.key"
echo "output: $output"
echo "status: $status"
assert_success
[[ -f "$DOKKU_ROOT/$TEST_APP/tls/server.crt" ]]
[[ -f "$DOKKU_ROOT/$TEST_APP/tls/server.key" ]]
}
@test "(certs) certs-set plugin trigger missing key file" {
run_plugn_trigger certs-set "$TEST_APP" "$BATS_TMPDIR/tls/server.crt" "/nonexistent/server.key"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "KEY file specified not found"
}
@test "(certs) certs-remove plugin trigger" {
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/server.crt $BATS_TMPDIR/tls/server.key"
echo "output: $output"
echo "status: $status"
assert_success
run_plugn_trigger certs-remove "$TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
[[ ! -d "$DOKKU_ROOT/$TEST_APP/tls" ]]
}
@test "(certs) certs-remove plugin trigger without endpoint" {
run_plugn_trigger certs-remove "$TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "An app-specific SSL endpoint is not defined"
}
@test "(certs) certs:show" {
run /bin/bash -c "dokku certs:show fake-app-name 2>&1"
echo "output: $output"

View File

@@ -16,6 +16,94 @@ teardown() {
global_teardown
}
@test "(checks:report) info-flag works before deploy" {
run /bin/bash -c "dokku checks:report $TEST_APP --checks-wait-to-retire"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:set $TEST_APP wait-to-retire 30"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:report $TEST_APP --checks-wait-to-retire"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "30"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(checks:report) --global --format json" {
run /bin/bash -c "dokku checks:set --global wait-to-retire"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:report --global --format json | jq -r '.\"global-wait-to-retire\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku checks:report --global --format json | jq -r '.\"computed-wait-to-retire\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "60"
run /bin/bash -c "dokku checks:set --global wait-to-retire 90"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:report --global --format json | jq -r '.\"global-wait-to-retire\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "90"
run /bin/bash -c "dokku checks:report --global --format json | jq -r '.\"computed-wait-to-retire\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "90"
run /bin/bash -c "dokku checks:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global checks information"
run /bin/bash -c "dokku checks:set --global wait-to-retire"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:report --global --checks-global-wait-to-retire"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku checks:report --global --checks-computed-wait-to-retire"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "60"
}
@test "(checks) checks:help" {
run /bin/bash -c "dokku checks"
echo "output: $output"
@@ -36,7 +124,7 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_DISABLED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-disabled-list"
echo "output: $output"
echo "status: $status"
assert_output "_all_"
@@ -48,30 +136,30 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_DISABLED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-disabled-list"
echo "output: $output"
echo "status: $status"
assert_output "_all_"
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_SKIPPED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
assert_output "none"
run /bin/bash -c "dokku checks:enable $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_DISABLED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-disabled-list"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
assert_output "none"
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_SKIPPED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
assert_output "none"
}
@test "(checks) checks:disable -> checks:skip" {
@@ -80,27 +168,27 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_DISABLED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-disabled-list"
echo "output: $output"
echo "status: $status"
assert_output "web,worker,urgentworker,notifications"
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_SKIPPED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
assert_output "none"
run /bin/bash -c "dokku checks:skip $TEST_APP urgentworker,worker"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_SKIPPED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_output "urgentworker,worker"
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_DISABLED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-disabled-list"
echo "output: $output"
echo "status: $status"
assert_output "web,notifications"
@@ -112,7 +200,7 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_SKIPPED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_output "_all_"
@@ -124,30 +212,30 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_SKIPPED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_output "_all_"
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_DISABLED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-disabled-list"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
assert_output "none"
run /bin/bash -c "dokku checks:enable $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_SKIPPED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
assert_output "none"
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_DISABLED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-disabled-list"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
assert_output "none"
}
@test "(checks) checks:skip -> checks:disable" {
@@ -156,27 +244,27 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_SKIPPED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_output "web,worker,urgentworker,notifications"
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_DISABLED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-disabled-list"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
assert_output "none"
run /bin/bash -c "dokku checks:disable $TEST_APP urgentworker,worker"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_DISABLED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-disabled-list"
echo "output: $output"
echo "status: $status"
assert_output "urgentworker,worker"
run /bin/bash -c "dokku config:get $TEST_APP DOKKU_CHECKS_SKIPPED"
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_output "web,notifications"

View File

@@ -4,16 +4,16 @@ load test_helper
setup() {
global_setup
[[ -f ${DOKKU_ROOT}/ENV ]] && mv -f ${DOKKU_ROOT}/ENV ${DOKKU_ROOT}/ENV.bak
sudo -H -u dokku /bin/bash -c "echo 'export global_test=true' > ${DOKKU_ROOT}/ENV"
mkdir -p "${DOKKU_LIB_ROOT}/config/--global"
[[ -f ${DOKKU_LIB_ROOT}/config/--global/ENV ]] && mv -f ${DOKKU_LIB_ROOT}/config/--global/ENV ${DOKKU_LIB_ROOT}/config/--global/ENV.bak
sudo -H -u dokku /bin/bash -c "echo 'export global_test=true' > ${DOKKU_LIB_ROOT}/config/--global/ENV"
create_app
}
teardown() {
destroy_app
ls -la ${DOKKU_ROOT}
if [[ -f ${DOKKU_ROOT}/ENV.bak ]]; then
mv -f ${DOKKU_ROOT}/ENV.bak ${DOKKU_ROOT}/ENV
if [[ -f ${DOKKU_LIB_ROOT}/config/--global/ENV.bak ]]; then
mv -f ${DOKKU_LIB_ROOT}/config/--global/ENV.bak ${DOKKU_LIB_ROOT}/config/--global/ENV
fi
global_teardown
}

View File

@@ -4,16 +4,16 @@ load test_helper
setup() {
global_setup
[[ -f ${DOKKU_ROOT}/ENV ]] && mv -f ${DOKKU_ROOT}/ENV ${DOKKU_ROOT}/ENV.bak
sudo -H -u dokku /bin/bash -c "echo 'export global_test=true' > ${DOKKU_ROOT}/ENV"
mkdir -p "${DOKKU_LIB_ROOT}/config/--global"
[[ -f ${DOKKU_LIB_ROOT}/config/--global/ENV ]] && mv -f ${DOKKU_LIB_ROOT}/config/--global/ENV ${DOKKU_LIB_ROOT}/config/--global/ENV.bak
sudo -H -u dokku /bin/bash -c "echo 'export global_test=true' > ${DOKKU_LIB_ROOT}/config/--global/ENV"
create_app
}
teardown() {
destroy_app
ls -la ${DOKKU_ROOT}
if [[ -f ${DOKKU_ROOT}/ENV.bak ]]; then
mv -f ${DOKKU_ROOT}/ENV.bak ${DOKKU_ROOT}/ENV
if [[ -f ${DOKKU_LIB_ROOT}/config/--global/ENV.bak ]]; then
mv -f ${DOKKU_LIB_ROOT}/config/--global/ENV.bak ${DOKKU_LIB_ROOT}/config/--global/ENV
fi
global_teardown
}
@@ -399,6 +399,57 @@ teardown() {
assert_output "hello world"
}
@test "(config) config:set --encoded preserves decoded bytes" {
local encoded_echo encoded_printf encoded_echo_n encoded_cat tmpfile
encoded_echo="$(echo "myvalue" | base64 -w 0)"
encoded_printf="$(printf '%s' "myvalue" | base64 -w 0)"
encoded_echo_n="$(echo -n "myvalue" | base64 -w 0)"
tmpfile="$(mktemp)"
printf 'filecontent' >"$tmpfile"
encoded_cat="$(cat "$tmpfile" | base64 -w 0)"
rm -f "$tmpfile"
run /bin/bash -c "dokku config:set --encoded --no-restart $TEST_APP test_echo=$encoded_echo"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP test_echo | wc -c"
echo "output: $output"
echo "status: $status"
assert_output "9"
run /bin/bash -c "dokku config:set --encoded --no-restart $TEST_APP test_printf=$encoded_printf"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP test_printf | wc -c"
echo "output: $output"
echo "status: $status"
assert_output "8"
run /bin/bash -c "dokku config:set --encoded --no-restart $TEST_APP test_echo_n=$encoded_echo_n"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP test_echo_n | wc -c"
echo "output: $output"
echo "status: $status"
assert_output "8"
run /bin/bash -c "dokku config:set --encoded --no-restart $TEST_APP test_cat=$encoded_cat"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:get $TEST_APP test_cat | wc -c"
echo "output: $output"
echo "status: $status"
assert_output "12"
}
@test "(config) config:clear" {
run ssh "dokku@$DOKKU_DOMAIN" config:set $TEST_APP test_var=true test_var2=\"hello world\" test_var3=\"with\\nnewline\"
echo "output: $output"
@@ -535,3 +586,134 @@ teardown() {
echo "status: $status"
assert_output '[{"name":"BKEY","value":"true"},{"name":"aKey","value":"true"},{"name":"bKey","value":"true"},{"name":"zKey","value":"true"}]'
}
@test "(config) install migrates a pre-0.38 ENV file before plugins read it" {
# The checks plugin installs before the config plugin, so before this was
# fixed it read the not-yet-relocated ENV file, found nothing, and migrated
# DOKKU_CHECKS_SKIPPED to the checks property silently doing nothing.
run /bin/bash -c "sudo rm -f ${DOKKU_LIB_ROOT}/config/config/$TEST_APP/env-migrated ${DOKKU_LIB_ROOT}/config/checks/$TEST_APP/skipped"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo 'export DOKKU_CHECKS_SKIPPED=worker' | sudo tee $DOKKU_ROOT/$TEST_APP/ENV && sudo chown dokku:dokku $DOKKU_ROOT/$TEST_APP/ENV"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku plugin:install --core"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:report $TEST_APP --checks-skipped-list"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "worker"
run /bin/bash -c "dokku config:show $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "DOKKU_CHECKS_SKIPPED" 0
run /bin/bash -c "test -f $DOKKU_ROOT/$TEST_APP/ENV"
echo "status: $status"
assert_failure
}
@test "(config) config-migrate-env preserves a stale ENV file without importing it" {
# drain once so the migration is on record, which is the state releases 0.38.0
# through 0.38.25 left behind alongside the ENV file staged below
run_plugn_trigger config-migrate-env
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:set --no-restart $TEST_APP KEEP=new"
echo "output: $output"
echo "status: $status"
assert_success
stage_stale_env "KEEP=old" "RESURRECTED=yes"
run_plugn_trigger config-migrate-env
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "the current config takes precedence for KEEP RESURRECTED"
assert_output_contains "$DOKKU_ROOT/$TEST_APP/ENV.migrated"
assert_output_contains "then delete it"
run /bin/bash -c "dokku config:get $TEST_APP KEEP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "new"
run /bin/bash -c "dokku config:get $TEST_APP RESURRECTED"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "test -f $DOKKU_ROOT/$TEST_APP/ENV"
echo "status: $status"
assert_failure
run /bin/bash -c "sudo cat $DOKKU_ROOT/$TEST_APP/ENV.migrated"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "RESURRECTED"
run /bin/bash -c "sudo rm -f $DOKKU_ROOT/$TEST_APP/ENV.migrated"
echo "status: $status"
assert_success
}
@test "(config) install reports a stale ENV file it did not import" {
# the apps plugin installs before config and drains through a captured
# trigger, so the report only reaches the operator if that stderr is streamed
run_plugn_trigger config-migrate-env
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku config:set --no-restart $TEST_APP KEEP=new"
echo "output: $output"
echo "status: $status"
assert_success
stage_stale_env "KEEP=old"
run /bin/bash -c "dokku plugin:install --core"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$DOKKU_ROOT/$TEST_APP/ENV.migrated"
run /bin/bash -c "dokku config:get $TEST_APP KEEP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "new"
run /bin/bash -c "sudo rm -f $DOKKU_ROOT/$TEST_APP/ENV.migrated"
echo "status: $status"
assert_success
}
stage_stale_env() {
declare desc="writes a legacy ENV file at the pre-0.38 path for the test app"
local contents=""
for pair in "$@"; do
contents+="export $pair\n"
done
run /bin/bash -c "printf '$contents' | sudo tee $DOKKU_ROOT/$TEST_APP/ENV && sudo chown dokku:dokku $DOKKU_ROOT/$TEST_APP/ENV"
echo "output: $output"
echo "status: $status"
assert_success
}

View File

@@ -91,3 +91,32 @@ teardown() {
echo "status: $status"
assert_output "false"
}
@test "(common) fn-docker-args-split does not expand injected commands" {
export DOKKU_TEST_PAYLOAD='--label x=$(id)'
run /bin/bash -c "source '$PLUGIN_CORE_AVAILABLE_PATH/common/functions'; fn-docker-args-split \"\$DOKKU_TEST_PAYLOAD\" | tr '\\0' '\\n'"
echo "output: $output"
echo "status: $status"
assert_success
assert_line 1 'x=$(id)'
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - value was expanded"
export DOKKU_TEST_PAYLOAD='--label x=`id`'
run /bin/bash -c "source '$PLUGIN_CORE_AVAILABLE_PATH/common/functions'; fn-docker-args-split \"\$DOKKU_TEST_PAYLOAD\" | tr '\\0' '\\n'"
echo "output: $output"
echo "status: $status"
assert_success
assert_line 1 'x=`id`'
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - value was expanded"
unset DOKKU_TEST_PAYLOAD
}
@test "(common) fn-docker-args-split preserves quoted tokens" {
run /bin/bash -c "source '$PLUGIN_CORE_AVAILABLE_PATH/common/functions'; fn-docker-args-split \"--label 'a b'\" | tr '\\0' '\\n'"
echo "output: $output"
echo "status: $status"
assert_success
assert_line 0 "--label"
assert_line 1 "a b"
}

View File

@@ -112,6 +112,16 @@ teardown() {
assert_urls "http://dokku.example.com" "http://${TEST_APP}.${DOKKU_DOMAIN}" "https://dokku.example.com" "https://${TEST_APP}.${DOKKU_DOMAIN}" "https://test.${DOKKU_DOMAIN}" "http://test.${DOKKU_DOMAIN}"
}
@test "(core) release_and_deploy does not emit command not found errors" {
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "fn-plugin-property-get-default: command not found"
assert_output_not_contains "fn-plugin-property-get: command not found"
assert_output_not_contains "/common/property-functions: No such file or directory"
}
@test "(core) git-remote (off-port)" {
run deploy_app nodejs-express ssh://dokku@127.0.0.1:22333/$TEST_APP
echo "output: $output"

263
tests/unit/cron-1.bats Normal file
View File

@@ -0,0 +1,263 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
create_app
mkdir -p /var/lib/dokku/plugins/available/cron-entries
mkdir -p /var/lib/dokku/plugins/enabled/cron-entries
cat >"/var/lib/dokku/plugins/available/cron-entries/plugin.toml" <<EOF
[plugin]
description = "dokku test cron-entries plugin"
version = "0.0.1"
[plugin.config]
EOF
cp /var/lib/dokku/plugins/available/cron-entries/plugin.toml /var/lib/dokku/plugins/enabled/cron-entries/plugin.toml
}
teardown() {
rm -rf /var/lib/dokku/plugins/available/cron-entries /var/lib/dokku/plugins/enabled/cron-entries
# restore the default scheduler before destroy: a k3s-scheduled app cannot be
# torn down cleanly without a cluster, and would otherwise leak into the next
# test's cleanup_apps
dokku scheduler:set "$TEST_APP" selected docker-local 2>/dev/null || true
destroy_app
global_teardown
}
@test "(cron) cron:help" {
run /bin/bash -c "dokku cron"
echo "output: $output"
echo "status: $status"
assert_output_contains "Manage scheduled cron tasks"
help_output="$output"
run /bin/bash -c "dokku cron:help"
echo "output: $output"
echo "status: $status"
assert_output_contains "Manage scheduled cron tasks"
assert_output "$help_output"
}
@test "(cron) installed" {
run /bin/bash -c "test -f /etc/sudoers.d/dokku-cron"
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(cron) scheduler-uses-host-cron" {
run /bin/bash -c "dokku plugin:trigger scheduler-uses-host-cron docker-local"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku plugin:trigger scheduler-uses-host-cron k3s"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku plugin:trigger scheduler-uses-host-cron null"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku plugin:trigger scheduler-uses-host-cron bogus-scheduler"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
}
@test "(cron) invalid [missing-keys]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_invalid
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(cron) invalid [schedule]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_invalid_schedule
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(cron) invalid [seconds]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_invalid_schedule_seconds
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(cron) create [single-verbose]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_single
echo "output: $output"
echo "status: $status"
assert_success
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "dokku cron:run $TEST_APP $cron_id"
assert_output_contains "python3 task.py schedule" 0
}
@test "(cron) create [single-short]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_short
echo "output: $output"
echo "status: $status"
assert_success
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "dokku cron:run $TEST_APP $cron_id"
assert_output_contains "python3 task.py daily" 0
}
@test "(cron) k3s-scheduled app skips host crontab" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_single
echo "output: $output"
echo "status: $status"
assert_success
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "dokku cron:run $TEST_APP $cron_id"
# switch the app to a scheduler that manages its own cron backend
run /bin/bash -c "dokku scheduler:set $TEST_APP selected k3s"
echo "output: $output"
echo "status: $status"
assert_success
# regenerating the host crontab must now skip the k3s app's tasks, leaving
# no host-cron tasks and therefore no crontab file
run /bin/bash -c "dokku plugin:trigger scheduler-cron-write"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(cron) crontab format [no raw command leakage]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_single
echo "output: $output"
echo "status: $status"
assert_success
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "dokku cron:run $TEST_APP $cron_id"
# User command must never appear verbatim in the crontab - the crontab
# only references the cron ID, and cron:run resolves the command at run
# time and exec's it inside the container.
assert_output_contains "python3 task.py schedule" 0
}
template_cron_file_invalid() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting invalid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"key": "value"
}
]
}
EOF
}
template_cron_file_invalid_schedule() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting invalid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py",
"schedule": "@nonstandard"
}
]
}
EOF
}
template_cron_file_invalid_schedule_seconds() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting invalid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py",
"schedule": "0 5 * * * *"
}
]
}
EOF
}
template_cron_file_valid_single() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting valid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py schedule",
"schedule": "5 5 5 5 5"
}
]
}
EOF
}
template_cron_file_valid_short() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting valid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py daily",
"schedule": "@daily"
}
]
}
EOF
}

411
tests/unit/cron-2.bats Normal file
View File

@@ -0,0 +1,411 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
create_app
mkdir -p /var/lib/dokku/plugins/available/cron-entries
mkdir -p /var/lib/dokku/plugins/enabled/cron-entries
cat >"/var/lib/dokku/plugins/available/cron-entries/plugin.toml" <<EOF
[plugin]
description = "dokku test cron-entries plugin"
version = "0.0.1"
[plugin.config]
EOF
cp /var/lib/dokku/plugins/available/cron-entries/plugin.toml /var/lib/dokku/plugins/enabled/cron-entries/plugin.toml
}
teardown() {
rm -rf /var/lib/dokku/plugins/available/cron-entries /var/lib/dokku/plugins/enabled/cron-entries
# restore the default scheduler before destroy: a k3s-scheduled app cannot be
# torn down cleanly without a cluster, and would otherwise leak into the next
# test's cleanup_apps
dokku scheduler:set "$TEST_APP" selected docker-local 2>/dev/null || true
destroy_app
global_teardown
}
@test "(cron:report) --global --format json" {
run /bin/bash -c "dokku cron:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"cron-maintenance\")'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"cron-global-maintenance\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"global-maintenance\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"cron-computed-maintenance\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"computed-maintenance\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"cron-global-mailfrom\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"global-mailfrom\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"cron-computed-mailfrom\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"computed-mailfrom\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"cron-global-mailto\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"global-mailto\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"cron-computed-mailto\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global --format json | jq -r 'has(\"computed-mailto\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report --global"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(cron:set) --global mailto" {
run /bin/bash -c "dokku cron:set --global mailto admin@example.com"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "unknown flag"
run /bin/bash -c "dokku cron:report --global --format json | jq -r '.\"cron-global-mailto\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "admin@example.com"
run /bin/bash -c "dokku cron:report --global --format json | jq -r '.\"cron-computed-mailto\"'"
assert_success
assert_output "admin@example.com"
run /bin/bash -c "dokku cron:set --global mailto"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "unknown flag"
run /bin/bash -c "dokku cron:report --global --format json | jq -r '.\"cron-global-mailto\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku cron:report --global --format json | jq -r '.\"cron-computed-mailto\"'"
assert_success
assert_output ""
}
@test "(cron:set) --global mailfrom" {
run /bin/bash -c "dokku cron:set --global mailfrom dokku@example.com"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "unknown flag"
run /bin/bash -c "dokku cron:report --global --format json | jq -r '.\"cron-global-mailfrom\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku@example.com"
run /bin/bash -c "dokku cron:report --global --format json | jq -r '.\"cron-computed-mailfrom\"'"
assert_success
assert_output "dokku@example.com"
run /bin/bash -c "dokku cron:set --global mailfrom"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "unknown flag"
run /bin/bash -c "dokku cron:report --global --format json | jq -r '.\"cron-global-mailfrom\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku cron:report --global --format json | jq -r '.\"cron-computed-mailfrom\"'"
assert_success
assert_output ""
}
@test "(cron:set) --global maintenance" {
run /bin/bash -c "dokku cron:set --global maintenance true"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "unknown flag"
run /bin/bash -c "dokku cron:report --global --format json | jq -r '.\"cron-global-maintenance\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:set --global maintenance"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "unknown flag"
}
@test "(cron:report) maintenance raw vs computed vs global" {
run /bin/bash -c "dokku cron:set --global maintenance"
assert_success
run /bin/bash -c "dokku cron:report $TEST_APP --format json | jq -r '.\"cron-maintenance\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku cron:report $TEST_APP --format json | jq -r '.\"cron-global-maintenance\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku cron:report $TEST_APP --format json | jq -r '.\"cron-computed-maintenance\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku cron:set --global maintenance true"
assert_success
run /bin/bash -c "dokku cron:report $TEST_APP --format json | jq -r '.\"cron-global-maintenance\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report $TEST_APP --format json | jq -r '.\"cron-computed-maintenance\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:set $TEST_APP maintenance true"
assert_success
run /bin/bash -c "dokku cron:report $TEST_APP --format json | jq -r '.\"cron-maintenance\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:report $TEST_APP --format json | jq -r '.\"cron-global-maintenance\"'"
assert_success
assert_output "true"
# cron computed-maintenance returns "true" if either per-app or global is
# "true" (cron's logic at plugins/cron/report.go::reportComputedMaintenance
# is OR-not-override: any "true" wins). This is intentional for maintenance
# mode - a per-app "false" does NOT override a global "true".
run /bin/bash -c "dokku cron:report $TEST_APP --format json | jq -r '.\"cron-computed-maintenance\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku cron:set $TEST_APP maintenance"
assert_success
run /bin/bash -c "dokku cron:set --global maintenance"
assert_success
}
@test "(cron:set) --global rejects task maintenance properties" {
run /bin/bash -c "dokku cron:set --global maintenance.fakeid true"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Task maintenance properties cannot be set globally"
}
@test "(cron) create [multiple]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_multiple
echo "output: $output"
echo "status: $status"
assert_success
first_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
second_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[1].id')"
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "dokku cron:run $TEST_APP $first_id"
assert_output_contains "dokku cron:run $TEST_APP $second_id"
assert_output_contains "python3 task.py first" 0
assert_output_contains "python3 task.py second" 0
}
@test "(cron) cron:list --format json" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku cron:list $TEST_APP --format json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "echo $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
}
@test "(cron) cron:run" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid
echo "output: $output"
echo "status: $status"
assert_success
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "echo $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "['task.py', 'schedule']"
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[1].id')"
run /bin/bash -c "echo $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "['task.py', 'schedule', 'now']"
}
@test "(cron) cron:suspend cron:resume" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_multiple
echo "output: $output"
echo "status: $status"
assert_success
first_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
second_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[1].id')"
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "dokku cron:run $TEST_APP $first_id"
assert_output_contains "dokku cron:run $TEST_APP $second_id"
run /bin/bash -c "dokku cron:report $TEST_APP --cron-maintenance-$first_id"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku cron:suspend $TEST_APP $first_id"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku cron:report $TEST_APP --cron-maintenance-$first_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "dokku cron:run $TEST_APP $first_id" 0
assert_output_contains "dokku cron:run $TEST_APP $second_id"
run /bin/bash -c "dokku cron:resume $TEST_APP $first_id"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku cron:report $TEST_APP --cron-maintenance-$first_id"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "dokku cron:run $TEST_APP $first_id"
assert_output_contains "dokku cron:run $TEST_APP $second_id"
}
template_cron_file_valid() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting valid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py schedule",
"schedule": "5 5 5 5 5"
},
{
"command": "python3 task.py schedule now",
"schedule": "6 5 5 5 5"
}
]
}
EOF
}
template_cron_file_valid_multiple() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting valid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py first",
"schedule": "5 5 5 5 5"
},
{
"command": "python3 task.py second",
"schedule": "@daily"
}
]
}
EOF
}

View File

@@ -18,52 +18,14 @@ EOF
teardown() {
rm -rf /var/lib/dokku/plugins/available/cron-entries /var/lib/dokku/plugins/enabled/cron-entries
# restore the default scheduler before destroy: a k3s-scheduled app cannot be
# torn down cleanly without a cluster, and would otherwise leak into the next
# test's cleanup_apps
dokku scheduler:set "$TEST_APP" selected docker-local 2>/dev/null || true
destroy_app
global_teardown
}
@test "(cron) cron:help" {
run /bin/bash -c "dokku cron"
echo "output: $output"
echo "status: $status"
assert_output_contains "Manage scheduled cron tasks"
help_output="$output"
run /bin/bash -c "dokku cron:help"
echo "output: $output"
echo "status: $status"
assert_output_contains "Manage scheduled cron tasks"
assert_output "$help_output"
}
@test "(cron) installed" {
run /bin/bash -c "test -f /etc/sudoers.d/dokku-cron"
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(cron) invalid [missing-keys]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_invalid
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(cron) invalid [schedule]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_invalid_schedule
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(cron) invalid [seconds]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_invalid_schedule_seconds
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(cron) create [empty]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
@@ -76,46 +38,6 @@ teardown() {
assert_failure
}
@test "(cron) create [single-verbose]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_single
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "python3 task.py schedule"
}
@test "(cron) create [single-short]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_short
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "python3 task.py daily"
}
@test "(cron) create [multiple]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_multiple
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "python3 task.py first"
assert_output_contains "python3 task.py second"
}
@test "(cron) injected entries" {
echo "echo '@daily;/bin/true'" >/var/lib/dokku/plugins/enabled/cron-entries/cron-entries
chmod +x /var/lib/dokku/plugins/enabled/cron-entries/cron-entries
@@ -182,57 +104,11 @@ teardown() {
assert_failure
}
@test "(cron) cron:list --format json" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid
@test "(cron) invalid [command]" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_injection
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku cron:list $TEST_APP --format json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "echo $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
}
@test "(cron) cron:run" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid
echo "output: $output"
echo "status: $status"
assert_success
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "echo $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "['task.py', 'schedule']"
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[1].id')"
run /bin/bash -c "echo $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "['task.py', 'schedule', 'now']"
assert_failure
}
@test "(cron) cron:run concurrency_policy forbid" {
@@ -266,193 +142,132 @@ teardown() {
assert_failure
}
@test "(cron) cron:suspend cron:resume" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_valid_multiple
@test "(cron) container labels regression" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_long_running
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "python3 task.py first"
assert_output_contains "python3 task.py second"
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "echo $cron_id"
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id --detach"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
first_command="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].command')"
run /bin/bash -c "echo $first_command"
run /bin/bash -c "docker ps --filter \"label=com.dokku.cron-id=$cron_id\" -q | xargs docker inspect -f '{{ index .Config.Labels \"com.dokku.cron-id\" }}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
assert_output "$cron_id"
run /bin/bash -c "dokku cron:report $TEST_APP --cron-maintenance-$cron_id"
run /bin/bash -c "docker ps --filter \"label=com.dokku.cron-id=$cron_id\" -q | xargs docker inspect -f '{{ index .Config.Labels \"com.dokku.concurrency-policy\" }}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "allow"
run /bin/bash -c "docker ps --filter \"label=com.dokku.cron-id=$cron_id\" -q | xargs docker inspect -f '{{ index .Config.Labels \"com.dokku.container-type\" }}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "cron"
run /bin/bash -c "docker ps --filter \"label=com.dokku.cron-id=$cron_id\" -q | xargs docker inspect -f '{{ index .Config.Labels \"com.dokku.app-name\" }}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "$TEST_APP"
run /bin/bash -c "docker ps --filter \"label=com.dokku.cron-id=$cron_id\" -q | xargs docker inspect -f '{{ index .Config.Labels \"com.dokku.active-deadline-seconds\" }}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "86400"
}
@test "(cron:run) retires containers past their active deadline" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_long_running
echo "output: $output"
echo "status: $status"
assert_success
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id --detach --ttl-seconds 1"
echo "output: $output"
echo "status: $status"
assert_success
expiring_container="$output"
run /bin/bash -c "docker container inspect $expiring_container --format '{{ index .Config.Labels \"com.dokku.active-deadline-seconds\" }}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "1"
run /bin/bash -c "docker container inspect $expiring_container --format '{{ index .Config.Labels \"com.dokku.container-type\" }}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "cron"
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id --detach --ttl-seconds 300"
echo "output: $output"
echo "status: $status"
assert_success
surviving_container="$output"
run /bin/bash -c "sleep 2"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:retire"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "docker container ls --filter \"label=com.dokku.container-type=cron\" --format '{{ .Names }}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "$expiring_container"
assert_output_contains "$surviving_container"
}
@test "(cron:run) --ttl-seconds must be a positive integer" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_long_running
echo "output: $output"
echo "status: $status"
assert_success
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id --detach --ttl-seconds 0"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "--ttl-seconds must be a positive integer"
run /bin/bash -c "dokku cron:suspend $TEST_APP $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku cron:report $TEST_APP --cron-maintenance-$cron_id"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "python3 task.py first" 0
assert_output_contains "python3 task.py second"
run /bin/bash -c "dokku cron:resume $TEST_APP $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku cron:report $TEST_APP --cron-maintenance-$cron_id"
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id --detach --ttl-seconds -1"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "cat /var/spool/cron/crontabs/dokku"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "python3 task.py first"
assert_output_contains "python3 task.py second"
assert_output_contains "--ttl-seconds must be a positive integer"
}
template_cron_file_invalid() {
template_cron_file_injection() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting invalid cron app.json -> $APP_REPO_DIR/app.json"
echo "injecting injection-attempt cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"key": "value"
}
]
}
EOF
}
template_cron_file_invalid_schedule() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting invalid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py",
"schedule": "@nonstandard"
}
]
}
EOF
}
template_cron_file_invalid_schedule_seconds() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting invalid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py",
"schedule": "0 5 * * * *"
}
]
}
EOF
}
template_cron_file_valid() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting valid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py schedule",
"schedule": "5 5 5 5 5"
},
{
"command": "python3 task.py schedule now",
"schedule": "6 5 5 5 5"
}
]
}
EOF
}
template_cron_file_valid_single() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting valid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py schedule",
"schedule": "5 5 5 5 5"
}
]
}
EOF
}
template_cron_file_valid_short() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting valid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py daily",
"schedule": "@daily"
}
]
}
EOF
}
template_cron_file_valid_multiple() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting valid cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 task.py first",
"schedule": "5 5 5 5 5"
},
{
"command": "python3 task.py second",
"schedule": "@daily"
"command": "echo CRON_OK; echo hi > /tmp/appjson-injection-test.txt",
"schedule": "* * * * *"
}
]
}
@@ -476,3 +291,20 @@ template_cron_file_concurrency_forbid() {
}
EOF
}
template_cron_file_long_running() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting long-running cron app.json -> $APP_REPO_DIR/app.json"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "sleep 30",
"schedule": "0 0 * * *"
}
]
}
EOF
}

View File

@@ -0,0 +1,57 @@
#!/usr/bin/env bats
REPO_ROOT="$(cd "$BATS_TEST_DIRNAME/../.." && pwd)"
NGINX_CONF="${REPO_ROOT}/docker/etc/nginx/conf.d/zz-dokku-health.conf"
FINISH_SCRIPT="${REPO_ROOT}/docker/etc/runit/runsvdir/default/dokku-restore/finish"
MY_INIT_SCRIPT="${REPO_ROOT}/docker/etc/my_init.d/10_dokku_init"
DOCKERFILE="${REPO_ROOT}/Dockerfile"
@test "(docker-image) [healthcheck] nginx health conf is shipped via the docker overlay" {
[[ -f "$NGINX_CONF" ]]
grep -qE "listen[[:space:]]+127\.0\.0\.1:18080" "$NGINX_CONF"
grep -qE "location = /_dokku/health" "$NGINX_CONF"
grep -qE "/var/run/dokku/ready" "$NGINX_CONF"
grep -qE "default_type[[:space:]]+text/plain" "$NGINX_CONF"
}
@test "(docker-image) [healthcheck] finish script touches sentinel after waiting for sshd and nginx" {
[[ -f "$FINISH_SCRIPT" ]]
local sshd_line nginx_line touch_line
sshd_line=$(grep -nE "/dev/tcp/127\.0\.0\.1/22" "$FINISH_SCRIPT" | head -n1 | cut -d: -f1)
nginx_line=$(grep -nE "/dev/tcp/127\.0\.0\.1/80" "$FINISH_SCRIPT" | head -n1 | cut -d: -f1)
touch_line=$(grep -nE "touch /var/run/dokku/ready" "$FINISH_SCRIPT" | head -n1 | cut -d: -f1)
[[ -n "$sshd_line" ]]
[[ -n "$nginx_line" ]]
[[ -n "$touch_line" ]]
((touch_line > sshd_line))
((touch_line > nginx_line))
}
@test "(docker-image) [healthcheck] my_init clears stale sentinel on container boot" {
[[ -f "$MY_INIT_SCRIPT" ]]
local rm_line mkdir_line plugin_line hostname_line
rm_line=$(grep -nE "rm -f /var/run/dokku/ready" "$MY_INIT_SCRIPT" | head -n1 | cut -d: -f1)
mkdir_line=$(grep -nE "mkdir -p /var/run/dokku( |$)" "$MY_INIT_SCRIPT" | head -n1 | cut -d: -f1)
plugin_line=$(grep -nE "plugin:install" "$MY_INIT_SCRIPT" | head -n1 | cut -d: -f1)
hostname_line=$(grep -nE "domains:set-global" "$MY_INIT_SCRIPT" | head -n1 | cut -d: -f1)
[[ -n "$rm_line" ]]
[[ -n "$mkdir_line" ]]
[[ -n "$plugin_line" ]]
[[ -n "$hostname_line" ]]
((rm_line < plugin_line))
((rm_line < hostname_line))
((mkdir_line < plugin_line))
((mkdir_line < hostname_line))
}
@test "(docker-image) [healthcheck] Dockerfile declares HEALTHCHECK with the expected endpoint" {
[[ -f "$DOCKERFILE" ]]
grep -qE "^HEALTHCHECK" "$DOCKERFILE"
grep -qE "http://127\.0\.0\.1:18080/_dokku/health" "$DOCKERFILE"
grep -qE "\-\-start-period" "$DOCKERFILE"
}

View File

@@ -0,0 +1,326 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
create_app
}
teardown() {
destroy_app
global_teardown
}
@test "(docker-options:add) --process scopes option to one process type" {
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP deploy '-p 8080:5000'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --process web --phase deploy"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "-p 8080:5000"
run /bin/bash -c "dokku docker-options:list $TEST_APP --phase deploy"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "-p 8080:5000" 0
}
@test "(docker-options:add) multiple --process flags add to each process" {
run /bin/bash -c "dokku docker-options:add --process web --process worker $TEST_APP deploy '-v /shared:/shared'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --process web --phase deploy"
echo "output: $output"
assert_output "-v /shared:/shared"
run /bin/bash -c "dokku docker-options:list $TEST_APP --process worker --phase deploy"
echo "output: $output"
assert_output "-v /shared:/shared"
}
@test "(docker-options:add) without --process keeps default-scope behaviour" {
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '-v /tmp/shared:/shared'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --phase deploy"
echo "output: $output"
assert_output_contains "-v /tmp/shared:/shared"
run /bin/bash -c "dokku docker-options:report $TEST_APP --docker-options-deploy"
echo "output: $output"
assert_output_contains "-v /tmp/shared:/shared"
}
@test "(docker-options:add) rejects --process for non-deploy phases" {
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP build '--shm-size 256m'"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "deploy phase"
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP run '--shm-size 256m'"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP build,deploy '--shm-size 256m'"
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(docker-options:add) rejects reserved _default_ process name" {
run /bin/bash -c "dokku docker-options:add --process _default_ $TEST_APP deploy '-v /tmp:/tmp'"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "_default_"
}
@test "(docker-options:add) warns on process types missing from Procfile" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:add --process nonexistent $TEST_APP deploy '-v /tmp:/tmp'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "nonexistent"
}
@test "(docker-options:remove) --process removes from a single process" {
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP deploy '-p 8080:5000'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:add --process worker $TEST_APP deploy '-p 9000:9000'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:remove --process web $TEST_APP deploy '-p 8080:5000'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --process web --phase deploy"
echo "output: $output"
assert_output ""
run /bin/bash -c "dokku docker-options:list $TEST_APP --process worker --phase deploy"
echo "output: $output"
assert_output "-p 9000:9000"
}
@test "(docker-options:clear) --process clears only that process" {
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP deploy '-p 8080:5000'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:add --process worker $TEST_APP deploy '-p 9000:9000'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:clear --process web $TEST_APP deploy"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --process web --phase deploy"
echo "output: $output"
assert_output ""
run /bin/bash -c "dokku docker-options:list $TEST_APP --process worker --phase deploy"
echo "output: $output"
assert_output "-p 9000:9000"
}
@test "(docker-options:list) --phase is required" {
run /bin/bash -c "dokku docker-options:list $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "phase"
}
@test "(docker-options:report) exposes dynamic per-process keys" {
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP deploy '-p 8080:5000'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:report $TEST_APP --docker-options-deploy.web"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "-p 8080:5000"
run /bin/bash -c "dokku docker-options:report $TEST_APP"
echo "output: $output"
assert_success
assert_output_contains "Docker options deploy web"
assert_output_contains "-p 8080:5000"
}
@test "(docker-options:report) --format json carries process-scoped options" {
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP deploy '-p 8080:5000'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '-v /logs:/logs'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:report $TEST_APP --format json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains '"docker-options-deploy.web"'
assert_output_contains '"deploy.web"'
assert_output_contains '"deploy.web-list"'
assert_output_contains "-p 8080:5000" 3
assert_output_contains '"docker-options-deploy"'
assert_output_contains '"deploy"'
assert_output_contains '"deploy-list"'
assert_output_contains "-v /logs:/logs" 3
}
@test "(docker-options:report) --format json exposes structured -list keys" {
run /bin/bash -c "dokku docker-options:add $TEST_APP build --build-arg X=Y --link foo --link bar"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP deploy '-p 8080:5000'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '-v /logs:/logs' '--memory=512m'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --label 'com.example.description=my app'"
echo "output: $output"
assert_success
run /bin/bash -c "dokku docker-options:report $TEST_APP --format json | jq -e '.\"build-list\" | length == 3'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:report $TEST_APP --format json | jq -e '.\"deploy-list\" | length == 3'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:report $TEST_APP --format json | jq -e '.\"deploy-list\" | index(\"--memory=512m\") != null'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:report $TEST_APP --format json | jq -e '.\"deploy-list\"[] | select(test(\"my app\"))'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:report $TEST_APP --format json | jq -e '.\"deploy.web-list\"[]'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "-p 8080:5000"
run /bin/bash -c "dokku docker-options:report $TEST_APP --format json | jq -e 'has(\"docker-options-deploy-list\") | not'"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(docker-options:report) --format json emits empty -list arrays for unset phases" {
run /bin/bash -c "dokku docker-options:report $TEST_APP --format json | jq -e '.\"build-list\" == [] and .\"deploy-list\" == [] and .\"run-list\" == []'"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(docker-options) clone copies default and per-process options" {
local CLONE_APP="${TEST_APP}-clone"
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP deploy '-p 8080:5000'"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '-v /logs:/logs'"
assert_success
run /bin/bash -c "dokku apps:clone --skip-deploy $TEST_APP $CLONE_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $CLONE_APP --process web --phase deploy"
echo "output: $output"
assert_output "-p 8080:5000"
run /bin/bash -c "dokku docker-options:list $CLONE_APP --phase deploy"
echo "output: $output"
assert_output_contains "-v /logs:/logs"
dokku --force apps:destroy "$CLONE_APP" || true
}
@test "(docker-options) rename moves default and per-process options" {
local RENAMED_APP="${TEST_APP}-renamed"
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP deploy '-p 8080:5000'"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '-v /logs:/logs'"
assert_success
run /bin/bash -c "dokku apps:rename $TEST_APP $RENAMED_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $RENAMED_APP --process web --phase deploy"
assert_output "-p 8080:5000"
run /bin/bash -c "dokku docker-options:list $RENAMED_APP --phase deploy"
assert_output_contains "-v /logs:/logs"
[[ ! -d "/var/lib/dokku/config/docker-options/$TEST_APP" ]]
TEST_APP="$RENAMED_APP"
}
@test "(docker-options) deploy with web-only port mapping does not break worker" {
run /bin/bash -c "dokku docker-options:add --process web $TEST_APP deploy '-p 8080:5000'"
echo "output: $output"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP web_worker_callback
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "App container failed to start" 0
assert_output_contains "all ports are allocated" 0
run /bin/bash -c "dokku ps:report $TEST_APP --ps-status-web-1"
echo "output: $output"
assert_output_contains "running"
run /bin/bash -c "dokku ps:report $TEST_APP --ps-status-worker-1"
echo "output: $output"
assert_output_contains "running"
}
web_worker_callback() {
local APP="$1"
local APP_REPO_DIR="$2"
cat >"$APP_REPO_DIR/Procfile" <<EOF
web: python3 -u web.py
worker: python3 -u worker.py
EOF
}

View File

@@ -193,7 +193,6 @@ teardown() {
echo "status: $status"
assert_success
assert_output_contains "-v /tmp" 0
assert_output_contains "Docker options deploy: --restart=on-failure:10"
}
@test "(docker-options) docker-options:remove (build phase)" {
@@ -264,11 +263,7 @@ teardown() {
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo '-v /tmp' >> $DOKKU_ROOT/$TEST_APP/DOCKER_OPTIONS_DEPLOY"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo '# comment' >> $DOKKU_ROOT/$TEST_APP/DOCKER_OPTIONS_DEPLOY"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy \"-v /tmp\""
echo "output: $output"
echo "status: $status"
assert_success
@@ -290,16 +285,31 @@ teardown() {
assert_output "/tmp:{} /var/tmp:{}"
}
@test "(docker-options) deploy does not expand command substitution in option values [buildpacks]" {
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '--label=com.dokku.test=\$(id)'"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
CID=$(<$DOKKU_ROOT/$TEST_APP/CONTAINER.web.1)
run /bin/bash -c "docker inspect $CID --format '{{ index .Config.Labels \"com.dokku.test\" }}'"
echo "output: $output"
echo "status: $status"
assert_output '$(id)'
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - option value was expanded"
}
@test "(docker-options) deploy with options [dockerfile]" {
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy \"-v /var/tmp\""
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo '-v /tmp' >> $DOKKU_ROOT/$TEST_APP/DOCKER_OPTIONS_DEPLOY"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo '# comment' >> $DOKKU_ROOT/$TEST_APP/DOCKER_OPTIONS_DEPLOY"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy \"-v /tmp\""
echo "output: $output"
echo "status: $status"
assert_success
@@ -370,3 +380,116 @@ teardown() {
assert_success
assert_output_contains "TOKEN is: hello" 2
}
@test "(docker-options:add) splits multi-flag input into separate options" {
run /bin/bash -c "dokku docker-options:add $TEST_APP build --build-arg X=Y --link foo --link bar"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --phase build"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "--build-arg X=Y"
assert_output_contains "--link foo"
assert_output_contains "--link bar"
run /bin/bash -c "dokku docker-options:report $TEST_APP --docker-options-build"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "--build-arg X=Y"
assert_output_contains "--link foo"
assert_output_contains "--link bar"
}
@test "(docker-options:remove) symmetrically removes multi-flag input" {
run /bin/bash -c "dokku docker-options:add $TEST_APP build --build-arg X=Y --link foo --link bar"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:remove $TEST_APP build --build-arg X=Y --link foo --link bar"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --phase build"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
}
@test "(docker-options:add) lifts misplaced --process out of option content" {
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --link foo --process web"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --process web --phase deploy"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--link foo"
run /bin/bash -c "dokku docker-options:list $TEST_APP --phase deploy"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "--link foo" 0
}
@test "(docker-options:remove) removes an option stored in the pre-0.38.25 unquoted form" {
# Options drained out of a legacy DOCKER_OPTIONS_<PHASE> file by
# releases before 0.38.26 were copied verbatim, so a value holding
# shell metacharacters sits in the property store unquoted. Seed that
# state directly - the add path always canonicalizes, so it cannot
# produce it.
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy \"-v /tmp/keep:/keep\""
echo "output: $output"
echo "status: $status"
assert_success
legacy_option='--group-add $(getent group docker | cut -d: -f3)'
property_file="/var/lib/dokku/config/docker-options/$TEST_APP/_default_.deploy"
run /bin/bash -c "printf '%s\n-v /tmp/keep:/keep\n' '$legacy_option' | sudo tee $property_file"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "sudo chown dokku:dokku $property_file"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --phase deploy"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$legacy_option"
run /bin/bash -c "dokku docker-options:remove $TEST_APP deploy '$legacy_option'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:list $TEST_APP --phase deploy"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "-v /tmp/keep:/keep"
}
@test "(docker-options) dockerfile build skips unsupported flags from multi-flag input" {
run /bin/bash -c "dokku docker-options:add $TEST_APP build --build-arg PAYPAL_CLIENT_ID=abc --link postgres"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app dockerfile
echo "output: $output"
echo "status: $status"
assert_success
}

View File

@@ -28,6 +28,37 @@ teardown() {
assert_output "$help_output"
}
@test "(domains:report) --global --format json" {
run /bin/bash -c "dokku domains:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku domains:report --global --format json | jq -r 'keys[]' | grep -v 'global-' | wc -l"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "0"
run /bin/bash -c "dokku domains:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global domains information"
run /bin/bash -c "dokku domains:report --global --domains-global-enabled"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku domains:report --global --domains-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(domains) domains" {
run /bin/bash -c "dokku domains:report $TEST_APP 2>/dev/null | grep ${TEST_APP}.${DOKKU_DOMAIN}"
echo "output: $output"
@@ -393,6 +424,62 @@ teardown() {
assert_success
}
@test "(domains) app rename preserves all subdomains across multiple global vhosts" {
run /bin/bash -c "dokku domains:set-global ${DOKKU_DOMAIN} dokku.test"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku domains:set $TEST_APP $TEST_APP.${DOKKU_DOMAIN} $TEST_APP.dokku.test custom.example.com"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku apps:rename $TEST_APP other-name"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku domains:report other-name --domains-app-vhosts"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "other-name.${DOKKU_DOMAIN} other-name.dokku.test custom.example.com"
run /bin/bash -c "dokku apps:rename other-name $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(domains) app rename preserves custom domains when no global vhost is set" {
run /bin/bash -c "dokku domains:clear-global"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku domains:set $TEST_APP custom.example.com other.example.org"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku apps:rename $TEST_APP other-name"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku domains:report other-name --domains-app-vhosts"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "custom.example.com other.example.org"
run /bin/bash -c "dokku apps:rename other-name $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(domains) verify warning on ipv4/ipv6 domain name" {
touch /etc/nginx/sites-enabled/default
rm "$DOKKU_ROOT/VHOST"

View File

@@ -12,6 +12,229 @@ teardown() {
global_teardown
}
@test "(git:report) info-flag works before deploy" {
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "master"
run /bin/bash -c "dokku git:set $TEST_APP deploy-branch main"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "main"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "main"
run /bin/bash -c "dokku git:set $TEST_APP deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "master"
run /bin/bash -c "dokku git:report $TEST_APP --git-sha"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(git:report) keep-git-dir raw vs computed vs global" {
run /bin/bash -c "dokku git:set --global keep-git-dir"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-keep-git-dir"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku git:report $TEST_APP --git-global-keep-git-dir"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-keep-git-dir"
assert_success
assert_output "false"
run /bin/bash -c "dokku git:set --global keep-git-dir true"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-global-keep-git-dir"
assert_success
assert_output "true"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-keep-git-dir"
assert_success
assert_output "true"
run /bin/bash -c "dokku git:set $TEST_APP keep-git-dir false"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-keep-git-dir"
assert_success
assert_output "false"
run /bin/bash -c "dokku git:report $TEST_APP --git-global-keep-git-dir"
assert_success
assert_output "true"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-keep-git-dir"
assert_success
assert_output "false"
run /bin/bash -c "dokku git:set $TEST_APP keep-git-dir"
assert_success
run /bin/bash -c "dokku git:set --global keep-git-dir"
assert_success
}
@test "(git:report) rev-env-var raw" {
# Unset the per-app property file if a previous test left it written-empty
# (git:set <app> rev-env-var "" intentionally writes an empty file as the
# documented "unset" behavior, which masks the report's default fallback).
run /bin/bash -c "dokku git:set $TEST_APP rev-env-var COMMIT_SHA"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-rev-env-var"
assert_success
assert_output "COMMIT_SHA"
run /bin/bash -c "dokku git:set $TEST_APP rev-env-var"
assert_success
}
@test "(git:report) source-image raw" {
run /bin/bash -c "dokku git:report $TEST_APP --git-source-image"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku git:set $TEST_APP source-image alpine:3.20"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-source-image"
assert_success
assert_output "alpine:3.20"
run /bin/bash -c "dokku git:set $TEST_APP source-image"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-source-image"
assert_success
assert_output_not_exists
}
@test "(git:report) raw and computed keys in --format json" {
run /bin/bash -c "dokku git:report $TEST_APP --format json | jq -r '.\"deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report $TEST_APP --format json | jq -r '.\"computed-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "master"
run /bin/bash -c "dokku git:report $TEST_APP --format json | jq -r '.\"keep-git-dir\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report $TEST_APP --format json | jq -r '.\"computed-keep-git-dir\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
}
@test "(git:report) --global raw and computed keys" {
run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"global-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"computed-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "master"
run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"global-archive-max-files\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"computed-archive-max-files\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10000"
run /bin/bash -c "dokku git:set --global deploy-branch main"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"global-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "main"
run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"computed-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "main"
run /bin/bash -c "dokku git:set --global deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"global-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
}
@test "(git) git:help" {
run /bin/bash -c "dokku git"
echo "output: $output"

View File

@@ -93,6 +93,145 @@ teardown() {
echo "status: $status"
assert_success
assert_output_contains "Setting netrc auth entry for host github.com"
run /bin/bash -c "printf 'piped-password' | dokku git:auth github.com piped-username"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting netrc auth entry for host github.com"
run /bin/bash -c "netrc get --netrc-file ${DOKKU_ROOT}/.netrc github.com"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "piped-username:piped-password"
run /bin/bash -c "stat -c '%a' ${DOKKU_ROOT}/.netrc"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "600"
run /bin/bash -c "stat -c '%U:%G' ${DOKKU_ROOT}/.netrc"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku:dokku"
}
@test "(git) git:auth repairs world-readable .netrc" {
run /bin/bash -c "chmod 644 ${DOKKU_ROOT}/.netrc"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "stat -c '%a' ${DOKKU_ROOT}/.netrc"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "644"
run /bin/bash -c "dokku git:auth github.com username password"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting netrc auth entry for host github.com"
run /bin/bash -c "stat -c '%a' ${DOKKU_ROOT}/.netrc"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "600"
run /bin/bash -c "stat -c '%U:%G' ${DOKKU_ROOT}/.netrc"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku:dokku"
}
@test "(git) git:auth unset preserves 0600 on remaining .netrc" {
run /bin/bash -c "dokku git:auth github.com username password"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:auth other.example.com user2 pass2"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "chmod 644 ${DOKKU_ROOT}/.netrc"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:auth github.com"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Removing netrc auth entry for host github.com"
if [[ -f "${DOKKU_ROOT}/.netrc" ]]; then
run /bin/bash -c "stat -c '%a' ${DOKKU_ROOT}/.netrc"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "600"
fi
}
@test "(git) git:auth-status" {
run /bin/bash -c "dokku git:auth-status"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku git:auth-status github.com"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:auth github.com username password"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:auth-status github.com"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku git:auth-status github.com username password"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:auth-status github.com username wrong-password"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku git:auth-status github.com other-username password"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku git:auth-status github.com username"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Missing password for netrc auth entry"
run /bin/bash -c "printf 'password' | dokku git:auth-status github.com username"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "printf 'wrong-password' | dokku git:auth-status github.com username"
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(git) git:sync new [errors]" {
@@ -631,7 +770,7 @@ teardown() {
}
@test "(git:sync) --skip-deploy-branch" {
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
@@ -659,7 +798,7 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
@@ -671,7 +810,7 @@ teardown() {
assert_success
assert_output_contains "skipping deploy-branch setting"
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
@@ -679,7 +818,7 @@ teardown() {
}
@test "(git:sync) --build --skip-deploy-branch" {
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
@@ -692,7 +831,7 @@ teardown() {
assert_output_contains "skipping deploy-branch setting"
assert_output_contains "Application deployed"
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
@@ -700,7 +839,7 @@ teardown() {
}
@test "(git:sync) --build-if-changes --skip-deploy-branch" {
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
@@ -713,7 +852,7 @@ teardown() {
assert_output_contains "skipping deploy-branch setting"
assert_output_contains "Application deployed"
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
@@ -725,7 +864,94 @@ teardown() {
assert_success
assert_output_contains "Skipping build as no changes were detected"
run /bin/bash -c "dokku git:report $TEST_APP --git-deploy-branch"
run /bin/bash -c "dokku git:report $TEST_APP --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "master"
}
@test "(git:report) --format json" {
run /bin/bash -c "dokku git:set $TEST_APP deploy-branch main"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --format json | jq -r '.\"deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "main"
run /bin/bash -c "dokku git:report $TEST_APP --format json | jq -r '.\"global-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report $TEST_APP --format json | jq -r '.\"computed-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "main"
run /bin/bash -c "dokku git:report $TEST_APP --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report $TEST_APP --format json --git-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "--format flag cannot be specified when specifying an info flag"
}
@test "(git:report) --global" {
run /bin/bash -c "dokku git:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global git information"
assert_output_contains "Git global deploy branch"
}
@test "(git:report) --global --format json" {
run /bin/bash -c "dokku git:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"global-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report --global --format json | jq -r '.\"computed-deploy-branch\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "master"
run /bin/bash -c "dokku git:report --global --format json | jq -r 'has(\"deploy-branch\")'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku git:report --global --git-global-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku git:report --global --git-computed-deploy-branch"
echo "output: $output"
echo "status: $status"
assert_success

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env bats
load test_helper
setup() {
create_app
}
teardown() {
destroy_app
dokku haproxy:set --global log-level >/dev/null 2>&1 || true
dokku haproxy:set --global refresh-conf >/dev/null 2>&1 || true
}
@test "(haproxy:report) info-flag works before deploy" {
run /bin/bash -c "dokku haproxy:set --global refresh-conf"
assert_success
run /bin/bash -c "dokku haproxy:report $TEST_APP --haproxy-computed-refresh-conf"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10"
run /bin/bash -c "dokku haproxy:report $TEST_APP --haproxy-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(haproxy:report) --format json" {
run /bin/bash -c "dokku haproxy:set --global log-level"
assert_success
run /bin/bash -c "dokku haproxy:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku haproxy:report --global --format json | jq -r '.\"computed-log-level\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "ERROR"
run /bin/bash -c "dokku haproxy:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global haproxy information"
}
@test "(haproxy:report) refresh-conf global computed" {
run /bin/bash -c "dokku haproxy:set --global refresh-conf"
assert_success
run /bin/bash -c "dokku haproxy:report --global --haproxy-global-refresh-conf"
assert_success
assert_output ""
run /bin/bash -c "dokku haproxy:report --global --haproxy-computed-refresh-conf"
assert_success
assert_output "10"
run /bin/bash -c "dokku haproxy:set --global refresh-conf 30"
assert_success
run /bin/bash -c "dokku haproxy:report --global --haproxy-global-refresh-conf"
assert_success
assert_output "30"
run /bin/bash -c "dokku haproxy:report --global --haproxy-computed-refresh-conf"
assert_success
assert_output "30"
}

View File

@@ -7,6 +7,7 @@ setup() {
dokku nginx:stop
dokku haproxy:set --global letsencrypt-server https://acme-staging-v02.api.letsencrypt.org/directory
dokku haproxy:set --global letsencrypt-email
dokku haproxy:set --global refresh-conf 2
dokku haproxy:start
create_app
}
@@ -15,6 +16,7 @@ teardown() {
global_teardown
destroy_app
dokku haproxy:stop
dokku haproxy:set --global refresh-conf
dokku nginx:start
}
@@ -32,6 +34,94 @@ teardown() {
assert_output "$help_output"
}
@test "(haproxy) global-only keys" {
for key in image log-level letsencrypt-email letsencrypt-server refresh-conf; do
run /bin/bash -c "dokku haproxy:set $TEST_APP $key somevalue"
echo "key: $key"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "can only be set globally"
done
}
@test "(haproxy) refresh-conf" {
run /bin/bash -c "dokku haproxy:set $TEST_APP refresh-conf 2"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "can only be set globally"
run /bin/bash -c "dokku haproxy:set --global refresh-conf 5"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku haproxy:report --global --haproxy-global-refresh-conf"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "5"
run /bin/bash -c "dokku haproxy:report --global --haproxy-computed-refresh-conf"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "5"
run /bin/bash -c "dokku haproxy:show-config"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "EASYHAPROXY_REFRESH_CONF=5"
run /bin/bash -c "dokku haproxy:set --global refresh-conf"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku haproxy:report --global --haproxy-global-refresh-conf"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku haproxy:report --global --haproxy-computed-refresh-conf"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10"
}
@test "(haproxy:report) --global raw and computed keys in --format json" {
run /bin/bash -c "dokku haproxy:set --global refresh-conf"
assert_success
run /bin/bash -c "dokku haproxy:report --global --format json | jq -r '.\"global-image\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku haproxy:report --global --format json | jq -r '.\"computed-image\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku haproxy:report --global --format json | jq -r '.\"global-refresh-conf\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku haproxy:report --global --format json | jq -r '.\"computed-refresh-conf\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10"
}
@test "(haproxy) log-level" {
run /bin/bash -c "dokku haproxy:set --global log-level DEBUG"
echo "output: $output"
@@ -60,11 +150,7 @@ teardown() {
echo "status: $status"
assert_success
run /bin/bash -c "curl --silent $(dokku url $TEST_APP)"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "python/http.server"
assert_http_localhost_response_contains "http" "$TEST_APP.$DOKKU_DOMAIN" "80" "/" "python/http.server"
}
@test "(haproxy) multiple domains" {
@@ -88,8 +174,6 @@ teardown() {
echo "status: $status"
assert_success
sleep 5
run /bin/bash -c "dokku logs $TEST_APP"
echo "output: $output"
echo "status: $status"
@@ -162,12 +246,12 @@ teardown() {
assert_success
assert_output "true"
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map"
run /bin/bash -c "dokku ports:report $TEST_APP --ports-map"
echo "output: $output"
echo "status: $status"
assert_output_not_exists
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-detected"
run /bin/bash -c "dokku ports:report $TEST_APP --ports-map-detected"
echo "output: $output"
echo "status: $status"
assert_output "http:80:5000 https:443:5000"

View File

@@ -22,9 +22,10 @@ teardown() {
local CIDS=$(get_app_container_ids "$APP")
run "$DOCKER_BIN" container top "$CIDS"
run /bin/bash -c "$DOCKER_BIN container top $CIDS"
echo "output: $output"
assert_output_contains "<defunct>" "0"
echo "status: $status"
assert_output_not_contains "<defunct>"
}
@test "(init) dockerfile no tini" {
@@ -37,9 +38,10 @@ teardown() {
local CIDS=$(get_app_container_ids "$APP")
run "$DOCKER_BIN" container top "$CIDS"
run /bin/bash -c "$DOCKER_BIN container top $CIDS"
echo "output: $output"
assert_output_contains "<defunct>" "0"
echo "status: $status"
assert_output_not_contains "<defunct>"
}
@test "(init) dockerfile with tini" {
@@ -52,7 +54,8 @@ teardown() {
local CIDS=$(get_app_container_ids "$APP")
run "$DOCKER_BIN" container top "$CIDS"
run /bin/bash -c "$DOCKER_BIN container top $CIDS"
echo "output: $output"
assert_output_contains "<defunct>" "0"
echo "status: $status"
assert_output_not_contains "<defunct>"
}

1261
tests/unit/logs-1.bats Normal file

File diff suppressed because it is too large Load Diff

425
tests/unit/logs-2.bats Normal file
View File

@@ -0,0 +1,425 @@
#!/usr/bin/env bats
load test_helper
setup() {
rm "${BATS_PARENT_TMPNAME}.skip" || true
global_setup
}
teardown() {
destroy_app
# a leftover app-label-alias makes every later test's vector source filter on
# a label that dokku never applies to a container, which silently disables log
# collection for the rest of the file
dokku logs:set --global app-label-alias >/dev/null 2>/dev/null || true
dokku logs:set --global vector-image >/dev/null 2>/dev/null || true
dokku logs:set --global vector-networks >/dev/null 2>/dev/null || true
dokku logs:set --global vector-sink >/dev/null 2>/dev/null || true
dokku logs:set --global vector-cron-sink >/dev/null 2>/dev/null || true
docker network rm test-vector-net-a >/dev/null || true
docker network rm test-vector-net-b >/dev/null || true
global_teardown
}
@test "(logs) vector validates the generated cron routing config" {
run create_app
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-cron-sink console://?encoding[codec]=text"
assert_success
run /bin/bash -c "dokku logs:vector-start 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
# unit tests cannot catch a VRL syntax error or a malformed route schema
run /bin/bash -c "docker exec vector-vector-1 vector validate --no-environment /etc/vector/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
# the relabel branches are generated VRL too, and a syntax error there would
# take the whole config down rather than just the rename
run /bin/bash -c "dokku logs:set --global vector-sink console://?encoding[codec]=json"
assert_success
run /bin/bash -c "dokku logs:set --global app-label-alias global_alt_name"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP app-label-alias app_alt_name"
assert_success
run /bin/bash -c "docker exec vector-vector-1 vector validate --no-environment /etc/vector/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-stop 2>&1"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP app-label-alias"
assert_success
run /bin/bash -c "dokku logs:set --global app-label-alias"
assert_success
run /bin/bash -c "dokku logs:set --global vector-sink"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-cron-sink"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink"
assert_success
}
# the regression test for the alias silently disabling collection: the source
# has to keep filtering on the label dokku applies, while the event that comes
# out the other end carries the alias instead
@test "(logs) a non-default app-label-alias still ships logs" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink 'console://?encoding[codec]=json'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set --global app-label-alias alt_name"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-start 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
run start_vector_probe VECTOR_ALIAS_OK
echo "output: $output"
echo "status: $status"
assert_success
run wait_for_vector_alias_event VECTOR_ALIAS_OK alt_name
echo "output: $output"
echo "status: $status"
dump_vector_diagnostics "$TEST_APP"
assert_success
run /bin/bash -c "docker container rm --force vector-alias-probe"
assert_success
run /bin/bash -c "dokku logs:vector-stop 2>&1"
assert_success
}
@test "(logs) logs:vector-start attaches configured networks" {
docker network create test-vector-net-a >/dev/null
docker network create test-vector-net-b >/dev/null
run /bin/bash -c "dokku logs:set --global vector-networks test-vector-net-a,test-vector-net-b 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-start 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container is running"
run /bin/bash -c "sudo docker inspect --format='{{range \$k, \$v := .NetworkSettings.Networks}}{{\$k}} {{end}}' vector-vector-1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "test-vector-net-a"
assert_output_contains "test-vector-net-b"
assert_output_contains "bridge" 0
run /bin/bash -c "dokku logs:vector-stop 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-start 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container is running"
run /bin/bash -c "sudo docker inspect --format='{{range \$k, \$v := .NetworkSettings.Networks}}{{\$k}} {{end}}' vector-vector-1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "test-vector-net-a"
assert_output_contains "test-vector-net-b"
assert_output_contains "bridge" 0
run /bin/bash -c "dokku logs:set --global vector-networks 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-stop 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-start 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "sudo docker inspect --format='{{range \$k, \$v := .NetworkSettings.Networks}}{{\$k}} {{end}}' vector-vector-1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "bridge"
run /bin/bash -c "dokku logs:vector-stop 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(logs) logs:vector" {
run /bin/bash -c "dokku logs:vector-logs 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Vector container does not exist"
run /bin/bash -c "dokku apps:create example.com"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-start 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container is running"
run /bin/bash -c "sudo docker inspect --format='{{.HostConfig.RestartPolicy.Name}}' vector-vector-1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "unless-stopped"
run /bin/bash -c "dokku logs:vector-logs 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container logs"
run /bin/bash -c "dokku --force apps:destroy example.com"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-logs --num 10 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container logs"
assert_output_contains "vector:" 10
assert_line_count 11
run /bin/bash -c "dokku logs:vector-logs --num 5 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container logs"
assert_output_contains "vector:" 5
assert_line_count 6
run /bin/bash -c "docker stop vector-vector-1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-logs 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container logs"
assert_output_contains "Vector container is not running"
run /bin/bash -c "dokku logs:vector-stop 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Stopping and removing vector container"
}
@test "(logs) vector-cron-sink routes cron task output to the cron sink" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP template_cron_file_marker
echo "output: $output"
echo "status: $status"
assert_success
cron_id="$(dokku cron:list $TEST_APP --format json | jq -r '.[0].id')"
echo "cron_id: $cron_id"
run /bin/bash -c "dokku logs:vector-start 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
# both sinks write to vector's own stdout, with different codecs, so the sink
# an event was routed to is identifiable without depending on a writable
# mount: the cron branch emits json carrying the fields the remap adds, while
# anything reaching the plain sink emits the bare message
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink 'console://?encoding[codec]=text'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-cron-sink 'console://?encoding[codec]=json'"
echo "output: $output"
echo "status: $status"
assert_success
# vector reloads via --watch-config, so wait for the routing to be live
run wait_for_vector_route "$TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku cron:run $TEST_APP $cron_id"
echo "output: $output"
echo "status: $status"
assert_success
run wait_for_vector_cron_event VECTOR_CRON_OK "$cron_id"
echo "output: $output"
echo "status: $status"
dump_vector_diagnostics "$TEST_APP"
assert_success
# a bare message line would mean the event reached the plain sink instead of
# being routed onto the cron branch
run count_vector_plain_lines VECTOR_CRON_OK
echo "output: $output"
echo "status: $status"
assert_output "0"
run /bin/bash -c "dokku logs:vector-stop 2>&1"
assert_success
}
wait_for_vector_route() {
declare desc="waits for the vector config on disk to contain the app's cron router"
declare APP="$1"
local i
for i in $(seq 1 30); do
if jq -e ".transforms[\"docker-router:$APP\"]" /var/lib/dokku/data/logs/vector.json >/dev/null 2>&1; then
return 0
fi
sleep 1
done
echo "timed out waiting for the cron router in vector.json"
return 1
}
start_vector_probe() {
declare desc="runs a container carrying only the label dokku applies, emitting a marker for long enough for vector to attach"
declare MARKER="$1"
docker container run --detach --name vector-alias-probe \
--label "com.dokku.app-name=$TEST_APP" \
gliderlabs/herokuish \
bash -c "for i in \$(seq 1 30); do echo $MARKER; sleep 1; done"
}
wait_for_vector_alias_event() {
declare desc="waits for a marker to arrive carrying the configured alias in place of the default label"
declare MARKER="$1" ALIAS="$2"
local i
for i in $(seq 1 60); do
if docker logs vector-vector-1 2>/dev/null | grep "$MARKER" \
| jq -e --arg alias "$ALIAS" \
'select(.label[$alias] != null and .label["com.dokku.app-name"] == null)' >/dev/null 2>/dev/null; then
return 0
fi
sleep 1
done
echo "timed out waiting for a $MARKER event labelled $ALIAS"
return 1
}
wait_for_vector_cron_event() {
declare desc="waits for a marker to arrive on the cron branch, carrying the fields the remap adds"
declare MARKER="$1" CRON_ID="$2"
local i
for i in $(seq 1 60); do
if docker logs vector-vector-1 2>/dev/null | grep "$MARKER" \
| jq -e --arg id "$CRON_ID" 'select(.dokku_cron_id == $id)' >/dev/null 2>/dev/null; then
return 0
fi
sleep 1
done
echo "timed out waiting for a cron-routed $MARKER event with dokku_cron_id=$CRON_ID"
return 1
}
count_vector_plain_lines() {
declare desc="counts bare message lines, which only the text-encoded plain sink emits"
declare MARKER="$1"
docker logs vector-vector-1 2>/dev/null | grep -c -x "$MARKER" || true
}
dump_vector_diagnostics() {
declare desc="prints the state needed to tell apart the ways cron shipping can fail"
declare APP="$1"
# sources matter as much as routing here: a stale app-label-alias makes the
# source filter on a label no container carries, which collects nothing
echo "--- generated config ---"
jq '{sources, transforms, sinks}' /var/lib/dokku/data/logs/vector.json || true
echo "--- containers carrying the app label ---"
docker ps --all --filter "label=com.dokku.app-name=$APP" --format '{{.Names}} {{.Status}}' || true
echo "--- vector stdout, where both sinks write ---"
docker logs vector-vector-1 2>/dev/null | tail -20 || true
# vector reports template_failed and other component errors on stderr, so
# keep it separate from the collected log lines on stdout
echo "--- vector stderr ---"
docker logs vector-vector-1 2>&1 1>/dev/null | tail -20 || true
}
template_cron_file_marker() {
declare desc="writes an app.json with a cron task emitting a known marker"
local APP="$1" APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
echo "injecting cron app.json -> $APP_REPO_DIR/app.json"
# cron_task.py sleeps either side of its output. a task that exits
# immediately is removed before vector can attach to it, which is documented
# behavior rather than something this test should assert against
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"cron": [
{
"command": "python3 cron_task.py VECTOR_CRON_OK",
"schedule": "@daily"
}
]
}
EOF
}

View File

@@ -1,717 +0,0 @@
#!/usr/bin/env bats
load test_helper
setup() {
rm "${BATS_PARENT_TMPNAME}.skip" || true
global_setup
}
teardown() {
destroy_app
global_teardown
}
@test "(logs) logs:help" {
run /bin/bash -c "dokku logs:help"
echo "output: $output"
echo "status: $status"
assert_output_contains "Manage log integration for an app"
}
@test "(logs) logs:report" {
run /bin/bash -c "dokku logs:report"
echo "output: $output"
echo "status: $status"
assert_output_contains "You haven't deployed any applications yet"
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:report 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$TEST_APP logs information"
}
@test "(logs) logs:report app" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$TEST_APP logs information"
run /bin/bash -c "dokku logs:report $TEST_APP --invalid-flag 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "$TEST_APP logs information" 0
assert_output_contains "Invalid flag passed, valid flags: --logs-app-label-alias, --logs-computed-app-label-alias, --logs-computed-max-size, --logs-global-app-label-alias, --logs-global-max-size, --logs-global-vector-sink, --logs-max-size, --logs-vector-global-image, --logs-vector-sink"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$TEST_APP logs information" 0
assert_output_contains "Invalid flag passed" 0
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "$TEST_APP logs information" 0
assert_output_contains "Invalid flag passed" 0
}
@test "(logs) logs:set [error]" {
run /bin/bash -c "dokku logs:set 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Please specify an app to run the command on"
run /bin/bash -c "dokku logs:set ${TEST_APP}-non-existent" 2>&1
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "App $TEST_APP-non-existent does not exist"
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP" 2>&1
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "No property specified"
run /bin/bash -c "dokku logs:set $TEST_APP invalid" 2>&1
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid property specified, valid properties include: app-label-alias, max-size, vector-image, vector-sink"
run /bin/bash -c "dokku logs:set $TEST_APP invalid value" 2>&1
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid property specified, valid properties include: app-label-alias, max-size, vector-image, vector-sink"
}
@test "(logs) logs:set app" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink console://?encoding[codec]=json" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "console://?encoding[codec]=json"
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink datadog_logs://?api_key=abc123" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "datadog_logs://?api_key=abc123"
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP max-size" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "20m"
run /bin/bash -c "dokku logs:set $TEST_APP max-size unlimited" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "unlimited"
run /bin/bash -c "dokku logs:set "$TEST_APP" max-size" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
}
@test "(logs) logs:set equals in uri" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink 'loki://?endpoint=https://host&encoding[codec]=text&auth[token]=foobar%3D&auth[strategy]=bearer'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
# type: loki
# endpoint: https://host
# encoding[codec]: text
# auth[token]: foobar=
# auth[strategy]: bearer
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].auth.strategy' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "bearer"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].auth.token' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "foobar="
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].endpoint' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "https://host"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].encoding.codec' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "text"
}
@test "(logs) logs:set escaped uri" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink http://?uri=https%3A//loggerservice.com%3A1234/%3Ftoken%3Dabc1234%26type%3Dvector%26key%3Dvalue%2Bvalue2"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "http://?uri=https%3A//loggerservice.com%3A1234/%3Ftoken%3Dabc1234%26type%3Dvector%26key%3Dvalue%2Bvalue2"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].uri' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "https://loggerservice.com:1234/?token=abc1234&type=vector&key=value+value2"
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink 'aws_cloudwatch_logs://?create_missing_group=true&create_missing_stream=true&group_name=groupname&encoding[codec]=json&region=sa-east-1&stream_name={{ host }}&auth[access_key_id]=KSDSIDJSAJD&auth[secret_access_key]=2932JSDJ%252BKSDSDJ'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "aws_cloudwatch_logs://?create_missing_group=true&create_missing_stream=true&group_name=groupname&encoding[codec]=json&region=sa-east-1&stream_name={{ host }}&auth[access_key_id]=KSDSIDJSAJD&auth[secret_access_key]=2932JSDJ%252BKSDSDJ"
run /bin/bash -c "jq -r '.sinks[\"docker-sink:$TEST_APP\"].auth.secret_access_key' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "2932JSDJ+KSDSDJ"
}
@test "(logs) logs:set global" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set --global vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set --global vector-sink console://?encoding[codec]=json" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "console://?encoding[codec]=json"
run /bin/bash -c "dokku logs:set --global vector-sink datadog_logs://?api_key=abc123" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "datadog_logs://?api_key=abc123"
run /bin/bash -c "dokku logs:set --global vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:set --global vector-sink" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting vector-sink"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-vector-sink 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10m"
run /bin/bash -c "dokku logs:set --global max-size" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10m"
run /bin/bash -c "dokku logs:set --global max-size 20m" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "20m"
run /bin/bash -c "dokku logs:set --global max-size unlimited" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "unlimited"
run /bin/bash -c "dokku logs:set --global max-size" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting max-size"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-global-max-size 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "10m"
}
@test "(logs) logs:set app-label-alias" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP vector-sink console://?encoding[codec]=json" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting vector-sink"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:set --global app-label-alias" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Unsetting app-label-alias"
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "jq -r '.sources[\"docker-source:$TEST_APP\"].include_labels[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "com.dokku.app-name=$TEST_APP"
run /bin/bash -c "dokku logs:set --global app-label-alias global-alt-name" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-computed-app-label-alias" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global-alt-name"
run /bin/bash -c "cat /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "jq -r '.sources[\"docker-source:$TEST_APP\"].include_labels[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "global-alt-name=$TEST_APP"
run /bin/bash -c "dokku logs:set --global app-label-alias alt-name" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Writing updated vector config to /var/lib/dokku/data/logs/vector.json"
run /bin/bash -c "dokku logs:report $TEST_APP --logs-computed-app-label-alias" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "alt-name"
run /bin/bash -c "jq -r '.sources[\"docker-source:$TEST_APP\"].include_labels[0]' /var/lib/dokku/data/logs/vector.json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "alt-name=$TEST_APP"
}
@test "(logs) logs:set max-size with alternate log-driver daemon" {
if [[ "$REMOTE_CONTAINERS" == "true" ]]; then
skip "skipping due non-existent docker service in remote dev container"
fi
if [[ ! -f /etc/docker/daemon.json ]]; then
echo "{}" >/etc/docker/daemon.json
fi
driver="$(jq -r '."log-driver"' /etc/docker/daemon.json)"
local TMP_FILE=$(mktemp "/tmp/${DOKKU_DOMAIN}.XXXX")
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "echo '' | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m"
DRIVER="journald" jq '."log-driver" = env.DRIVER' <"/etc/docker/daemon.json" >"$TMP_FILE"
mv "$TMP_FILE" /etc/docker/daemon.json
sudo service docker restart
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "echo '' | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
if [[ "$driver" = "null" ]]; then
DRIVER="$driver" jq 'del(."log-driver")' <"/etc/docker/daemon.json" >"$TMP_FILE"
else
DRIVER="$driver" jq '."log-driver" = env.DRIVER' <"/etc/docker/daemon.json" >"$TMP_FILE"
fi
mv "$TMP_FILE" /etc/docker/daemon.json
sudo service docker restart
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "echo '' | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m"
}
@test "(logs) logs:set max-size with alternate log-driver" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:set $TEST_APP max-size 20m" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Setting max-size"
run /bin/bash -c "echo "" | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --log-driver=local" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo "" | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --log-driver=json-file" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo "" | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1 | xargs"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "--log-opt=max-size=20m"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy --log-driver=journald" 2>&1
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "echo "" | dokku plugin:trigger docker-args-process-deploy $TEST_APP 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_exists
}
@test "(logs) logs:vector" {
run /bin/bash -c "dokku logs:vector-logs 2>&1"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Vector container does not exist"
run /bin/bash -c "dokku apps:create example.com"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-start 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container is running"
run /bin/bash -c "sudo docker inspect --format='{{.HostConfig.RestartPolicy.Name}}' vector-vector-1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "unless-stopped"
run /bin/bash -c "dokku logs:vector-logs 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container logs"
run /bin/bash -c "dokku --force apps:destroy example.com"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-logs --num 10 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container logs"
assert_output_contains "vector:" 10
assert_line_count 11
run /bin/bash -c "dokku logs:vector-logs --num 5 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container logs"
assert_output_contains "vector:" 5
assert_line_count 6
run /bin/bash -c "docker stop vector-vector-1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku logs:vector-logs 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Vector container logs"
assert_output_contains "Vector container is not running"
run /bin/bash -c "dokku logs:vector-stop 2>&1"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Stopping and removing vector container"
}

View File

@@ -14,6 +14,7 @@ teardown() {
docker network rm create-network || true
docker network rm deploy-network || true
docker network rm initial-network || true
docker network rm "$TEST_NETWORK" || true
global_teardown
}
@@ -31,6 +32,299 @@ teardown() {
assert_output "$help_output"
}
@test "(network:report) --global --format json" {
run /bin/bash -c "dokku network:set --global tld dokku.test"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-global-tld\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku.test"
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"global-tld\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku.test"
run /bin/bash -c "dokku network:report --global --format json | jq -r 'has(\"network-tld\")'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku network:report --global --format json | jq -r 'has(\"tld\")'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku network:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "--global"
run /bin/bash -c "dokku network:set --global tld"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(network:report) emits new stripped JSON keys alongside legacy" {
run /bin/bash -c "dokku network:report --global --format json | jq -r 'has(\"global-tld\") and has(\"network-global-tld\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku network:report --global --format json | jq -r 'has(\"computed-tld\") and has(\"network-computed-tld\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r 'has(\"tld\") and has(\"network-tld\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r 'has(\"web-listeners\") and has(\"network-web-listeners\")'"
assert_success
assert_output "true"
}
@test "(network:report) tld raw vs computed" {
run /bin/bash -c "dokku network:set --global tld"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-global-tld\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku network:set --global tld example.test"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-global-tld\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "example.test"
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-global-tld\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "example.test"
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-computed-tld\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "example.test"
run /bin/bash -c "dokku network:set --global tld"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(network:report) attach-post-create raw vs computed vs global" {
docker network create create-network-x >/dev/null
run /bin/bash -c "dokku network:set --global attach-post-create"
assert_success
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-attach-post-create\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-global-attach-post-create\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-computed-attach-post-create\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku network:set --global attach-post-create create-network-x"
assert_success
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-global-attach-post-create\"'"
assert_success
assert_output "create-network-x"
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-computed-attach-post-create\"'"
assert_success
assert_output "create-network-x"
run /bin/bash -c "dokku network:set --global attach-post-create"
assert_success
docker network rm create-network-x >/dev/null
}
@test "(network:report) attach-post-deploy raw vs computed vs global" {
docker network create deploy-network-x >/dev/null
run /bin/bash -c "dokku network:set --global attach-post-deploy"
assert_success
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-attach-post-deploy\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-global-attach-post-deploy\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku network:set --global attach-post-deploy deploy-network-x"
assert_success
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-global-attach-post-deploy\"'"
assert_success
assert_output "deploy-network-x"
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-computed-attach-post-deploy\"'"
assert_success
assert_output "deploy-network-x"
run /bin/bash -c "dokku network:set --global attach-post-deploy"
assert_success
docker network rm deploy-network-x >/dev/null
}
@test "(network:report) initial-network raw vs computed vs global" {
docker network create initial-network-x >/dev/null
run /bin/bash -c "dokku network:set --global initial-network"
assert_success
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-initial-network\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-global-initial-network\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku network:set --global initial-network initial-network-x"
assert_success
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-global-initial-network\"'"
assert_success
assert_output "initial-network-x"
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-computed-initial-network\"'"
assert_success
assert_output "initial-network-x"
run /bin/bash -c "dokku network:set --global initial-network"
assert_success
docker network rm initial-network-x >/dev/null
}
@test "(network:report) bind-all-interfaces raw vs computed vs global" {
run /bin/bash -c "dokku network:set --global bind-all-interfaces"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-global-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-computed-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku network:set --global bind-all-interfaces true"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-global-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-computed-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-computed-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku network:set --global bind-all-interfaces"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-global-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku network:report --global --format json | jq -r '.\"network-computed-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku network:set $TEST_APP bind-all-interfaces true"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku network:set $TEST_APP bind-all-interfaces"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku network:report $TEST_APP --format json | jq -r '.\"network-computed-bind-all-interfaces\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
}
@test "(network) network:set bind-all-interfaces" {
run deploy_app
echo "output: $output"
@@ -148,6 +442,63 @@ teardown() {
assert_failure
}
@test "(network:list) --format json exposes DokkuManaged" {
run /bin/bash -c "dokku network:create $TEST_NETWORK"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:list --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:list --format json | jq -r '.[] | select(.Name == \"bridge\") | .DokkuManaged'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku network:list --format json | jq -r '.[] | select(.Name == \"$TEST_NETWORK\") | .DokkuManaged'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku --force network:destroy $TEST_NETWORK"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(network:list) --dokku-managed filters to dokku-created networks" {
run /bin/bash -c "dokku network:create $TEST_NETWORK"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:list --dokku-managed | grep -w bridge"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku network:list --dokku-managed | grep $TEST_NETWORK"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku network:list --dokku-managed --format json | jq -r '.[].DokkuManaged' | sort -u"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku --force network:destroy $TEST_NETWORK"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(network) network:set attach" {
run deploy_app
echo "output: $output"
@@ -327,7 +678,7 @@ teardown() {
}
@test "(network) handle single-udp app" {
run /bin/bash -c "dokku docker-options:add $TEST_APP -p 1194:1194"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy -p 1194:1194"
echo "output: $output"
echo "status: $status"
assert_success

View File

@@ -28,6 +28,104 @@ teardown() {
assert_output "$help_output"
}
@test "(nginx:report) info-flag works before deploy" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:report $TEST_APP --nginx-bind-address-ipv4"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:set $TEST_APP bind-address-ipv4 127.0.0.1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:report $TEST_APP --nginx-bind-address-ipv4"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "127.0.0.1"
run /bin/bash -c "dokku nginx:report $TEST_APP --nginx-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(nginx:report) --format json" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:set $TEST_APP bind-address-ipv4 127.0.0.1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:report $TEST_APP --format json | jq -r '.\"bind-address-ipv4\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "127.0.0.1"
run /bin/bash -c "dokku nginx:report $TEST_APP --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:report --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:report $TEST_APP --format json --nginx-bind-address-ipv4"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "--format flag cannot be specified when specifying an info flag"
}
@test "(nginx:report) --global --format json" {
run /bin/bash -c "dokku nginx:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:report --global --format json | jq -r 'keys[]' | grep -v 'global-' | wc -l"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "0"
run /bin/bash -c "dokku nginx:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global nginx information"
run /bin/bash -c "dokku nginx:set --global client-max-body-size 5m"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:report --global --nginx-global-client-max-body-size"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "5m"
run /bin/bash -c "dokku nginx:set --global client-max-body-size"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(nginx-vhosts) proxy:build-config (domains:disable/enable)" {
run deploy_app
echo "output: $output"

View File

@@ -0,0 +1,99 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
[[ -f "$DOKKU_ROOT/VHOST" ]] && cp -fp "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak"
}
teardown() {
destroy_app
[[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" && chown dokku:dokku "$DOKKU_ROOT/VHOST"
global_teardown
}
@test "(nginx-vhosts) proxy:build-config generates 502 config for undeployed app" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $DOKKU_ROOT/$TEST_APP/nginx.conf"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "return 502" -1
}
@test "(nginx-vhosts) proxy:build-config undeployed app returns 502" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
sleep 2
assert_http_localhost_response "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/" "" "502"
}
@test "(nginx-vhosts) proxy:build-config 502 config replaced after deploy" {
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "return 502" 0
assert_output_contains "proxy_pass" -1
assert_http_success "http://${TEST_APP}.${DOKKU_DOMAIN}"
}
@test "(nginx-vhosts) proxy:build-config domains:add updates 502 config" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku domains:add $TEST_APP custom.${DOKKU_DOMAIN}"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "custom.${DOKKU_DOMAIN}" -1
assert_output_contains "return 502" -1
}
@test "(nginx-vhosts) proxy:build-config no nginx.conf when proxy disabled" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $DOKKU_ROOT/$TEST_APP/nginx.conf"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku proxy:disable $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $DOKKU_ROOT/$TEST_APP/nginx.conf"
echo "output: $output"
echo "status: $status"
assert_failure
}

View File

@@ -0,0 +1,151 @@
#!/usr/bin/env bats
# Tests for the nginx:reload command and the catch-all default site shipped
# at /etc/nginx/conf.d/00-default-vhost.conf. Postinst-driven behavior
# (debconf flag, fresh-install detection, sites-enabled/default rename) is
# not exercised here because the bats harness does not reinstall the apt
# package; the rename logic is exercised manually by simulating the
# conflicting upstream vhost.
load test_helper
NGINX_DEFAULT_VHOST_PATH="/etc/nginx/conf.d/00-default-vhost.conf"
NGINX_DEFAULT_VHOST_SOURCE_MODERN="/var/lib/dokku/core-plugins/available/nginx-vhosts/templates/default-site.conf"
NGINX_DEFAULT_VHOST_SOURCE_LEGACY="/var/lib/dokku/core-plugins/available/nginx-vhosts/templates/default-site-legacy.conf"
fn-nginx-supports-ssl-reject-handshake() {
local nginx_version major minor patch
nginx_version="$(nginx -v 2>&1 | cut -d'/' -f 2 | awk '{print $1}')"
major="$(echo "$nginx_version" | awk -F. '{print $1}')"
minor="$(echo "$nginx_version" | awk -F. '{print $2}')"
patch="$(echo "$nginx_version" | awk -F. '{print $3}')"
if [ "${major:-0}" -ge 2 ]; then
return 0
fi
if [ "${major:-0}" -eq 1 ] && [ "${minor:-0}" -gt 19 ]; then
return 0
fi
if [ "${major:-0}" -eq 1 ] && [ "${minor:-0}" -eq 19 ] && [ "${patch:-0}" -ge 4 ]; then
return 0
fi
return 1
}
fn-default-site-source() {
if fn-nginx-supports-ssl-reject-handshake; then
echo "$NGINX_DEFAULT_VHOST_SOURCE_MODERN"
else
echo "$NGINX_DEFAULT_VHOST_SOURCE_LEGACY"
fi
}
setup() {
global_setup
[[ -f "$DOKKU_ROOT/VHOST" ]] && cp -fp "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak"
[[ -f "$NGINX_DEFAULT_VHOST_PATH" ]] && cp -fp "$NGINX_DEFAULT_VHOST_PATH" "${NGINX_DEFAULT_VHOST_PATH}.bats-bak"
rm -f "$NGINX_DEFAULT_VHOST_PATH"
}
teardown() {
rm -f "$NGINX_DEFAULT_VHOST_PATH"
if [[ -f "${NGINX_DEFAULT_VHOST_PATH}.bats-bak" ]]; then
mv "${NGINX_DEFAULT_VHOST_PATH}.bats-bak" "$NGINX_DEFAULT_VHOST_PATH"
fi
rm -f /etc/nginx/sites-enabled/default.bats-stub
[[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" && chown dokku:dokku "$DOKKU_ROOT/VHOST"
if sudo nginx -t &>/dev/null; then
sudo systemctl reload nginx || true
fi
global_teardown
}
@test "(nginx-vhosts:reload) reloads with valid config" {
run /bin/bash -c "dokku nginx:reload"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(nginx-vhosts:reload) fails with invalid config without restarting" {
local invalid_conf="/etc/nginx/conf.d/dokku-bats-invalid.conf"
echo "this is not valid nginx config" | sudo tee "$invalid_conf" >/dev/null
run /bin/bash -c "dokku nginx:reload"
echo "output: $output"
echo "status: $status"
assert_failure
sudo rm -f "$invalid_conf"
}
@test "(nginx-vhosts) [default-site] modern template installs and validates on nginx >= 1.19.4" {
fn-nginx-supports-ssl-reject-handshake || skip "nginx < 1.19.4 does not support ssl_reject_handshake"
[[ -f "$NGINX_DEFAULT_VHOST_SOURCE_MODERN" ]] || skip "default-site template not installed; run 'sudo make copyfiles'"
sudo install -m 0644 -o root -g root "$NGINX_DEFAULT_VHOST_SOURCE_MODERN" "$NGINX_DEFAULT_VHOST_PATH"
run /bin/bash -c "sudo grep -F 'ssl_reject_handshake on' '$NGINX_DEFAULT_VHOST_PATH'"
assert_success
run /bin/bash -c "sudo grep -F 'return 444' '$NGINX_DEFAULT_VHOST_PATH'"
assert_success
run /bin/bash -c "sudo grep -F 'default_server' '$NGINX_DEFAULT_VHOST_PATH'"
assert_success
run /bin/bash -c "sudo nginx -t"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(nginx-vhosts) [default-site] legacy template installs and validates on nginx < 1.19.4" {
if fn-nginx-supports-ssl-reject-handshake; then
skip "nginx >= 1.19.4 uses the modern default-site template"
fi
[[ -f "$NGINX_DEFAULT_VHOST_SOURCE_LEGACY" ]] || skip "default-site-legacy template not installed; run 'sudo make copyfiles'"
sudo install -m 0644 -o root -g root "$NGINX_DEFAULT_VHOST_SOURCE_LEGACY" "$NGINX_DEFAULT_VHOST_PATH"
run /bin/bash -c "sudo grep -F 'return 444' '$NGINX_DEFAULT_VHOST_PATH'"
assert_success
run /bin/bash -c "sudo grep -F 'default_server' '$NGINX_DEFAULT_VHOST_PATH'"
assert_success
run /bin/bash -c "sudo grep -F 'ssl_reject_handshake' '$NGINX_DEFAULT_VHOST_PATH'"
assert_failure
run /bin/bash -c "sudo grep -E 'listen[[:space:]]+(\\[::\\]:)?443' '$NGINX_DEFAULT_VHOST_PATH'"
assert_failure
run /bin/bash -c "sudo nginx -t"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(nginx-vhosts) [default-site] coexists with stock sites-enabled/default" {
local default_vhost_source
default_vhost_source="$(fn-default-site-source)"
[[ -f "$default_vhost_source" ]] || skip "default-site template not installed; run 'sudo make copyfiles'"
sudo mkdir -p /etc/nginx/sites-enabled
sudo tee /etc/nginx/sites-enabled/default.bats-stub >/dev/null <<'STOCK'
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 200 "stock default";
}
STOCK
sudo install -m 0644 -o root -g root "$default_vhost_source" "$NGINX_DEFAULT_VHOST_PATH"
run /bin/bash -c "sudo nginx -t"
echo "output: $output"
echo "status: $status"
assert_failure
sudo rm -f /etc/nginx/sites-enabled/default.bats-stub
run /bin/bash -c "sudo nginx -t"
echo "output: $output"
echo "status: $status"
assert_success
}

View File

@@ -0,0 +1,172 @@
#!/usr/bin/env bats
load test_helper
NGINX_VALIDATE_PLUGIN_NAME="test-nginx-validate"
NGINX_VALIDATE_ZONE_CONF="/etc/nginx/conf.d/00-dokku-test-limit-req.conf"
setup() {
global_setup
[[ -f "$DOKKU_ROOT/VHOST" ]] && cp -fp "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak"
create_app
}
teardown() {
rm -rf "${PLUGIN_ENABLED_PATH:?}/$NGINX_VALIDATE_PLUGIN_NAME" "${PLUGIN_AVAILABLE_PATH:?}/$NGINX_VALIDATE_PLUGIN_NAME"
destroy_app
rm -f "$NGINX_VALIDATE_ZONE_CONF"
[[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" && chown dokku:dokku "$DOKKU_ROOT/VHOST"
global_teardown
}
@test "(nginx-vhosts) pre-validate fails fast on broken nginx.conf.sigil" {
run deploy_app nodejs-express dokku@$DOKKU_DOMAIN:$TEST_APP bad_custom_nginx_template
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Pre-validating custom nginx.conf.sigil"
assert_output_contains "Custom nginx.conf.sigil failed nginx -t validation"
assert_output_not_contains "Building $TEST_APP"
assert_output_not_contains "Releasing $TEST_APP"
}
@test "(nginx-vhosts) pre-validate succeeds on first deploy with valid nginx.conf.sigil" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP custom_nginx_template
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Pre-validating custom nginx.conf.sigil"
}
@test "(nginx-vhosts) pre-validate is skipped when disable-custom-config=true" {
run /bin/bash -c "dokku nginx:set $TEST_APP disable-custom-config true"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app nodejs-express dokku@$DOKKU_DOMAIN:$TEST_APP bad_custom_nginx_template
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "Pre-validating custom nginx.conf.sigil"
}
@test "(nginx-vhosts) pre-validate is skipped when proxy is not nginx" {
run /bin/bash -c "dokku proxy:set $TEST_APP caddy"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app nodejs-express dokku@$DOKKU_DOMAIN:$TEST_APP bad_custom_nginx_template
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "Pre-validating custom nginx.conf.sigil"
}
@test "(nginx-vhosts) pre-validate fails when nginx.conf.sigil needs a directive absent from the wrapper" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP custom_nginx_template_with_limit_req
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Pre-validating custom nginx.conf.sigil"
assert_output_contains "Custom nginx.conf.sigil failed nginx -t validation"
}
@test "(nginx-vhosts) pre-validate passes when nginx-app-template-source overrides validate-config" {
echo 'limit_req_zone $binary_remote_addr zone=dokkuprevalidate:10m rate=100r/s;' >"$NGINX_VALIDATE_ZONE_CONF"
setup_nginx_validate_plugin
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP custom_nginx_template_with_limit_req
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Pre-validating custom nginx.conf.sigil"
}
setup_nginx_validate_plugin() {
declare desc="installs a plugin that overrides the validate-config nginx template"
local PLUGIN_DIR="$PLUGIN_AVAILABLE_PATH/$NGINX_VALIDATE_PLUGIN_NAME"
mkdir -p "$PLUGIN_DIR"
cat <<EOF >"$PLUGIN_DIR/plugin.toml"
[plugin]
description = "test plugin overriding the validate-config nginx template"
version = "0.1.0"
[plugin.config]
EOF
cat <<'EOF' >"$PLUGIN_DIR/nginx-app-template-source"
#!/usr/bin/env bash
set -eo pipefail
[[ $DOKKU_TRACE ]] && set -x
TEMPLATE_TYPE="$2"
if [[ "$TEMPLATE_TYPE" == "validate-config" ]]; then
echo "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/validate.conf.sigil"
fi
EOF
chmod +x "$PLUGIN_DIR/nginx-app-template-source"
cat <<'EOF' >"$PLUGIN_DIR/validate.conf.sigil"
events { worker_connections 768; }
http {
access_log off;
error_log /dev/null;
limit_req_zone $binary_remote_addr zone=dokkuprevalidate:10m rate=100r/s;
include {{ $.NGINX_CONF }};
}
EOF
dokku plugin:enable "$NGINX_VALIDATE_PLUGIN_NAME"
}
custom_nginx_template_with_limit_req() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
mkdir -p "$APP_REPO_DIR"
echo "injecting custom_nginx_template_with_limit_req -> $APP_REPO_DIR/nginx.conf.sigil"
cat <<EOF >"$APP_REPO_DIR/nginx.conf.sigil"
{{ range \$port_map := .PROXY_PORT_MAP | split " " }}
{{ \$port_map_list := \$port_map | split ":" }}
{{ \$scheme := index \$port_map_list 0 }}
{{ \$listen_port := index \$port_map_list 1 }}
{{ \$upstream_port := index \$port_map_list 2 }}
server {
listen [::]:{{ \$listen_port }};
listen {{ \$listen_port }};
server_name {{ $.NOSSL_SERVER_NAME }} customtemplate.${DOKKU_DOMAIN};
location / {
limit_req zone=dokkuprevalidate burst=100 nodelay;
proxy_pass http://{{ $.APP }}-{{ \$upstream_port }};
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$http_host;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Forwarded-For \$remote_addr;
proxy_set_header X-Forwarded-Port \$server_port;
proxy_set_header X-Request-Start \$msec;
}
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
}
{{ end }}
{{ if $.DOKKU_APP_WEB_LISTENERS }}
{{ range \$upstream_port := $.PROXY_UPSTREAM_PORTS | split " " }}
upstream {{ $.APP }}-{{ \$upstream_port }} {
{{ range \$listeners := $.DOKKU_APP_WEB_LISTENERS | split " " }}
{{ \$listener_list := \$listeners | split ":" }}
{{ \$listener_ip := index \$listener_list 0 }}
server {{ \$listener_ip }}:{{ \$upstream_port }};{{ end }}
}
{{ end }}{{ end }}
EOF
cat "$APP_REPO_DIR/nginx.conf.sigil"
}

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bats
load test_helper
setup_local_tls() {
TLS=$BATS_TMPDIR/tls
mkdir -p $TLS
tar xf $BATS_TEST_DIRNAME/server_ssl.tar -C $TLS
tar xf $BATS_TEST_DIRNAME/domain_ssl.tar -C $TLS
sudo chown -R dokku:dokku $TLS
}
teardown_local_tls() {
TLS=$BATS_TMPDIR/tls
rm -R $TLS
}
setup() {
global_setup
[[ -f "$DOKKU_ROOT/VHOST" ]] && cp -fp "$DOKKU_ROOT/VHOST" "$DOKKU_ROOT/VHOST.bak"
create_app
}
teardown() {
destroy_app
[[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" && chown dokku:dokku "$DOKKU_ROOT/VHOST"
global_teardown
}
@test "(nginx-vhosts) refactored template generates nginx -t parseable http config" {
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "test -f $DOKKU_ROOT/$TEST_APP/nginx.conf"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "sudo nginx -t"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(nginx-vhosts) refactored template generates nginx -t parseable https config" {
setup_local_tls
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku certs:add $TEST_APP $BATS_TMPDIR/tls/server.crt $BATS_TMPDIR/tls/server.key"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "sudo nginx -t"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku nginx:show-config $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "ssl_certificate" -1
assert_output_contains "return 301 https" -1
teardown_local_tls
}

View File

@@ -60,9 +60,9 @@ teardown() {
assert_success
}
@test "(nginx-vhosts) proxy:build-config (global DOKKU_PROXY_PORT)" {
@test "(nginx-vhosts) proxy:build-config (global proxy-port)" {
local GLOBAL_PORT=30999
run /bin/bash -c "dokku config:set --global DOKKU_PROXY_PORT=${GLOBAL_PORT}"
run /bin/bash -c "dokku proxy:set --global proxy-port ${GLOBAL_PORT}"
echo "output: $output"
echo "status: $status"
assert_success
@@ -74,7 +74,7 @@ teardown() {
check_urls "http://${TEST_APP}.${DOKKU_DOMAIN}:${GLOBAL_PORT}"
assert_http_success "http://${TEST_APP}.${DOKKU_DOMAIN}:${GLOBAL_PORT}"
run /bin/bash -c "dokku config:unset --global DOKKU_PROXY_PORT"
run /bin/bash -c "dokku proxy:set --global proxy-port"
echo "output: $output"
echo "status: $status"
assert_success

View File

@@ -96,4 +96,67 @@ teardown() {
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Pre-validating custom nginx.conf.sigil"
assert_output_contains "Custom nginx.conf.sigil failed nginx -t validation"
}
@test "(nginx-vhosts) proxy:build-config (custom nginx template with deprecated listen http2)" {
run /bin/bash -c "dokku domains:add $TEST_APP www.test.app.${DOKKU_DOMAIN}"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP custom_nginx_template_with_http2_listen
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "Deprecated: Usage of 'listen ... http2' within nginx.conf.sigil templates is deprecated" -1
}
custom_nginx_template_with_http2_listen() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
mkdir -p "$APP_REPO_DIR"
echo "injecting custom_nginx_template_with_http2_listen -> $APP_REPO_DIR/nginx.conf.sigil"
cat <<EOF >"$APP_REPO_DIR/nginx.conf.sigil"
{{ range \$port_map := .PROXY_PORT_MAP | split " " }}
{{ \$port_map_list := \$port_map | split ":" }}
{{ \$scheme := index \$port_map_list 0 }}
{{ \$listen_port := index \$port_map_list 1 }}
{{ \$upstream_port := index \$port_map_list 2 }}
server {
listen [::]:{{ \$listen_port }} http2;
listen {{ \$listen_port }} http2;
server_name {{ $.NOSSL_SERVER_NAME }} customtemplate.${DOKKU_DOMAIN};
location / {
proxy_pass http://{{ $.APP }}-{{ \$upstream_port }};
proxy_http_version 1.1;
proxy_set_header Upgrade \$http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host \$http_host;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Forwarded-For \$remote_addr;
proxy_set_header X-Forwarded-Port \$server_port;
proxy_set_header X-Request-Start \$msec;
}
include {{ $.DOKKU_ROOT }}/{{ $.APP }}/nginx.conf.d/*.conf;
}
{{ end }}
{{ if $.DOKKU_APP_WEB_LISTENERS }}
{{ range \$upstream_port := $.PROXY_UPSTREAM_PORTS | split " " }}
upstream {{ $.APP }}-{{ \$upstream_port }} {
{{ range \$listeners := $.DOKKU_APP_WEB_LISTENERS | split " " }}
{{ \$listener_list := \$listeners | split ":" }}
{{ \$listener_ip := index \$listener_list 0 }}
server {{ \$listener_ip }}:{{ \$upstream_port }};{{ end }}
}
{{ end }}{{ end }}
EOF
cat "$APP_REPO_DIR/nginx.conf.sigil"
}

View File

@@ -0,0 +1,109 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
create_app
}
teardown() {
destroy_app
global_teardown
}
# assert_nginx_property_set_get verifies that for a given nginx property,
# (a) the raw per-app and global keys cycle through set/unset states,
# (b) the computed key always returns a non-empty value when defaults exist,
# and (c) the computed key falls back through per-app -> global.
#
# This intentionally does not pin the exact default value for properties whose
# default is computed at runtime (e.g. proxy-buffer-size depends on the host's
# page size) - those would be brittle to assert verbatim. The set/unset cycle
# is the canonical test for the report convention.
assert_nginx_property_set_get() {
declare prop="$1" app_value="$2" global_value="$3"
run /bin/bash -c "dokku nginx:set --global $prop"
assert_success
run /bin/bash -c "dokku nginx:set --global $prop '$global_value'"
assert_success
run /bin/bash -c "dokku nginx:report $TEST_APP --format json | jq -r '.\"global-$prop\"'"
assert_success
assert_output "$global_value"
run /bin/bash -c "dokku nginx:report $TEST_APP --format json | jq -r '.\"computed-$prop\"'"
assert_success
assert_output "$global_value"
run /bin/bash -c "dokku nginx:set $TEST_APP $prop '$app_value'"
assert_success
run /bin/bash -c "dokku nginx:report $TEST_APP --format json | jq -r '.\"$prop\"'"
assert_success
assert_output "$app_value"
run /bin/bash -c "dokku nginx:report $TEST_APP --format json | jq -r '.\"global-$prop\"'"
assert_success
assert_output "$global_value"
run /bin/bash -c "dokku nginx:report $TEST_APP --format json | jq -r '.\"computed-$prop\"'"
assert_success
assert_output "$app_value"
run /bin/bash -c "dokku nginx:set $TEST_APP $prop"
assert_success
run /bin/bash -c "dokku nginx:set --global $prop"
assert_success
run /bin/bash -c "dokku nginx:report $TEST_APP --format json | jq -r '.\"global-$prop\"'"
assert_success
assert_output ""
}
@test "(nginx:report) timeout properties raw/global/computed" {
for prop in client-body-timeout client-header-timeout keepalive-timeout lingering-timeout send-timeout proxy-connect-timeout proxy-read-timeout proxy-send-timeout; do
assert_nginx_property_set_get "$prop" "30s" "45s"
done
}
@test "(nginx:report) buffer properties raw/global/computed" {
assert_nginx_property_set_get "proxy-buffer-size" "8k" "16k"
assert_nginx_property_set_get "proxy-buffering" "off" "on"
assert_nginx_property_set_get "proxy-buffers" "16 16k" "32 16k"
assert_nginx_property_set_get "proxy-busy-buffers-size" "16k" "32k"
assert_nginx_property_set_get "client-max-body-size" "10m" "20m"
}
@test "(nginx:report) hsts properties raw/global/computed" {
assert_nginx_property_set_get "hsts" "false" "true"
assert_nginx_property_set_get "hsts-include-subdomains" "false" "true"
assert_nginx_property_set_get "hsts-max-age" "3600" "7200"
assert_nginx_property_set_get "hsts-preload" "true" "false"
}
@test "(nginx:report) x-forwarded properties raw/global/computed" {
assert_nginx_property_set_get "x-forwarded-for-value" "\$remote_addr" "\$proxy_add_x_forwarded_for"
assert_nginx_property_set_get "x-forwarded-port-value" "8080" "8443"
assert_nginx_property_set_get "x-forwarded-proto-value" "https" "http"
assert_nginx_property_set_get "x-forwarded-ssl" "on" "off"
}
@test "(nginx:report) log/address properties raw/global/computed" {
assert_nginx_property_set_get "bind-address-ipv4" "127.0.0.1" "0.0.0.0"
assert_nginx_property_set_get "bind-address-ipv6" "::1" "::"
assert_nginx_property_set_get "access-log-format" "main" "combined"
assert_nginx_property_set_get "access-log-path" "/var/log/nginx/app-access.log" "/dev/stdout"
assert_nginx_property_set_get "error-log-path" "/var/log/nginx/app-error.log" "/dev/stderr"
}
@test "(nginx:report) misc properties raw/global/computed" {
assert_nginx_property_set_get "disable-custom-config" "false" "true"
assert_nginx_property_set_get "underscore-in-headers" "on" "off"
assert_nginx_property_set_get "proxy-keepalive" "8" "16"
assert_nginx_property_set_get "nginx-conf-sigil-path" "custom.sigil" "global.sigil"
assert_nginx_property_set_get "nginx-service-command" "/usr/sbin/nginx-app" "/usr/sbin/nginx-global"
}

View File

@@ -0,0 +1,84 @@
#!/usr/bin/env bats
load test_helper
setup() {
create_app
}
teardown() {
destroy_app
dokku openresty:set --global log-level >/dev/null 2>&1 || true
dokku openresty:set --global proxy-buffer-size >/dev/null 2>&1 || true
dokku openresty:set --global client-max-body-size >/dev/null 2>&1 || true
}
@test "(openresty:report) info-flag works before deploy" {
run /bin/bash -c "dokku openresty:set --global log-level"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "ERROR"
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
}
@test "(openresty:report) --format json" {
run /bin/bash -c "dokku openresty:set --global proxy-buffer-size"
assert_success
run /bin/bash -c "dokku openresty:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"computed-proxy-buffer-size\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "4k"
run /bin/bash -c "dokku openresty:report --global"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "global openresty information"
}
@test "(openresty:report) client-max-body-size raw global computed" {
run /bin/bash -c "dokku openresty:set --global client-max-body-size"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-client-max-body-size"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-client-max-body-size"
assert_success
assert_output "1m"
run /bin/bash -c "dokku openresty:set --global client-max-body-size 2m"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-client-max-body-size"
assert_success
assert_output "2m"
run /bin/bash -c "dokku openresty:set $TEST_APP client-max-body-size 5m"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-client-max-body-size"
assert_success
assert_output "5m"
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-client-max-body-size"
assert_success
assert_output "5m"
}

View File

@@ -12,12 +12,440 @@ setup() {
}
teardown() {
dokku openresty:set --global log-level >/dev/null 2>&1 || true
for key in bind-address-ipv6 keepalive-timeout client-body-timeout client-header-timeout client-max-body-size; do
dokku openresty:set --global "$key" >/dev/null || true
done
global_teardown
destroy_app
dokku openresty:stop
dokku nginx:start
}
@test "(openresty:report) --global --openresty-computed-letsencrypt-server" {
run /bin/bash -c "dokku openresty:report --global --openresty-computed-letsencrypt-server"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "https://acme-staging-v02.api.letsencrypt.org/directory"
run /bin/bash -c "dokku openresty:report --global --openresty-global-letsencrypt-server"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "https://acme-staging-v02.api.letsencrypt.org/directory"
}
@test "(openresty:report) --global raw and computed keys in --format json" {
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"global-letsencrypt-server\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "https://acme-staging-v02.api.letsencrypt.org/directory"
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"computed-letsencrypt-server\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "https://acme-staging-v02.api.letsencrypt.org/directory"
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"global-letsencrypt-email\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"computed-letsencrypt-email\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"global-image\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"computed-image\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"global-allowed-letsencrypt-domains-func-base64\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"computed-allowed-letsencrypt-domains-func-base64\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"global-hsts\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"computed-hsts\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
for key in image letsencrypt-email letsencrypt-server allowed-letsencrypt-domains-func-base64; do
run /bin/bash -c "dokku openresty:report --global --format json | jq -e \"has(\\\"$key\\\")\""
echo "key: $key"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output "false"
done
}
@test "(openresty:report) --global global vs computed image" {
run /bin/bash -c "dokku openresty:report --global --openresty-global-image"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report --global --openresty-computed-image"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
run /bin/bash -c "dokku openresty:set --global image dokku/openresty-docker-proxy:0.5.6"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report --global --openresty-global-image"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku/openresty-docker-proxy:0.5.6"
run /bin/bash -c "dokku openresty:report --global --openresty-computed-image"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku/openresty-docker-proxy:0.5.6"
run /bin/bash -c "dokku openresty:set --global image"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report --global --openresty-global-image"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report --global --openresty-computed-image"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
}
@test "(openresty:report) --global log-level raw vs computed" {
run /bin/bash -c "dokku openresty:report --global --openresty-global-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report --global --openresty-computed-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "ERROR"
run /bin/bash -c "dokku openresty:set --global log-level DEBUG"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report --global --openresty-global-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "DEBUG"
run /bin/bash -c "dokku openresty:report --global --openresty-computed-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "DEBUG"
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"global-log-level\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "DEBUG"
run /bin/bash -c "dokku openresty:report --global --format json | jq -r '.\"computed-log-level\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "DEBUG"
run /bin/bash -c "dokku openresty:set --global log-level"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report --global --openresty-global-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report --global --openresty-computed-log-level"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "ERROR"
}
@test "(openresty:report) per-app raw vs global vs computed for bind-address-ipv6" {
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-bind-address-ipv6"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-global-bind-address-ipv6"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-bind-address-ipv6"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "::"
run /bin/bash -c "dokku openresty:set $TEST_APP bind-address-ipv6 ::1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-bind-address-ipv6"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "::1"
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-bind-address-ipv6"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "::1"
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-global-bind-address-ipv6"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:set $TEST_APP bind-address-ipv6"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-bind-address-ipv6"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "::"
}
@test "(openresty:report) per-app inherits global value, per-app overrides global" {
run /bin/bash -c "dokku openresty:set --global keepalive-timeout 90s"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-global-keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "90s"
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "90s"
run /bin/bash -c "dokku openresty:set $TEST_APP keepalive-timeout 30s"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "30s"
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "30s"
run /bin/bash -c "dokku openresty:report $TEST_APP --format json | jq -r '.\"keepalive-timeout\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "30s"
run /bin/bash -c "dokku openresty:report $TEST_APP --format json | jq -r '.\"global-keepalive-timeout\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "90s"
run /bin/bash -c "dokku openresty:report $TEST_APP --format json | jq -r '.\"computed-keepalive-timeout\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "30s"
run /bin/bash -c "dokku openresty:set $TEST_APP keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:set --global keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "75s"
}
@test "(openresty:report) client-header-timeout reads its own property key" {
run /bin/bash -c "dokku openresty:set $TEST_APP client-body-timeout 99s"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-client-header-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "60s"
run /bin/bash -c "dokku openresty:set $TEST_APP client-header-timeout 30s"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-client-header-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "30s"
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-client-header-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "30s"
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-client-body-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "99s"
}
@test "(openresty:report) client-max-body-size computed default is 1m" {
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-client-max-body-size"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-computed-client-max-body-size"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "1m"
}
@test "(openresty) per-app properties are settable globally" {
run /bin/bash -c "dokku openresty:set --global keepalive-timeout 90s"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report --global --openresty-global-keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "90s"
run /bin/bash -c "dokku openresty:report --global --openresty-computed-keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "90s"
run /bin/bash -c "dokku openresty:set --global keepalive-timeout"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(openresty) global-only keys" {
for key in allowed-letsencrypt-domains-func-base64 image log-level letsencrypt-email letsencrypt-server; do
run /bin/bash -c "dokku openresty:set $TEST_APP $key somevalue"
echo "key: $key"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "can only be set globally"
done
run /bin/bash -c "dokku openresty:set $TEST_APP bind-address-ipv4 127.0.0.1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku openresty:report $TEST_APP --openresty-bind-address-ipv4"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "127.0.0.1"
run /bin/bash -c "dokku openresty:set $TEST_APP bind-address-ipv4"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(openresty) openresty:help" {
run /bin/bash -c "dokku openresty"
echo "output: $output"
@@ -245,6 +673,24 @@ teardown() {
assert_output_contains "charset UTF-8;"
}
@test "(openresty) [security] eval injection via malicious include filename" {
rm -f /tmp/openresty-include
run /bin/bash -c "dokku proxy:set $TEST_APP openresty"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP add_openresty_include_unsafe
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "unsafe filename" -1
# No injection payload to test since we're using a simple space character
# The test should have failed during core-post-extract, not during eval
}
@test "(openresty) label management" {
run /bin/bash -c "dokku proxy:set $TEST_APP openresty"
echo "output: $output"
@@ -327,3 +773,16 @@ add_openresty_include() {
touch "$APP_REPO_DIR/openresty/http-location-includes/example.conf"
echo "# location-block" >>"$APP_REPO_DIR/openresty/http-location-includes/example.conf"
}
add_openresty_include_unsafe() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
mkdir -p "$APP_REPO_DIR/openresty/http-includes"
# Create a filename with a space - simpler test that should be rejected by [^a-zA-Z0-9_.-]
printf 'charset UTF-8;\n' >"$APP_REPO_DIR/openresty/http-includes/unsafe filename.conf"
mkdir -p "$APP_REPO_DIR/openresty/http-location-includes"
printf '# location\n' >"$APP_REPO_DIR/openresty/http-location-includes/unsafe filename.conf"
}

View File

@@ -26,6 +26,70 @@ teardown() {
assert_output "$help_output"
}
@test "(plugin) plugin:list --format json" {
run /bin/bash -c "dokku plugin:list --format nonsense"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid output format"
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"apps\") | .core'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"apps\") | .enabled'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"apps\") | .source_url'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
# Clone a git-based third-party plugin directly into the available path so the
# git install source is present without running the (build-dependent) install
# trigger. plugn lists it as a disabled plugin.
run /bin/bash -c "git clone $TEST_PLUGIN_GIT_REPO $PLUGIN_AVAILABLE_PATH/$TEST_PLUGIN_NAME"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .source_url'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "$TEST_PLUGIN_GIT_REPO"
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .core'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .enabled'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "false"
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .committish | length'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "40"
run /bin/bash -c "dokku plugin:list --format json | jq -r '.[] | select(.name == \"$TEST_PLUGIN_NAME\") | .branch'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_exists
}
@test "(plugin) plugin:install, plugin:disable, plugin:update plugin:uninstall" {
run /bin/bash -c "dokku plugin:installed $TEST_PLUGIN_NAME"
echo "output: $output"

View File

@@ -50,6 +50,11 @@ teardown() {
echo "status: $status"
assert_output "http:1234:5001"
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-json | jq -e 'length == 1 and .[0].scheme == \"http\" and .[0].host_port == 1234 and .[0].container_port == 5001'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ports:add $TEST_APP http:8080:5002 https:8443:5003"
echo "output: $output"
echo "status: $status"
@@ -60,6 +65,11 @@ teardown() {
echo "status: $status"
assert_output "http:1234:5001 http:8080:5002 https:8443:5003"
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-json | jq -e 'length == 3 and any(.scheme == \"http\" and .host_port == 1234 and .container_port == 5001) and any(.scheme == \"http\" and .host_port == 8080 and .container_port == 5002) and any(.scheme == \"https\" and .host_port == 8443 and .container_port == 5003)'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ports:set $TEST_APP http:8080:5000 https:8443:5000 http:1234:5001"
echo "output: $output"
echo "status: $status"
@@ -90,6 +100,11 @@ teardown() {
echo "status: $status"
assert_output "http:1234:5001 http:8080:5000 https:8443:5000"
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-json | jq -e 'length == 3 and any(.scheme == \"http\" and .host_port == 1234 and .container_port == 5001) and any(.scheme == \"http\" and .host_port == 8080 and .container_port == 5000) and any(.scheme == \"https\" and .host_port == 8443 and .container_port == 5000)'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ports:remove $TEST_APP 8080"
echo "output: $output"
echo "status: $status"
@@ -100,6 +115,11 @@ teardown() {
echo "status: $status"
assert_output "http:1234:5001 https:8443:5000"
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-json | jq -e 'length == 2 and any(.scheme == \"http\" and .host_port == 1234 and .container_port == 5001) and any(.scheme == \"https\" and .host_port == 8443 and .container_port == 5000)'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ports:remove $TEST_APP http:1234:5001"
echo "output: $output"
echo "status: $status"
@@ -110,6 +130,11 @@ teardown() {
echo "status: $status"
assert_output "https:8443:5000"
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-json | jq -e 'length == 1 and .[0].scheme == \"https\" and .[0].host_port == 8443 and .[0].container_port == 5000'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ports:clear $TEST_APP"
echo "output: $output"
echo "status: $status"
@@ -120,10 +145,20 @@ teardown() {
echo "status: $status"
assert_output_not_exists
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-json | jq -e '. == [] or . == null'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-detected"
echo "output: $output"
echo "status: $status"
assert_output "http:80:5000"
run /bin/bash -c "dokku --quiet ports:report $TEST_APP --ports-map-detected-json | jq -e 'length == 1 and .[0].scheme == \"http\" and .[0].host_port == 80 and .[0].container_port == 5000'"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(ports:add) post-deploy add" {
@@ -370,3 +405,13 @@ teardown() {
assert_success
assert_output "http:3001:3001"
}
@test "(ports:report) emits new stripped JSON keys alongside legacy" {
run /bin/bash -c "dokku ports:report $TEST_APP --format json | jq -r 'has(\"map\") and has(\"ports-map\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ports:report $TEST_APP --format json | jq -r 'has(\"map-detected\") and has(\"ports-map-detected\")'"
assert_success
assert_output "true"
}

View File

@@ -9,6 +9,8 @@ setup() {
}
teardown() {
dokku proxy:set --global proxy-port >/dev/null 2>&1 || true
dokku proxy:set --global proxy-ssl-port >/dev/null 2>&1 || true
destroy_app
[[ -f "$DOKKU_ROOT/VHOST.bak" ]] && mv "$DOKKU_ROOT/VHOST.bak" "$DOKKU_ROOT/VHOST" && chown dokku:dokku "$DOKKU_ROOT/VHOST"
global_teardown
@@ -28,6 +30,251 @@ teardown() {
assert_output "$help_output"
}
@test "(proxy:report) --global raw vs computed type" {
run /bin/bash -c "dokku proxy:report --global --format json | jq -r '.\"proxy-global-type\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report --global --format json | jq -r '.\"proxy-computed-type\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "nginx"
run /bin/bash -c "dokku proxy:set --global type caddy"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku proxy:report --global --format json | jq -r '.\"proxy-global-type\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "caddy"
run /bin/bash -c "dokku proxy:report --global --format json | jq -r '.\"proxy-computed-type\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "caddy"
run /bin/bash -c "dokku proxy:set --global type"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku proxy:report --global --format json | jq -r '.\"proxy-global-type\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report --global --format json | jq -r '.\"proxy-computed-type\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "nginx"
}
@test "(proxy:report) type raw vs computed vs global" {
run /bin/bash -c "dokku proxy:set --global type"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-type\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-global-type\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-type\"'"
assert_success
assert_output "nginx"
run /bin/bash -c "dokku proxy:set --global type caddy"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-global-type\"'"
assert_success
assert_output "caddy"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-type\"'"
assert_success
assert_output "caddy"
run /bin/bash -c "dokku proxy:set $TEST_APP type traefik"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-type\"'"
assert_success
assert_output "traefik"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-global-type\"'"
assert_success
assert_output "caddy"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-type\"'"
assert_success
assert_output "traefik"
run /bin/bash -c "dokku proxy:set $TEST_APP type"
assert_success
run /bin/bash -c "dokku proxy:set --global type"
assert_success
}
@test "(proxy:report) proxy-port raw vs computed vs global" {
run /bin/bash -c "dokku proxy:set --global proxy-port"
assert_success
run /bin/bash -c "dokku proxy:set $TEST_APP proxy-port"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-proxy-port\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-global-proxy-port\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-proxy-port\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:set --global proxy-port 5000"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-global-proxy-port\"'"
assert_success
assert_output "5000"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-proxy-port\"'"
assert_success
assert_output "5000"
run /bin/bash -c "dokku proxy:set $TEST_APP proxy-port 6000"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-proxy-port\"'"
assert_success
assert_output "6000"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-global-proxy-port\"'"
assert_success
assert_output "5000"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-proxy-port\"'"
assert_success
assert_output "6000"
run /bin/bash -c "dokku proxy:set $TEST_APP proxy-port"
assert_success
run /bin/bash -c "dokku proxy:set --global proxy-port"
assert_success
}
@test "(proxy:report) proxy-ssl-port raw vs computed vs global" {
run /bin/bash -c "dokku proxy:set --global proxy-ssl-port"
assert_success
run /bin/bash -c "dokku proxy:set $TEST_APP proxy-ssl-port"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-proxy-ssl-port\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-global-proxy-ssl-port\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-proxy-ssl-port\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:set --global proxy-ssl-port 5443"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-global-proxy-ssl-port\"'"
assert_success
assert_output "5443"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-proxy-ssl-port\"'"
assert_success
assert_output "5443"
run /bin/bash -c "dokku proxy:set $TEST_APP proxy-ssl-port 6443"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-proxy-ssl-port\"'"
assert_success
assert_output "6443"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-global-proxy-ssl-port\"'"
assert_success
assert_output "5443"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-proxy-ssl-port\"'"
assert_success
assert_output "6443"
run /bin/bash -c "dokku proxy:set $TEST_APP proxy-ssl-port"
assert_success
run /bin/bash -c "dokku proxy:set --global proxy-ssl-port"
assert_success
}
@test "(proxy:report) disabled raw and computed match disabled state" {
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-disabled\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-disabled\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-enabled\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku proxy:disable $TEST_APP"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-disabled\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-disabled\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-enabled\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku proxy:enable $TEST_APP"
assert_success
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-disabled\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-computed-disabled\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r '.\"proxy-enabled\"'"
assert_success
assert_output "true"
}
@test "(proxy:set) invalid port mapping set" {
run /bin/bash -c "dokku proxy:set $TEST_APP http:80:80"
echo "output: $output"
@@ -125,3 +372,21 @@ teardown() {
assert_not_external_port $(<$CID_FILE)
done
}
@test "(proxy:report) emits new stripped JSON keys alongside legacy" {
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r 'has(\"type\") and has(\"proxy-type\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r 'has(\"global-type\") and has(\"proxy-global-type\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r 'has(\"computed-type\") and has(\"proxy-computed-type\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku proxy:report $TEST_APP --format json | jq -r 'has(\"enabled\") and has(\"proxy-enabled\")'"
assert_success
assert_output "true"
}

View File

@@ -83,7 +83,7 @@ teardown() {
run /bin/bash -c "dokku ps:report $TEST_APP --ps-global-procfile-path"
echo "output: $output"
echo "status: $status"
assert_output "Procfile"
assert_output ""
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --ps-procfile-path"
@@ -93,6 +93,114 @@ teardown() {
assert_success
}
@test "(ps:set) skip-deploy raw/global/computed" {
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-skip-deploy\"'"
echo "output: $output"
echo "status: $status"
assert_output "false"
assert_success
run /bin/bash -c "dokku ps:set --global skip-deploy true"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-global-skip-deploy\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-skip-deploy\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-skip-deploy\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:set $TEST_APP skip-deploy false"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-skip-deploy\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-global-skip-deploy\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-skip-deploy\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku ps:set $TEST_APP skip-deploy"
assert_success
run /bin/bash -c "dokku ps:set --global skip-deploy"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-global-skip-deploy\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-skip-deploy\"'"
assert_success
assert_output "false"
}
@test "(ps:set) dockerfile-start-cmd raw and computed" {
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-dockerfile-start-cmd\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-dockerfile-start-cmd\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:set $TEST_APP dockerfile-start-cmd 'node app.js'"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-dockerfile-start-cmd\"'"
assert_success
assert_output "node app.js"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-dockerfile-start-cmd\"'"
assert_success
assert_output "node app.js"
run /bin/bash -c "dokku ps:set $TEST_APP dockerfile-start-cmd"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-dockerfile-start-cmd\"'"
assert_success
assert_output ""
}
@test "(ps:set) start-cmd raw and computed" {
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-start-cmd\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-start-cmd\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:set $TEST_APP start-cmd 'bundle exec rails server'"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-start-cmd\"'"
assert_success
assert_output "bundle exec rails server"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-start-cmd\"'"
assert_success
assert_output "bundle exec rails server"
run /bin/bash -c "dokku ps:set $TEST_APP start-cmd"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-start-cmd\"'"
assert_success
assert_output ""
}
@test "(ps:scale) procfile commands extraction" {
source "$PLUGIN_CORE_AVAILABLE_PATH/ps/functions"
cat <<EOF >"$DOKKU_LIB_ROOT/data/ps/$TEST_APP/Procfile"
@@ -161,6 +269,42 @@ web
assert_output $'beat: 0\nweb: 4\nworker: 1'
}
@test "(ps:scale) --format json" {
run /bin/bash -c "dokku ps:scale $TEST_APP --format json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output '[{"process_type":"web","quantity":1}]'
echo "web=4
worker=1" >/var/lib/dokku/config/ps/$TEST_APP/scale
run /bin/bash -c "dokku ps:scale $TEST_APP --format json | jq '. | length'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "2"
run /bin/bash -c "dokku ps:scale $TEST_APP --format json | jq -r '.[] | select(.process_type==\"web\") | .quantity'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "4"
run /bin/bash -c "dokku ps:scale $TEST_APP --format json | jq -r '.[] | select(.process_type==\"worker\") | .quantity'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "1"
rm -f /var/lib/dokku/config/ps/$TEST_APP/scale
run /bin/bash -c "dokku ps:scale $TEST_APP --format json"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "[]"
}
@test "(ps) handle windows newlines in procfile" {
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP procfile_line_endings_to_windows
echo "output: $output"
@@ -168,8 +312,167 @@ web
assert_success
}
@test "(ps:report) stop-timeout-seconds raw vs computed vs global" {
run /bin/bash -c "dokku ps:set --global stop-timeout-seconds"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-stop-timeout-seconds\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"stop-timeout-seconds\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-global-stop-timeout-seconds\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"global-stop-timeout-seconds\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-stop-timeout-seconds\"'"
assert_success
assert_output "30"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"computed-stop-timeout-seconds\"'"
assert_success
assert_output "30"
run /bin/bash -c "dokku ps:set --global stop-timeout-seconds 90"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-global-stop-timeout-seconds\"'"
assert_success
assert_output "90"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"global-stop-timeout-seconds\"'"
assert_success
assert_output "90"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-stop-timeout-seconds\"'"
assert_success
assert_output "90"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"computed-stop-timeout-seconds\"'"
assert_success
assert_output "90"
run /bin/bash -c "dokku ps:set $TEST_APP stop-timeout-seconds 45"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-stop-timeout-seconds\"'"
assert_success
assert_output "45"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"stop-timeout-seconds\"'"
assert_success
assert_output "45"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-global-stop-timeout-seconds\"'"
assert_success
assert_output "90"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"ps-computed-stop-timeout-seconds\"'"
assert_success
assert_output "45"
run /bin/bash -c "dokku ps:report $TEST_APP --format json | jq -r '.\"computed-stop-timeout-seconds\"'"
assert_success
assert_output "45"
run /bin/bash -c "dokku ps:set $TEST_APP stop-timeout-seconds"
assert_success
run /bin/bash -c "dokku ps:set --global stop-timeout-seconds"
assert_success
}
@test "(ps:report) --global --format json" {
run /bin/bash -c "dokku ps:report --global --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:report --global --format json | jq -r 'has(\"ps-global-procfile-path\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report --global --format json | jq -r 'has(\"global-procfile-path\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report --global --format json | jq -r 'has(\"ps-computed-procfile-path\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report --global --format json | jq -r 'has(\"computed-procfile-path\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report --global --format json | jq -r 'has(\"ps-global-stop-timeout-seconds\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report --global --format json | jq -r 'has(\"global-stop-timeout-seconds\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report --global --format json | jq -r 'has(\"ps-computed-stop-timeout-seconds\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:report --global --format json | jq -r 'has(\"computed-stop-timeout-seconds\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku ps:set --global stop-timeout-seconds 75"
assert_success
run /bin/bash -c "dokku ps:report --global --format json | jq -r '.\"ps-global-stop-timeout-seconds\"'"
assert_success
assert_output "75"
run /bin/bash -c "dokku ps:report --global --format json | jq -r '.\"global-stop-timeout-seconds\"'"
assert_success
assert_output "75"
run /bin/bash -c "dokku ps:report --global --format json | jq -r '.\"ps-computed-stop-timeout-seconds\"'"
assert_success
assert_output "75"
run /bin/bash -c "dokku ps:report --global --format json | jq -r '.\"computed-stop-timeout-seconds\"'"
assert_success
assert_output "75"
run /bin/bash -c "dokku ps:set --global stop-timeout-seconds"
assert_success
run /bin/bash -c "dokku ps:report --global --format json | jq -r '.\"ps-global-stop-timeout-seconds\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:report --global --format json | jq -r '.\"global-stop-timeout-seconds\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku ps:report --global --format json | jq -r '.\"ps-computed-stop-timeout-seconds\"'"
assert_success
assert_output "30"
run /bin/bash -c "dokku ps:report --global --format json | jq -r '.\"computed-stop-timeout-seconds\"'"
assert_success
assert_output "30"
}
@test "(ps:restart-policy) default policy" {
run /bin/bash -c "dokku --quiet ps:report $TEST_APP --ps-restart-policy"
run /bin/bash -c "dokku ps:report $TEST_APP --ps-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --ps-computed-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output "on-failure:10"
@@ -182,13 +485,90 @@ web
echo "status: $status"
assert_success
run /bin/bash -c "dokku --quiet ps:report $TEST_APP --ps-restart-policy"
run /bin/bash -c "dokku ps:report $TEST_APP --ps-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output "$policy"
run /bin/bash -c "dokku ps:report $TEST_APP --ps-computed-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output "$policy"
done
}
@test "(ps:restart-policy) ps:set restart-policy unset" {
run /bin/bash -c "dokku ps:set $TEST_APP restart-policy on-failure:5"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --ps-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output "on-failure:5"
run /bin/bash -c "dokku ps:set $TEST_APP restart-policy"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --ps-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --ps-computed-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output "on-failure:10"
}
@test "(ps:restart-policy) invalid policy" {
run /bin/bash -c "dokku ps:set $TEST_APP restart-policy bogus"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid restart-policy specified"
}
@test "(ps:restart-policy) global policy" {
run /bin/bash -c "dokku ps:set --global restart-policy always"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --ps-global-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output "always"
run /bin/bash -c "dokku ps:report $TEST_APP --ps-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output ""
run /bin/bash -c "dokku ps:report $TEST_APP --ps-computed-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output "always"
run /bin/bash -c "dokku ps:set $TEST_APP restart-policy no"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:report $TEST_APP --ps-computed-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output "no"
run /bin/bash -c "dokku ps:set --global restart-policy"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(ps:restart-policy) deployed policy" {
test_restart_policy="on-failure:20"
run /bin/bash -c "dokku ps:set $TEST_APP restart-policy $test_restart_policy"
@@ -196,7 +576,7 @@ web
echo "status: $status"
assert_success
run /bin/bash -c "dokku --quiet ps:report $TEST_APP --ps-restart-policy"
run /bin/bash -c "dokku ps:report $TEST_APP --ps-restart-policy"
echo "output: $output"
echo "status: $status"
assert_output "$test_restart_policy"
@@ -216,6 +596,22 @@ web
echo "output: $output"
echo "status: $status"
assert_output "$test_restart_policy"
run /bin/bash -c "dokku ps:set $TEST_APP restart-policy"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
CID=$(<$DOKKU_ROOT/$TEST_APP/CONTAINER.web.1)
run /bin/bash -c "docker inspect -f '{{ .HostConfig.RestartPolicy.Name }}:{{ .HostConfig.RestartPolicy.MaximumRetryCount }}' $CID"
echo "output: $output"
echo "status: $status"
assert_output "on-failure:10"
}
procfile_line_endings_to_windows() {

View File

@@ -133,6 +133,314 @@ teardown() {
create_app
}
@test "(registry:report) image-repo raw vs computed vs global" {
run /bin/bash -c "dokku registry:set --global image-repo-template"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-image-repo\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-global-image-repo-template\"'"
assert_success
assert_output ""
# When neither per-app image-repo nor a global image-repo-template are set,
# reportComputedImageRepo falls back to common.GetAppImageRepo which returns
# the default dokku/<app> image name.
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo\"'"
assert_success
assert_output "dokku/$TEST_APP"
run /bin/bash -c "dokku registry:set --global image-repo-template 'dokku/{{ APP }}'"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-global-image-repo-template\"'"
assert_success
assert_output 'dokku/{{ APP }}'
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo\"'"
assert_success
assert_output "dokku/$TEST_APP"
run /bin/bash -c "dokku registry:set $TEST_APP image-repo my/$TEST_APP"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-image-repo\"'"
assert_success
assert_output "my/$TEST_APP"
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo\"'"
assert_success
assert_output "my/$TEST_APP"
run /bin/bash -c "dokku registry:set $TEST_APP image-repo"
assert_success
run /bin/bash -c "dokku registry:set --global image-repo-template"
assert_success
}
@test "(registry:report) image-repo-template raw vs computed vs global" {
run /bin/bash -c "dokku registry:set --global image-repo-template"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-image-repo-template\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-global-image-repo-template\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo-template\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:set --global image-repo-template 'global-prefix/{{ .AppName }}'"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-image-repo-template\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-global-image-repo-template\"'"
assert_success
assert_output 'global-prefix/{{ .AppName }}'
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo-template\"'"
assert_success
assert_output 'global-prefix/{{ .AppName }}'
# The global template renders into the computed image-repo.
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo\"'"
assert_success
assert_output "global-prefix/$TEST_APP"
# Per-app template overrides the global template.
run /bin/bash -c "dokku registry:set $TEST_APP image-repo-template 'app-prefix/{{ .AppName }}-prod'"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-image-repo-template\"'"
assert_success
assert_output 'app-prefix/{{ .AppName }}-prod'
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-global-image-repo-template\"'"
assert_success
assert_output 'global-prefix/{{ .AppName }}'
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo-template\"'"
assert_success
assert_output 'app-prefix/{{ .AppName }}-prod'
# The per-app template flows through to the computed image-repo.
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo\"'"
assert_success
assert_output "app-prefix/$TEST_APP-prod"
# Unsetting the per-app template restores the global template behavior.
run /bin/bash -c "dokku registry:set $TEST_APP image-repo-template"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-image-repo-template\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo-template\"'"
assert_success
assert_output 'global-prefix/{{ .AppName }}'
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-image-repo\"'"
assert_success
assert_output "global-prefix/$TEST_APP"
run /bin/bash -c "dokku registry:set --global image-repo-template"
assert_success
}
@test "(registry:report) push-on-release raw vs computed vs global" {
run /bin/bash -c "dokku registry:set --global push-on-release"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-push-on-release\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-global-push-on-release\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-push-on-release\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku registry:set --global push-on-release true"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-global-push-on-release\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-push-on-release\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku registry:set $TEST_APP push-on-release false"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-push-on-release\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-push-on-release\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku registry:set $TEST_APP push-on-release"
assert_success
run /bin/bash -c "dokku registry:set --global push-on-release"
assert_success
}
@test "(registry:report --global) computed and global keys" {
run /bin/bash -c "dokku registry:set --global push-on-release"
assert_success
run /bin/bash -c "dokku registry:set --global server"
assert_success
run /bin/bash -c "dokku registry:set --global image-repo-template"
assert_success
run /bin/bash -c "dokku registry:set --global push-extra-tags"
assert_success
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-push-on-release\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-push-on-release\"'"
assert_success
assert_output "false"
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-server\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-server\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-image-repo-template\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-image-repo-template\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-push-extra-tags\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-push-extra-tags\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:set --global push-on-release true"
assert_success
run /bin/bash -c "dokku registry:set --global server ghcr.io"
assert_success
run /bin/bash -c "dokku registry:set --global image-repo-template 'dokku/{{ APP }}'"
assert_success
run /bin/bash -c "dokku registry:set --global push-extra-tags latest,stable"
assert_success
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-push-on-release\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-push-on-release\"'"
assert_success
assert_output "true"
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-server\"'"
assert_success
assert_output "ghcr.io"
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-server\"'"
assert_success
assert_output "ghcr.io/"
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-image-repo-template\"'"
assert_success
assert_output 'dokku/{{ APP }}'
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-image-repo-template\"'"
assert_success
assert_output 'dokku/{{ APP }}'
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-global-push-extra-tags\"'"
assert_success
assert_output "latest,stable"
run /bin/bash -c "dokku registry:report --global --format json | jq -r '.\"registry-computed-push-extra-tags\"'"
assert_success
assert_output "latest,stable"
run /bin/bash -c "dokku registry:set --global push-on-release"
assert_success
run /bin/bash -c "dokku registry:set --global server"
assert_success
run /bin/bash -c "dokku registry:set --global image-repo-template"
assert_success
run /bin/bash -c "dokku registry:set --global push-extra-tags"
assert_success
}
@test "(registry:report) push-extra-tags raw vs computed vs global" {
run /bin/bash -c "dokku registry:set --global push-extra-tags"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-push-extra-tags\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-global-push-extra-tags\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-push-extra-tags\"'"
assert_success
assert_output ""
run /bin/bash -c "dokku registry:set --global push-extra-tags global-tag"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-global-push-extra-tags\"'"
assert_success
assert_output "global-tag"
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-push-extra-tags\"'"
assert_success
assert_output "global-tag"
run /bin/bash -c "dokku registry:set $TEST_APP push-extra-tags release,stable"
assert_success
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-push-extra-tags\"'"
assert_success
assert_output "release,stable"
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r '.\"registry-computed-push-extra-tags\"'"
assert_success
assert_output "release,stable"
run /bin/bash -c "dokku registry:set $TEST_APP push-extra-tags"
assert_success
run /bin/bash -c "dokku registry:set --global push-extra-tags"
assert_success
}
@test "(registry) registry:set server" {
run /bin/bash -c "dokku registry:set --global server ghcr.io"
echo "output: $output"
@@ -409,3 +717,29 @@ teardown() {
assert_success
assert_output_contains "dokku/test-app:foo"
}
@test "(registry:report) emits new stripped JSON keys alongside legacy" {
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r 'has(\"image-repo\") and has(\"registry-image-repo\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r 'has(\"computed-image-repo\") and has(\"registry-computed-image-repo\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r 'has(\"push-on-release\") and has(\"registry-push-on-release\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r 'has(\"global-push-on-release\") and has(\"registry-global-push-on-release\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku registry:report $TEST_APP --format json | jq -r 'has(\"computed-server\") and has(\"registry-computed-server\")'"
assert_success
assert_output "true"
run /bin/bash -c "dokku registry:report --global --format json | jq -r 'has(\"global-image-repo-template\") and has(\"registry-global-image-repo-template\")'"
assert_success
assert_output "true"
}

100
tests/unit/registry_2.bats Normal file
View File

@@ -0,0 +1,100 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
create_app
dokku checks:set $TEST_APP wait-to-retire 30
}
teardown() {
destroy_app
global_teardown
}
setup_push_on_release_app() {
if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then
skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN"
fi
run /bin/bash -c "dokku builder:set $TEST_APP selected herokuish"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku proxy:set $TEST_APP nginx"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku registry:login $TEST_APP docker.io $DOCKERHUB_USERNAME $DOCKERHUB_TOKEN"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku registry:set $TEST_APP image-repo $DOCKERHUB_USERNAME/$TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku registry:set $TEST_APP push-on-release true"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "docker image rm $DOCKERHUB_USERNAME/$TEST_APP:1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "docker image inspect $DOCKERHUB_USERNAME/$TEST_APP:1"
echo "output: $output"
echo "status: $status"
assert_failure
}
@test "(registry) [recover] ps:restart pulls missing image" {
setup_push_on_release_app
run /bin/bash -c "dokku ps:restart $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "not found locally, pulling from registry"
run /bin/bash -c "docker image inspect $DOCKERHUB_USERNAME/$TEST_APP:1"
echo "output: $output"
echo "status: $status"
assert_success
}
@test "(registry) [recover] dokku run pulls missing image" {
setup_push_on_release_app
run /bin/bash -c "dokku run $TEST_APP echo recovery-ok"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "not found locally, pulling from registry"
assert_output_contains "recovery-ok"
}
@test "(registry) [recover] domains:add pulls missing image" {
setup_push_on_release_app
run /bin/bash -c "dokku domains:add $TEST_APP recovery.${DOKKU_DOMAIN}"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "docker image inspect $DOCKERHUB_USERNAME/$TEST_APP:1"
echo "output: $output"
echo "status: $status"
assert_success
}

View File

@@ -26,7 +26,7 @@ teardown() {
echo "output: $output"
echo "status: $status"
assert_output_contains "herokuish version:"
assert_output_contains "Deployed: false" "0"
assert_output_contains "Deployed: false" "0"
assert_success
run /bin/bash -c "dokku report fake-app-name"
@@ -48,7 +48,7 @@ teardown() {
run /bin/bash -c "dokku report ${TEST_APP}-2 2>&1"
echo "output: $output"
echo "status: $status"
assert_output_contains "Deployed: false"
assert_output_contains "Deployed: false"
assert_success
run /bin/bash -c "dokku --force apps:destroy ${TEST_APP}-2"

131
tests/unit/resource_3.bats Normal file
View File

@@ -0,0 +1,131 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
create_app
}
teardown() {
destroy_app
global_teardown
}
@test "(resource) resource:limit --process-type build (herokuish)" {
run /bin/bash -c "dokku resource:limit --memory 256m --cpu 1 --memory-swap 512m --nvidia-gpu 1 --process-type build $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku resource:report --resource-build.limit.memory $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_output "256m"
run_plugn_trigger docker-args-process-build "$TEST_APP" herokuish
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "--memory=256m"
assert_output_contains "--cpus=1"
assert_output_contains "--memory-swap=512m"
assert_output_contains "--gpus=1"
}
@test "(resource) resource:limit --process-type build (dockerfile filters cpu and gpu)" {
run /bin/bash -c "dokku resource:limit --memory 512m --cpu 1 --nvidia-gpu 1 --memory-swap 1g --process-type build $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run_plugn_trigger docker-args-process-build "$TEST_APP" dockerfile
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "--memory=512m"
assert_output_contains "--memory-swap=1g"
assert_output_not_contains "--cpus="
assert_output_not_contains "--gpus="
}
@test "(resource) resource:limit --process-type build (pack/lambda emit nothing)" {
run /bin/bash -c "dokku resource:limit --memory 512m --process-type build $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run_plugn_trigger docker-args-process-build "$TEST_APP" pack
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "--memory"
run_plugn_trigger docker-args-process-build "$TEST_APP" lambda
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "--memory"
}
@test "(resource) resource:limit defaults do not leak into build trigger" {
run /bin/bash -c "dokku resource:limit --memory 128m $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run_plugn_trigger docker-args-process-build "$TEST_APP" herokuish
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "--memory"
}
@test "(resource) resource:limit reservations do not apply at build time" {
run /bin/bash -c "dokku resource:reserve --memory 128m --process-type build $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run_plugn_trigger docker-args-process-build "$TEST_APP" herokuish
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "--memory-reservation"
assert_output_not_contains "--memory"
}
@test "(resource) DOKKU_OMIT_RESOURCE_ARGS suppresses build trigger" {
run /bin/bash -c "dokku resource:limit --memory 256m --process-type build $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run_plugn_trigger DOKKU_OMIT_RESOURCE_ARGS=1 docker-args-process-build "$TEST_APP" herokuish
echo "output: $output"
echo "status: $status"
assert_success
assert_output_not_contains "--memory"
}
@test "(resource) resource:limit-clear --process-type build" {
run /bin/bash -c "dokku resource:limit --memory 256m --process-type build $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku resource:report --resource-build.limit.memory $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_output "256m"
run /bin/bash -c "dokku resource:limit-clear --process-type build $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku resource:report --resource-build.limit.memory $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
}

View File

@@ -153,3 +153,46 @@ teardown() {
assert_success
assert_output "2"
}
@test "(run) docker-options and -e flags are not eval-injected" {
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP run '--label=com.dokku.test=safe'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku run --ttl-seconds=60 -e FOO=bar $TEST_APP env | grep -E '^FOO=bar'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku run -e 'X=\$(id)' $TEST_APP env"
echo "output: $output"
echo "status: $status"
assert_success
[[ "$output" == *'X=$(id)'* ]] || flunk "expected literal X=\$(id) in container env"
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - env value was expanded"
}
@test "(run) --ttl-seconds rejects non-numeric input; docker-options stores it verbatim" {
run /bin/bash -c "dokku run --ttl-seconds '\$(id)' $TEST_APP echo hi"
echo "output: $output"
echo "status: $status"
assert_failure
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - ttl value was expanded"
run /bin/bash -c "dokku docker-options:add $TEST_APP run '--label=x=\$(id)'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:report $TEST_APP --docker-options-run"
echo "output: $output"
echo "status: $status"
[[ "$output" == *'x=$(id)'* ]] || flunk "expected literal x=\$(id) stored in docker options"
[[ "$output" != *"uid="* ]] || flunk "id command output leaked - docker option was expanded"
}

View File

@@ -10,6 +10,181 @@ teardown() {
global_teardown
}
@test "(scheduler-docker-local:report) --global raw and computed keys" {
run /bin/bash -c "dokku scheduler-docker-local:report --global --scheduler-docker-local-global-init-process"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report --global --scheduler-docker-local-computed-init-process"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku scheduler-docker-local:report --global --scheduler-docker-local-global-parallel-schedule-count"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report --global --scheduler-docker-local-computed-parallel-schedule-count"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "1"
}
@test "(scheduler-docker-local:report) info-flag works before deploy" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --scheduler-docker-local-parallel-schedule-count"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --scheduler-docker-local-computed-parallel-schedule-count"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "1"
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --scheduler-docker-local-global-parallel-schedule-count"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --scheduler-docker-local-init-process"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --scheduler-docker-local-computed-init-process"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "true"
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --scheduler-docker-local-global-init-process"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --scheduler-docker-local-invalid-flag"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "Invalid flag passed"
destroy_app
}
@test "(scheduler-docker-local:report) --format json" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -e ."
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"init-process\"'"
echo "output: $output"
echo "status: $status"
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"computed-init-process\"'"
echo "output: $output"
echo "status: $status"
assert_output "true"
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"global-init-process\"'"
echo "output: $output"
echo "status: $status"
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"parallel-schedule-count\"'"
echo "output: $output"
echo "status: $status"
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"computed-parallel-schedule-count\"'"
echo "output: $output"
echo "status: $status"
assert_output "1"
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"global-parallel-schedule-count\"'"
echo "output: $output"
echo "status: $status"
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:set $TEST_APP init-process false"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"init-process\"'"
echo "output: $output"
echo "status: $status"
assert_output "false"
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"computed-init-process\"'"
echo "output: $output"
echo "status: $status"
assert_output "false"
destroy_app
}
@test "(scheduler-docker-local:set) --global" {
run /bin/bash -c "dokku scheduler-docker-local:set --global parallel-schedule-count 4"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-docker-local:report --global --format json | jq -r '.\"global-parallel-schedule-count\"'"
echo "output: $output"
echo "status: $status"
assert_output "4"
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"parallel-schedule-count\"'"
echo "output: $output"
echo "status: $status"
assert_output ""
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"computed-parallel-schedule-count\"'"
echo "output: $output"
echo "status: $status"
assert_output "4"
run /bin/bash -c "dokku scheduler-docker-local:report $TEST_APP --format json | jq -r '.\"global-parallel-schedule-count\"'"
echo "output: $output"
echo "status: $status"
assert_output "4"
run /bin/bash -c "dokku scheduler-docker-local:set --global parallel-schedule-count"
echo "output: $output"
echo "status: $status"
assert_success
destroy_app
}
@test "(scheduler-docker-local) scheduler-docker-local:help" {
run /bin/bash -c "dokku scheduler-docker-local"
echo "output: $output"
@@ -175,3 +350,136 @@ teardown() {
assert_output_contains "Deploys may fail when publishing ports and scaling to multiple containers" 0
assert_output_contains "Deploys may fail when publishing ports and enabling zero downtime" 0
}
@test "(scheduler-docker-local) sends SIGTERM immediately on deploy" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:set $TEST_APP wait-to-retire 600"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
local old_cid
old_cid="$(docker ps --filter label=com.dokku.app-name=$TEST_APP --filter label=com.dokku.process-type=web --format '{{.ID}}')"
[[ -n "$old_cid" ]]
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
sleep 5
run /bin/bash -c "docker inspect --format '{{.State.Status}}' $old_cid"
echo "output: $output"
echo "status: $status"
assert_output "exited"
run /bin/bash -c "docker ps --filter label=com.dokku.app-name=$TEST_APP --filter label=com.dokku.process-type=web --format '{{.Names}}'"
echo "output: $output"
echo "status: $status"
assert_output "$TEST_APP.web.1"
}
@test "(scheduler-docker-local) scale down retires orphaned containers" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:set $TEST_APP wait-to-retire 1"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:scale $TEST_APP web=2"
echo "output: $output"
echo "status: $status"
assert_success
sleep 2
run /bin/bash -c "dokku ps:retire"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "docker ps --filter label=com.dokku.app-name=$TEST_APP --filter label=com.dokku.process-type=web --format '{{.Names}}' | wc -l"
echo "output: $output"
echo "status: $status"
assert_output "2"
run /bin/bash -c "dokku ps:scale $TEST_APP web=1"
echo "output: $output"
echo "status: $status"
assert_success
sleep 2
run /bin/bash -c "dokku ps:retire"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "docker ps --filter label=com.dokku.app-name=$TEST_APP --filter label=com.dokku.process-type=web --format '{{.Names}}'"
echo "output: $output"
echo "status: $status"
assert_output "$TEST_APP.web.1"
}
@test "(scheduler-docker-local) ps:rebuild with image-based deploy keeps running image" {
run create_app
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku checks:set $TEST_APP wait-to-retire 1"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku git:from-image $TEST_APP cockpithq/cockpit:core-latest"
echo "output: $output"
echo "status: $status"
assert_success
local running_image
running_image="$(docker container inspect "$TEST_APP.web.1" --format '{{.Image}}' | cut -d: -f2)"
[[ -n "$running_image" ]]
run /bin/bash -c "dokku ps:rebuild $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
sleep 3
run /bin/bash -c "dokku ps:retire"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "has running containers, skipping rm" 0
run /bin/bash -c "grep -F \"$running_image\" /var/lib/dokku/data/scheduler-docker-local/dead-images 2>/dev/null || true"
echo "output: $output"
echo "status: $status"
assert_output ""
run /bin/bash -c "docker container inspect $TEST_APP.web.1 --format '{{.State.Status}}'"
echo "output: $output"
echo "status: $status"
assert_output "running"
}

View File

@@ -52,6 +52,66 @@ teardown() {
assert_output "5000"
}
@test "(scheduler-k3s) deploy autoscaling cpu-only trigger [keda-fallback]" {
if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then
skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN"
fi
INGRESS_CLASS=nginx install_k3s
run /bin/bash -c "dokku apps:create $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP inject_cpu_autoscaling_app_json
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "kubectl get scaledobjects.keda.sh $TEST_APP-web -o=jsonpath='{.spec.fallback}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
run /bin/bash -c "kubectl get scaledobjects.keda.sh $TEST_APP-web -o=jsonpath='{.spec.triggers[0].type}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "cpu"
}
@test "(scheduler-k3s) deploy autoscaling external trigger [keda-fallback]" {
if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then
skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN"
fi
INGRESS_CLASS=nginx install_k3s
run /bin/bash -c "dokku apps:create $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP inject_prometheus_autoscaling_app_json
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "kubectl get scaledobjects.keda.sh $TEST_APP-web -o=jsonpath='{.spec.fallback.failureThreshold}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "3"
run /bin/bash -c "kubectl get scaledobjects.keda.sh $TEST_APP-web -o=jsonpath='{.spec.fallback.replicas}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "1"
}
inject_app_json() {
local APP="$1"
local APP_REPO_DIR="$2"
@@ -68,3 +128,60 @@ inject_app_json() {
}
EOF
}
inject_cpu_autoscaling_app_json() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"formation": {
"web": {
"autoscaling": {
"min_quantity": 1,
"max_quantity": 3,
"triggers": [
{
"name": "cpu-trigger",
"type": "cpu",
"metadata": {
"value": "80"
}
}
]
}
}
}
}
EOF
}
inject_prometheus_autoscaling_app_json() {
local APP="$1"
local APP_REPO_DIR="$2"
[[ -z "$APP" ]] && local APP="$TEST_APP"
cat <<EOF >"$APP_REPO_DIR/app.json"
{
"formation": {
"web": {
"autoscaling": {
"min_quantity": 1,
"max_quantity": 3,
"triggers": [
{
"name": "prom-trigger",
"type": "prometheus",
"metadata": {
"serverAddress": "http://prometheus.example.com:9090",
"metricName": "http_requests_total",
"threshold": "100",
"query": "sum(rate(http_requests_total{deployment=\"[[ .DEPLOYMENT_NAME ]]\"}[2m]))"
}
}
]
}
}
}
}
EOF
}

View File

@@ -0,0 +1,147 @@
#!/usr/bin/env bats
load test_helper
TEST_APP="rdmtestapp"
setup() {
uninstall_k3s || true
global_setup
dokku nginx:stop
export KUBECONFIG="/etc/rancher/k3s/k3s.yaml"
}
teardown() {
dokku scheduler-k3s:node-sysctls:set --global vm.max_map_count || true
global_teardown
dokku nginx:start
uninstall_k3s || true
}
@test "(scheduler-k3s) docker-options sysctl" {
if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then
skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN"
fi
INGRESS_CLASS=nginx install_k3s
run /bin/bash -c "dokku apps:create $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python dokku@$DOKKU_DOMAIN:$TEST_APP
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "kubectl get deployment $TEST_APP-web -o json | jq -r '.spec.template.spec.securityContext.sysctls'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "null"
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '--sysctl net.ipv4.ip_unprivileged_port_start=1024'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:restart $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "kubectl get deployment $TEST_APP-web -o json | jq -r '.spec.template.spec.securityContext.sysctls[0].name'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "net.ipv4.ip_unprivileged_port_start"
run /bin/bash -c "kubectl get deployment $TEST_APP-web -o json | jq -r '.spec.template.spec.securityContext.sysctls[0].value'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "1024"
run /bin/bash -c "dokku docker-options:remove $TEST_APP deploy '--sysctl net.ipv4.ip_unprivileged_port_start=1024'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku docker-options:add $TEST_APP deploy '--sysctl vm.max_map_count=262144'"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku ps:restart $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_failure
assert_output_contains "is not namespaced" -1
}
@test "(scheduler-k3s:node-sysctls) applies non-namespaced sysctls to nodes" {
if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then
skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN"
fi
INGRESS_CLASS=nginx install_k3s
run /bin/bash -c "kubectl get daemonset -n kube-system dokku-node-sysctls-global"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "dokku scheduler-k3s:node-sysctls:set --global vm.max_map_count 262144"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-k3s:node-sysctls:report --format json | jq -r '.\"--global\".\"vm.max_map_count\"'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "262144"
run /bin/bash -c "kubectl rollout status daemonset -n kube-system dokku-node-sysctls-global --timeout=120s"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "kubectl get daemonset -n kube-system dokku-node-sysctls-global -o json | jq -r '.status.desiredNumberScheduled'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "$(kubectl get nodes --no-headers | wc -l | tr -d ' ')"
run /bin/bash -c "cat /proc/sys/vm/max_map_count"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "262144"
run /bin/bash -c "dokku scheduler-k3s:node-sysctls:set --global vm.max_map_count"
echo "output: $output"
echo "status: $status"
assert_success
run wait_for_daemonset_deletion dokku-node-sysctls-global
echo "output: $output"
echo "status: $status"
assert_success
}
wait_for_daemonset_deletion() {
declare desc="waits for a daemonset to be removed from the api server"
declare NAME="$1"
for _ in $(seq 1 30); do
if ! kubectl get daemonset -n kube-system "$NAME" >/dev/null 2>&1; then
return 0
fi
sleep 2
done
echo "daemonset $NAME still exists after 60s"
return 1
}

View File

@@ -0,0 +1,115 @@
#!/usr/bin/env bats
load test_helper
setup() {
global_setup
dokku apps:create $TEST_APP >/dev/null 2>/dev/null || true
}
teardown() {
dokku --force apps:destroy $TEST_APP >/dev/null 2>/dev/null || true
dokku --force apps:destroy ${TEST_APP}-2 >/dev/null 2>/dev/null || true
for resource in deployment service pod cronjob job secret ingress serviceaccount; do
dokku scheduler-k3s:annotations:set --global --resource-type "$resource" foo "" >/dev/null 2>/dev/null || true
dokku scheduler-k3s:annotations:set --global --resource-type "$resource" bar "" >/dev/null 2>/dev/null || true
done
global_teardown
}
@test "(scheduler-k3s:annotations:report) lists annotations after set, clears them after unset" {
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment foo bar"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --format json | jq -r '.\"global.deployment.foo\"'"
assert_success
assert_output "bar"
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP"
assert_success
assert_output_contains "$TEST_APP annotations information"
assert_output_contains "Annotation (global/deployment) foo:"
assert_output_contains "bar"
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --scheduler-k3s-annotations.global.deployment.foo"
assert_success
assert_output "bar"
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment foo"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --format json"
assert_success
assert_output "{}"
}
@test "(scheduler-k3s:annotations:report) honours --process-type and --resource-type filters" {
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment foo bar"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --process-type web --resource-type deployment baz qux"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type service alpha beta"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --resource-type deployment --format json | jq -r 'keys | sort | join(\",\")'"
assert_success
assert_output "global.deployment.foo,web.deployment.baz"
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --process-type web --format json | jq -r 'keys | sort | join(\",\")'"
assert_success
assert_output "web.deployment.baz"
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --process-type web --resource-type deployment --format json | jq -r '.\"web.deployment.baz\"'"
assert_success
assert_output "qux"
}
@test "(scheduler-k3s:annotations:report) supports --global scope and no-arg multi-app loop" {
run /bin/bash -c "dokku apps:create ${TEST_APP}-2"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:set --global --resource-type deployment foo global-val"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment foo app1-val"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:set ${TEST_APP}-2 --resource-type deployment bar app2-val"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:report --global --format json | jq -r '.\"global.deployment.foo\"'"
assert_success
assert_output "global-val"
run /bin/bash -c "dokku scheduler-k3s:annotations:report"
assert_success
assert_output_contains "$TEST_APP annotations information"
assert_output_contains "${TEST_APP}-2 annotations information"
assert_output_contains "app1-val"
assert_output_contains "app2-val"
}
@test "(scheduler-k3s:annotations:set) preserves multi-line values and / in keys" {
local value=$'line one\nline two\nline three'
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment prometheus.io/scrape \"$value\""
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --format json | jq -r '.\"global.deployment.prometheus.io/scrape\"'"
assert_success
assert_output "$value"
}
@test "(scheduler-k3s:annotations:report) rejects invalid format and info-flag combinations" {
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --format yaml"
assert_failure
assert_output_contains "Invalid format"
run /bin/bash -c "dokku scheduler-k3s:annotations:set $TEST_APP --resource-type deployment foo bar"
assert_success
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --format json --scheduler-k3s-annotations.global.deployment.foo"
assert_failure
assert_output_contains "--format flag cannot be specified when specifying an info flag"
run /bin/bash -c "dokku scheduler-k3s:annotations:report $TEST_APP --scheduler-k3s-annotations.global.deployment.missing"
assert_failure
assert_output_contains "Invalid flag passed"
}

View File

@@ -0,0 +1,151 @@
#!/usr/bin/env bats
load test_helper
scheduler_k3s_seed_trigger_auth() {
local scope="$1"
local trigger="$2"
local key="$3"
local value="$4"
local dir="/var/lib/dokku/config/scheduler-k3s/$scope"
sudo mkdir -p "$dir"
echo -n "$value" | sudo tee "$dir/trigger-auth.${trigger}.${key}" >/dev/null
}
scheduler_k3s_clear_trigger_auth() {
local scope="$1"
local trigger="$2"
sudo rm -f "/var/lib/dokku/config/scheduler-k3s/$scope/trigger-auth.${trigger}."* 2>/dev/null || true
}
setup() {
global_setup
dokku apps:create $TEST_APP >/dev/null 2>/dev/null || true
dokku apps:create ${TEST_APP}-2 >/dev/null 2>/dev/null || true
}
teardown() {
dokku scheduler-k3s:autoscaling-auth:set $TEST_APP datadog >/dev/null 2>/dev/null || true
dokku scheduler-k3s:autoscaling-auth:set $TEST_APP memory >/dev/null 2>/dev/null || true
dokku scheduler-k3s:autoscaling-auth:set ${TEST_APP}-2 datadog >/dev/null 2>/dev/null || true
scheduler_k3s_clear_trigger_auth "--global" "datadog"
dokku --force apps:destroy $TEST_APP >/dev/null 2>/dev/null || true
dokku --force apps:destroy ${TEST_APP}-2 >/dev/null 2>/dev/null || true
global_teardown
}
@test "(scheduler-k3s:autoscaling-auth:report) no-arg loops all apps" {
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set $TEST_APP datadog --metadata apiKey=secret-1"
assert_success
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set ${TEST_APP}-2 datadog --metadata apiKey=secret-2"
assert_success
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report"
assert_success
assert_output_contains "$TEST_APP autoscaling-auth information"
assert_output_contains "${TEST_APP}-2 autoscaling-auth information"
assert_output_contains "Datadog:" 2
}
@test "(scheduler-k3s:autoscaling-auth:report) lists metadata in json and clears after unset" {
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set $TEST_APP datadog --metadata apiKey=secret-1 --metadata appKey=secret-2"
assert_success
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --format json | jq -r '.\"datadog.apiKey\"'"
assert_success
assert_output "secret-1"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --format json | jq -r '.\"datadog.appKey\"'"
assert_success
assert_output "secret-2"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --scheduler-k3s-autoscaling-auth.datadog.apiKey"
assert_success
assert_output "*******"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP"
assert_success
assert_output_contains "Datadog:"
assert_output_not_contains "Datadog apiKey:"
assert_output_not_contains "secret-1"
assert_output_not_contains "secret-2"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --include-metadata"
assert_success
assert_output_contains "Datadog apiKey:"
assert_output_contains "secret-1"
assert_output_contains "secret-2"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set $TEST_APP datadog"
assert_success
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --format json"
assert_success
assert_output "{}"
}
@test "(scheduler-k3s:autoscaling-auth:report) stdout includes metadata values with --include-metadata" {
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set $TEST_APP datadog --metadata apiKey=super-secret-value"
assert_success
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP"
assert_success
assert_output_contains "Datadog:"
assert_output_contains "configured"
assert_output_not_contains "Datadog apiKey:"
assert_output_not_contains "super-secret-value"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --include-metadata"
assert_success
assert_output_contains "Datadog apiKey:"
assert_output_contains "super-secret-value"
}
@test "(scheduler-k3s:autoscaling-auth:report) reports multiple triggers in json" {
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set $TEST_APP datadog --metadata apiKey=secret-1"
assert_success
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set $TEST_APP memory --metadata some-key=some-value"
assert_success
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --format json | jq -r 'keys | sort | join(\",\")'"
assert_success
assert_output "datadog.apiKey,memory.some-key"
}
@test "(scheduler-k3s:autoscaling-auth:report) supports --global scope" {
scheduler_k3s_seed_trigger_auth "--global" "datadog" "apiKey" "global-secret"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report --global --format json | jq -r '.\"datadog.apiKey\"'"
assert_success
assert_output "global-secret"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report --global --include-metadata"
assert_success
assert_output_contains "--global autoscaling-auth information"
assert_output_contains "Datadog:"
assert_output_contains "Datadog apiKey:"
assert_output_contains "global-secret"
}
@test "(scheduler-k3s:autoscaling-auth:report) returns empty json for unconfigured app" {
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --format json"
assert_success
assert_output "{}"
}
@test "(scheduler-k3s:autoscaling-auth:report) rejects invalid format and info-flag combinations" {
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --format yaml"
assert_failure
assert_output_contains "Invalid format"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:set $TEST_APP datadog --metadata apiKey=secret-1"
assert_success
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --format json --scheduler-k3s-autoscaling-auth.datadog.apiKey"
assert_failure
assert_output_contains "--format flag cannot be specified when specifying an info flag"
run /bin/bash -c "dokku scheduler-k3s:autoscaling-auth:report $TEST_APP --scheduler-k3s-autoscaling-auth.datadog.missing"
assert_failure
assert_output_contains "Invalid flag passed"
}

View File

@@ -0,0 +1,207 @@
#!/usr/bin/env bats
load test_helper
TEST_APP="rdmtestapp"
setup() {
uninstall_k3s || true
global_setup
dokku nginx:stop
export KUBECONFIG="/etc/rancher/k3s/k3s.yaml"
}
teardown() {
dokku scheduler-k3s:set --global cert-issuer-name >/dev/null 2>/dev/null || true
global_teardown
dokku nginx:start
uninstall_k3s || true
}
@test "(scheduler-k3s:certs) app-level letsencrypt email renders a per-app namespaced Issuer" {
if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then
skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN"
fi
INGRESS_CLASS=nginx install_k3s
run /bin/bash -c "dokku apps:create $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-k3s:set $TEST_APP letsencrypt-server staging"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-k3s:set $TEST_APP letsencrypt-email-stag app@dokku.me"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku domains:set $TEST_APP $TEST_APP.dokku.me"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python "dokku@$DOKKU_DOMAIN:$TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "sleep 30"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "kubectl get certificate ${TEST_APP}-web -n default -o jsonpath='{.spec.issuerRef.kind}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "Issuer"
run /bin/bash -c "kubectl get certificate ${TEST_APP}-web -n default -o jsonpath='{.spec.issuerRef.name}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "${TEST_APP}-letsencrypt-stag"
run /bin/bash -c "kubectl get issuer ${TEST_APP}-letsencrypt-stag -n default -o jsonpath='{.spec.acme.email}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "app@dokku.me"
}
@test "(scheduler-k3s:certs) a manually managed cert issuer issues the app certificate" {
if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then
skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN"
fi
INGRESS_CLASS=nginx install_k3s
run /bin/bash -c "dokku apps:create $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku domains:set $TEST_APP $TEST_APP.dokku.me"
echo "output: $output"
echo "status: $status"
assert_success
# no letsencrypt email is ever set, so tls is enabled purely by cert-issuer-name
run /bin/bash -c "dokku scheduler-k3s:set $TEST_APP cert-issuer-name dokku-test-selfsigned"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-k3s:preview $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
assert_output_contains "ClusterIssuer dokku-test-selfsigned not found"
create_selfsigned_cluster_issuer
run deploy_app python "dokku@$DOKKU_DOMAIN:$TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "kubectl get certificate ${TEST_APP}-web -n default -o jsonpath='{.spec.issuerRef.kind}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "ClusterIssuer"
run /bin/bash -c "kubectl get certificate ${TEST_APP}-web -n default -o jsonpath='{.spec.issuerRef.name}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "dokku-test-selfsigned"
# a selfSigned issuer issues immediately, so the secret proves end-to-end issuance
run /bin/bash -c "kubectl wait --for=condition=Ready certificate/${TEST_APP}-web -n default --timeout=120s"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "kubectl get secret tls-${TEST_APP}-web -n default -o jsonpath='{.type}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "kubernetes.io/tls"
run /bin/bash -c "kubectl get ingress ${TEST_APP}-web-${TEST_APP}-dokku-me -n default -o jsonpath='{.spec.tls[0].secretName}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output "tls-${TEST_APP}-web"
}
@test "(scheduler-k3s:certs) letsencrypt-server false disables a global cert issuer" {
if [[ -z "$DOCKERHUB_USERNAME" ]] || [[ -z "$DOCKERHUB_TOKEN" ]]; then
skip "skipping due to missing docker.io credentials DOCKERHUB_USERNAME:DOCKERHUB_TOKEN"
fi
INGRESS_CLASS=nginx install_k3s
create_selfsigned_cluster_issuer
run /bin/bash -c "dokku scheduler-k3s:set --global cert-issuer-name dokku-test-selfsigned"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku apps:create $TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku scheduler-k3s:set $TEST_APP letsencrypt-server false"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "dokku domains:set $TEST_APP $TEST_APP.dokku.me"
echo "output: $output"
echo "status: $status"
assert_success
run deploy_app python "dokku@$DOKKU_DOMAIN:$TEST_APP"
echo "output: $output"
echo "status: $status"
assert_success
run /bin/bash -c "kubectl get certificate ${TEST_APP}-web -n default"
echo "output: $output"
echo "status: $status"
assert_failure
run /bin/bash -c "kubectl get ingress ${TEST_APP}-web-${TEST_APP}-dokku-me -n default -o jsonpath='{.spec.tls}'"
echo "output: $output"
echo "status: $status"
assert_success
assert_output ""
}
create_selfsigned_cluster_issuer() {
declare desc="creates a selfSigned ClusterIssuer that issues certificates without acme"
local manifest="${BATS_TMPDIR:-/tmp}/dokku-test-selfsigned.yaml"
cat >"$manifest" <<'EOF'
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: dokku-test-selfsigned
spec:
selfSigned: {}
EOF
run /bin/bash -c "kubectl apply -f $manifest"
echo "output: $output"
echo "status: $status"
assert_success
}

Some files were not shown because too many files have changed in this diff Show More