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) } } }