238 lines
5.8 KiB
Go
238 lines
5.8 KiB
Go
package stack
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// full — output lengkap seperti tampil ke user (sudah termasuk komentar warning).
|
|
func full(r ConvertResult) string { return r.Output }
|
|
|
|
func checkGolden(t *testing.T, name, cmd, want string) {
|
|
t.Helper()
|
|
got, err := Convert(cmd)
|
|
if err != nil {
|
|
t.Fatalf("%s: Convert error: %v", name, err)
|
|
}
|
|
g := full(got)
|
|
if strings.TrimSpace(g) != strings.TrimSpace(want) {
|
|
t.Fatalf("%s: YAML beda.\n--- dapat ---\n%s\n--- mau ---\n%s", name, g, want)
|
|
}
|
|
}
|
|
|
|
func TestConvertVectors(t *testing.T) {
|
|
checkGolden(t, "V1 basic", "docker run -p 80:80 foobar/baz:latest", `
|
|
services:
|
|
baz:
|
|
ports:
|
|
- 80:80
|
|
image: foobar/baz:latest`)
|
|
|
|
checkGolden(t, "V2 flags umum",
|
|
"docker run -d --name web -p 8080:80 -v ./html:/usr/share/nginx/html:ro -e TZ=Asia/Jakarta --restart unless-stopped nginx:latest", `
|
|
services:
|
|
nginx:
|
|
container_name: web
|
|
ports:
|
|
- 8080:80
|
|
volumes:
|
|
- ./html:/usr/share/nginx/html:ro
|
|
environment:
|
|
- TZ=Asia/Jakarta
|
|
restart: unless-stopped
|
|
image: nginx:latest`)
|
|
|
|
checkGolden(t, "V3 multiline + $()", `docker run \
|
|
-d \
|
|
--name tor-relay \
|
|
-e TZ=Europe/London \
|
|
-e PUID=$(id -u) \
|
|
-v $(pwd)/tor/data:/data:Z \
|
|
-p 9001:9001 \
|
|
--restart always \
|
|
ilshidur/tor-relay`, `
|
|
services:
|
|
tor-relay:
|
|
container_name: tor-relay
|
|
environment:
|
|
- TZ=Europe/London
|
|
- PUID=$(id -u)
|
|
volumes:
|
|
- $(pwd)/tor/data:/data:Z
|
|
ports:
|
|
- 9001:9001
|
|
restart: always
|
|
image: ilshidur/tor-relay`)
|
|
|
|
checkGolden(t, "V4 kutip nilai", `docker run --name="foobar" -e GREETING="hello world" nginx`, `
|
|
services:
|
|
nginx:
|
|
container_name: foobar
|
|
environment:
|
|
- GREETING=hello world
|
|
image: nginx`)
|
|
|
|
checkGolden(t, "V5 -p nempel", "docker run -p8080:80 nginx", `
|
|
services:
|
|
nginx:
|
|
ports:
|
|
- 8080:80
|
|
image: nginx`)
|
|
|
|
checkGolden(t, "V6 flag tak dikenal", "docker run -d -z machin --unknown-long=truc nginx", `
|
|
# ignored options for 'nginx'
|
|
# -z=machin
|
|
# --unknown-long=truc
|
|
services:
|
|
nginx:
|
|
image: nginx`)
|
|
|
|
checkGolden(t, "V7 network bernama", "docker run --network appnet nginx", `
|
|
# named network 'appnet' is marked as "external" (used by service 'nginx'), so either remove "external" from network definition or it needs to be created using: docker network create -d bridge appnet
|
|
services:
|
|
nginx:
|
|
networks:
|
|
- appnet
|
|
image: nginx
|
|
networks:
|
|
appnet:
|
|
external: true
|
|
name: appnet`)
|
|
|
|
checkGolden(t, "V8 network host", "docker run --network host -p 8080:80 nginx", `
|
|
services:
|
|
nginx:
|
|
network_mode: host
|
|
image: nginx`)
|
|
|
|
checkGolden(t, "V9 named volume", "docker run -v vol:/data nginx", `
|
|
services:
|
|
nginx:
|
|
volumes:
|
|
- vol:/data
|
|
image: nginx
|
|
volumes:
|
|
vol: {}`)
|
|
|
|
checkGolden(t, "V10 mount long syntax",
|
|
"docker run --mount type=bind,source=/host,target=/container,readonly nginx", `
|
|
services:
|
|
nginx:
|
|
volumes:
|
|
- type: bind
|
|
source: /host
|
|
target: /container
|
|
readonly: true
|
|
image: nginx`)
|
|
|
|
checkGolden(t, "V11 healthcheck",
|
|
`docker run --health-cmd "curl -f http://localhost/" --health-interval 30s --health-retries 3 --health-timeout 5s --health-start-period 10s nginx`, `
|
|
services:
|
|
nginx:
|
|
healthcheck:
|
|
test: curl -f http://localhost/
|
|
interval: 30s
|
|
retries: 3
|
|
timeout: 5s
|
|
start_period: 10s
|
|
image: nginx`)
|
|
|
|
checkGolden(t, "V12 log opt", "docker run --log-opt max-size=1g --log-opt max-file=3 --restart always nginx", `
|
|
services:
|
|
nginx:
|
|
logging:
|
|
options:
|
|
max-size: 1g
|
|
max-file: 3
|
|
restart: always
|
|
image: nginx`)
|
|
|
|
checkGolden(t, "V13 limits", "docker run --memory 512m --cpus 1.5 --pids-limit 200 nginx", `
|
|
services:
|
|
nginx:
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
memory: 512m
|
|
cpus: 1.5
|
|
pids: 200
|
|
image: nginx`)
|
|
|
|
checkGolden(t, "V14 gpus", "docker run --gpus all nvidia/cuda:12.0-base", `
|
|
services:
|
|
cuda:
|
|
deploy:
|
|
resources:
|
|
reservations:
|
|
devices:
|
|
- driver: nvidia
|
|
count: all
|
|
capabilities:
|
|
- gpu
|
|
image: nvidia/cuda:12.0-base`)
|
|
|
|
checkGolden(t, "V15 command setelah image", "docker run nginx:alpine nginx -g daemon off;", `
|
|
services:
|
|
nginx:
|
|
image: nginx:alpine
|
|
command: nginx -g daemon off`)
|
|
|
|
// V16 (multi perintah) menyusul — dicatat di docs/rea/composerize.md.
|
|
|
|
checkGolden(t, "V18 env-file + env", "docker run --env-file .env -e DEBUG=1 app/api:1.2", `
|
|
services:
|
|
api:
|
|
env_file:
|
|
- .env
|
|
environment:
|
|
- DEBUG=1
|
|
image: app/api:1.2`)
|
|
|
|
checkGolden(t, "V19 ulimit", "docker run --ulimit nofile=1024:2048 --ulimit nproc=65535 nginx", `
|
|
services:
|
|
nginx:
|
|
ulimits:
|
|
nofile:
|
|
soft: 1024
|
|
hard: 2048
|
|
nproc: 65535
|
|
image: nginx`)
|
|
|
|
checkGolden(t, "V20 ip + network", "docker run --network appnet --ip 10.0.0.5 nginx", `
|
|
# named network 'appnet' is marked as "external" (used by service 'nginx'), so either remove "external" from network definition or it needs to be created using: docker network create -d bridge appnet
|
|
services:
|
|
nginx:
|
|
networks:
|
|
appnet:
|
|
ipv4_address: 10.0.0.5
|
|
image: nginx
|
|
networks:
|
|
appnet:
|
|
external: true
|
|
name: appnet`)
|
|
}
|
|
|
|
func TestConvertErrors(t *testing.T) {
|
|
if _, err := Convert("foo bar"); err == nil {
|
|
t.Fatal("bukan docker run harus error")
|
|
}
|
|
if _, err := Convert("docker run -d"); err == nil {
|
|
t.Fatal("tanpa image harus error")
|
|
}
|
|
}
|
|
|
|
func TestServiceNameFromImage(t *testing.T) {
|
|
cases := map[string]string{
|
|
"nginx": "nginx",
|
|
"nginx:latest": "nginx",
|
|
"foobar/baz:latest": "baz",
|
|
"registry.local:5000/app:v1": "app",
|
|
"ghcr.io/org/app": "app",
|
|
}
|
|
for in, want := range cases {
|
|
if got := serviceNameFromImage(in); got != want {
|
|
t.Errorf("%s → %s, mau %s", in, got, want)
|
|
}
|
|
}
|
|
}
|