#!/usr/bin/env bash
#
# O roteiro de publicar na producao monta, leva, troca e volta como o
# procedimento manda -- e quanto tempo levam a entrega e a volta? (D37)
#
#     bash scripts/ensaiar-publicar-producao.sh
#     bash scripts/ensaiar-publicar-producao.sh <copia do scripts/publicar-producao.sh>
#     IMAGEM_DO_ENSAIO=<imagem Linux com bash, php, git e coreutils> bash scripts/ensaiar-publicar-producao.sh
#
# Sai com 0 quando todo caso abaixo da a saida esperada, e diz os dois tempos; 1
# quando algum nao da, e diz qual; 2 quando nao consegue medir (sem docker, a
# imagem fora do cache -- o ensaio nao baixa nada --, sem o vendor/ daqui, ou o
# conteiner nao respondeu). O argumento aponta o ensaio para uma COPIA do
# roteiro -- e como se falsifica sem tocar no de verdade.
#
# ---------------------------------------------------------------------------
# POR QUE ISTO EXISTE (08/11/2026, a fatia 129; o D37)
#
# A producao nao tem git, e a entrega la e copia de arquivo. O procedimento da
# etapa 1 (o item 9 de "O que falta fazer antes da janela") pede o roteiro de
# publicar e o ensaio dele, que da "o tempo da entrega e o da volta a liberacao
# anterior" -- e a hora-limite de cada entrega sai deles (01:10 menos a volta,
# a sua 206 (a)). O roteiro foi escrito sem rodar em servidor nenhum: este
# ensaio e a unica prova de que ele faz o que diz.
#
# ---------------------------------------------------------------------------
# COMO
#
# 1. NA SUA MAQUINA, o `montar` do roteiro de verdade sobre o HEAD, com um
#    `docker` de mentira no comeco do PATH: o composer copia o vendor/ daqui
#    (o tamanho de verdade, sem rede) e a build escreve um dist com o
#    src="/novo/assets/". O <sobre> e o eaf1fca5, a importacao -- o que a
#    producao roda hoje. Um segundo pacote, sobre o HEAD, para a entrega sobre
#    uma entrega.
# 2. NUM CONTEINER DESCARTAVEL (docker run --rm, sem rede, da imagem do app
#    daqui), um /var/www/franquiabv.com.br de mentira: a arvore do eaf1fca5,
#    com pastas de upload e um data/ inventados (ENSAIO_UPLOAD_MB, padrao 120
#    MB em 600 arquivos; ENSAIO_DATA_MB, padrao 40), fotos no avatar e um
#    app.json mudado pela tela. O nginx, o systemctl, o crontab, o mysql, o
#    pgrep, o curl e o relogio (`date +%H%M`) sao dubles; o php e o de verdade,
#    menos o verificar-local-php.php e o conexao-do-local-php.php, que
#    respondem pelo local.php inventado. Os casos:
#
#    levar as 23:50, e as 00:02           recusa (a 206 (a): as duas metades da
#                                         guarda), nada ao lado
#    levar com o .sha256 errado           recusa
#    levar as 00:10                       a release ao lado, o local.php 640
#    entregar e trocar sem                recusa (o item 10 nao existe), nada mexido
#      MANUTENCAO_ARQUIVO
#    entregar com o nginx sem ela         recusa
#    entregar e trocar com o crontab      recusa; e a linha da forma nova (o
#      ativo                              Bearer), no crontab e no /etc/cron.d,
#                                         sai sem o token
#    entregar sem o crontab guardado,     recusa (o guardado nao tem padrao, e e
#      sem CRONTAB_GUARDADO, e com o      o desta noite)
#      de duas noites atras
#    entregar e trocar com conexao da     recusa depois da espera; e, com o codigo
#      aplicacao                          antigo no ar, sem USUARIO_DB_NO_AR, ou
#                                         com uma conexao dele (a leitura 10)
#    entregar as 01:00, 5 + 10 min        recusa (nao cabe ate as 01:10); trocar
#                                         as 00:02 recusa
#    entregar sem PHP_FPM_SERVICO         recusa antes de mexer
#    entregar e trocar com a producao     recusa e lista o arquivo; o conferir
#      divergente                         com DIFERENCAS_ACEITAS passa
#    entregar, e a pasta que nao muda     para nas pastas; o voltar dali recusa sem
#                                         a manutencao, com o cron e com conexao,
#                                         e depois as devolve
#    entregar (CRONOMETRADO)              a release no lugar, as pastas, o avatar
#                                         e o app.json de la, o data/ copiado, as
#                                         gravaveis do pool, a antiga inteira ao
#                                         lado, a tela nova, o reload, o 401
#    voltar ao codigo antigo, recusado    sem a manutencao, com o cron ativo, com
#                                         conexao, sem o bloqueio do migrar-senhas
#                                         no nginx -T, com o crontab de uma entrega,
#                                         e com uma volta parada no meio
#    voltar (CRONOMETRADO)                a arvore antiga, as pastas, o avatar; a
#                                         nova em public_html.novo-<data> (o nome
#                                         de "A volta"); SEM recarregar o php-fpm,
#                                         e o devolver-nomes pelo caminho dela
#    a segunda, sobre a primeira, pelo    recusa com o crontab da janela e com
#    trocar (o da janela)                 conexao do local.php no ar; depois
#                                         public_html.anterior-<hora>, sem
#                                         recarregar o php-fpm; e o voltar (entre
#                                         duas releases) recarrega e devolve
#                                         tambem a tela nova
#
# O QUE ELE NAO AFIRMA: nada da producao. O disco, o tamanho das pastas (340
# MB em 1.146 arquivos, pela operacao-atual.md), o nginx, o php-fpm e o MySQL de
# la sao outros; os tempos daqui sao os de um conteiner no Mac, e o ensaio da
# sua 199 (a), no BVIP, e o que fixa a hora-limite. O `montar` com o composer e
# o npm de verdade pede rede, e nao roda aqui.

set -u

cd "$(dirname "$0")/.." || exit 2
RAIZ=$(pwd)

PUBLICAR="${1:-scripts/publicar-producao.sh}"
case "$PUBLICAR" in /*) ;; *) PUBLICAR="$RAIZ/$PUBLICAR" ;; esac
[ -r "$PUBLICAR" ] || { echo "NAO CONSEGUI MEDIR: nao li $PUBLICAR" >&2; exit 2; }
IMAGEM="${IMAGEM_DO_ENSAIO:-franquiabv-app:latest}"
IMPORTACAO=eaf1fca5

command -v docker >/dev/null 2>&1 || { echo "NAO CONSEGUI MEDIR: sem o docker" >&2; exit 2; }
docker image inspect "$IMAGEM" >/dev/null 2>&1 \
    || { echo "NAO CONSEGUI MEDIR: a imagem $IMAGEM nao esta no cache (o ensaio nao baixa nada)" >&2; exit 2; }
[ -f vendor/autoload.php ] || { echo "NAO CONSEGUI MEDIR: sem o vendor/ daqui (o composer de mentira o copia)" >&2; exit 2; }
git rev-parse --verify --quiet "$IMPORTACAO^{commit}" >/dev/null || { echo "NAO CONSEGUI MEDIR: sem o commit $IMPORTACAO" >&2; exit 2; }

T=$(mktemp -d 2>/dev/null) || { echo "NAO CONSEGUI MEDIR: mktemp -d falhou" >&2; exit 2; }
trap 'rm -rf "$T"' EXIT INT TERM

# ---------------------------------------------------------------------------
# 1. O montar, com o docker de mentira.

mkdir -p "$T/bin-maquina" "$T/releases" "$T/ensaio"
cat > "$T/bin-maquina/docker" <<'FIM'
#!/usr/bin/env bash
# O docker de mentira do montar: o build nao faz nada; o composer copia o
# vendor/ daqui; a build escreve o dist.
[ "${1:-}" = build ] && exit 0
[ "${1:-}" = run ] || { echo "docker de mentira: nao sei '$*'" >&2; exit 99; }
app=""
prev=""
for a in "$@"; do
    [ "$prev" = -v ] && case "$a" in *:/app) app="${a%:/app}" ;; esac
    prev="$a"
done
[ -n "$app" ] || { echo "docker de mentira: sem o -v ...:/app" >&2; exit 99; }
case "$*" in
    *"composer install"*) cp -R "$ENSAIO_VENDOR" "$app/vendor" ;;
    *"npm run build -- --base=/novo/"*)
        mkdir -p "$app/dist/assets"
        printf '<!doctype html><script type="module" src="/novo/assets/index-ensaio.js"></script>\n' > "$app/dist/index.html"
        printf 'console.log("ensaio")\n' > "$app/dist/assets/index-ensaio.js" ;;
    *) echo "docker de mentira: nao sei '$*'" >&2; exit 99 ;;
esac
FIM
chmod +x "$T/bin-maquina/docker"

montar() {
    PATH="$T/bin-maquina:$PATH" RELEASES="$T/releases" ENSAIO_VENDOR="$RAIZ/vendor" \
        bash "$PUBLICAR" montar "$1" "$2" > "$T/montar-$3.txt" 2>&1
}
HEAD=$(git rev-parse HEAD)
CURTO=$(git rev-parse --short HEAD)
montar HEAD "$IMPORTACAO" 1 || { echo "NAO CONSEGUI MEDIR: o montar sobre a importacao falhou: $(grep -m1 ABORTADO "$T/montar-1.txt")" >&2; exit 2; }
mv "$T/releases/release-$CURTO.tar.gz" "$T/ensaio/pacote1.tar.gz"
( cd "$T/ensaio" && sed "s/release-$CURTO.tar.gz/pacote1.tar.gz/" "$T/releases/release-$CURTO.tar.gz.sha256" > pacote1.tar.gz.sha256 )
montar HEAD HEAD 2 || { echo "NAO CONSEGUI MEDIR: o montar sobre o HEAD falhou: $(grep -m1 ABORTADO "$T/montar-2.txt")" >&2; exit 2; }
mv "$T/releases/release-$CURTO.tar.gz" "$T/ensaio/pacote2.tar.gz"
( cd "$T/ensaio" && sed "s/release-$CURTO.tar.gz/pacote2.tar.gz/" "$T/releases/release-$CURTO.tar.gz.sha256" > pacote2.tar.gz.sha256 )

# O que o montar nao pode levar, e o que tem de levar.
falhas_maquina=""
LISTA=$(tar -tzf "$T/ensaio/pacote1.tar.gz")
for f in arvore/.publicar/release arvore/.publicar/sobre arvore/.publicar/impressao-esperada.txt arvore/.publicar/novo/index.html arvore/vendor/autoload.php arvore/scripts/comparar-com-producao.sh; do
    grep -qx "$f" <<<"$LISTA" || falhas_maquina="$falhas_maquina\n  - o pacote nao traz $f"
done
grep -qE '^arvore/(config/autoload/local\.php|\.env)$|^arvore/ensaios/|base-teste[^/]*\.sql\.gz$|/\._' <<<"$LISTA" && falhas_maquina="$falhas_maquina\n  - o pacote leva o que nao pode"
[ "$(tar -xzf "$T/ensaio/pacote1.tar.gz" -O arvore/.publicar/release)" = "$HEAD" ] || falhas_maquina="$falhas_maquina\n  - o .publicar/release nao e o HEAD"
[ "$(tar -xzf "$T/ensaio/pacote1.tar.gz" -O arvore/.publicar/sobre)" = "$(git rev-parse "$IMPORTACAO")" ] || falhas_maquina="$falhas_maquina\n  - o .publicar/sobre nao e a importacao"

# O sobre da producao: a arvore da importacao.
git archive "$IMPORTACAO" > "$T/ensaio/importacao.tar"
cp "$PUBLICAR" "$T/ensaio/publicar-producao.sh"
printf '%s\n' "$HEAD" > "$T/ensaio/head"

# ---------------------------------------------------------------------------
# 2. No conteiner.

DENTRO=$(cat <<'FIM'
set -u
E=/ensaio
falhas=0; casos=0
falhou() { echo "  - $1"; falhas=$((falhas + 1)); }
caso() { casos=$((casos + 1)); }
SITE=/var/www/franquiabv.com.br
A=$SITE/public_html
N=$SITE/public_html.novo
EST=$SITE/.publicar-producao
FR=$SITE/front
HEAD=$(cat $E/head)
REG=/tmp/registro.txt
: > $REG

# Os dubles.
mkdir -p /tmp/bin
for d in nginx systemctl crontab mysql pgrep curl; do
cat > /tmp/bin/$d <<'DUB'
#!/usr/bin/env bash
n=$(basename "$0")
printf '%s %s\n' "$n" "$*" >> /tmp/registro.txt
case "$n" in
    nginx) if [ "${1:-}" = -T ]; then
               [ "${ENSAIO_MANUTENCAO_CARREGADA:-sim}" != sim ] || printf '# configuration file /etc/nginx/manutencao.conf:\nlocation / { return 503; }\n'
               [ "${ENSAIO_BLOQUEIO:-sim}" != sim ] || printf 'location = /index.php/autenticacao/migrar-senhas { return 404; }\n'
           fi; exit 0 ;;
    systemctl) exit 0 ;;
    crontab) case "${ENSAIO_CRON_ATIVO:-}" in
                 '') echo "no crontab for root" >&2; exit 1 ;;
                 bearer) printf '*/5 * * * * curl -fsS -m 60 "https://franquiabv.com.br/api/cronjobs/npsNotificacoes" -H "Authorization: Bearer %s"\n' "$SEGREDO_DO_ENSAIO" ;;
                 *) echo "*/5 * * * * curl -s https://franquiabv.com.br/api/cronjobs/npsNotificacoes" ;;
             esac; exit 0 ;;
    # O MySQL conta por usuario: com ENSAIO_CONEXAO_DE, 1 se a lista do IN o traz.
    mysql) if [ -n "${ENSAIO_CONEXAO_DE:-}" ]; then case "$*" in *"'$ENSAIO_CONEXAO_DE'"*) echo 1; exit 0 ;; esac; fi
           echo "${ENSAIO_CONEXOES:-0}"; exit 0 ;;
    pgrep) exit 1 ;;
    curl) case "$*" in *npsContabilizar*) printf '%s' "${ENSAIO_NPS:-401}" ;; */novo/*) printf '<script type="module" src="/novo/assets/index-ensaio.js"></script>' ;; esac; exit 0 ;;
esac
DUB
chmod +x /tmp/bin/$d
done
cat > /tmp/bin/php <<'DUB'
#!/usr/bin/env bash
# Um usuario para o local.php da release ao lado, outro para o da arvore no ar.
case "$*" in
    *conexao-do-local-php.php*public_html.novo/*) echo 'localhost|franquia_producao|franquiabv_app'; exit 0 ;;
    *conexao-do-local-php.php*) echo 'localhost|franquia_producao|franquiabv_no_ar'; exit 0 ;;
    *verificar-local-php.php*) echo 'Todas as chaves preenchidas (duble do ensaio).'; exit 0 ;;
esac
exec /usr/local/bin/php "$@"
DUB
cat > /tmp/bin/date <<'DUB'
#!/usr/bin/env bash
if [ "${1:-}" = "+%H%M" ] && [ -n "${ENSAIO_HORA:-}" ]; then echo "$ENSAIO_HORA"; exit 0; fi
exec /bin/date "$@"
DUB
chmod +x /tmp/bin/php /tmp/bin/date
export PATH="/tmp/bin:$PATH"

# A producao de mentira: a arvore da importacao, com o que o git nao tem.
mkdir -p $A /etc/nginx
tar -x -C $A -f $E/importacao.tar
UP_MB=${ENSAIO_UPLOAD_MB:-120}; DATA_MB=${ENSAIO_DATA_MB:-40}
for p in arquivos contratos banners assistentes vip-class visagismo; do
    mkdir -p $A/public/$p
    for i in $(seq 1 100); do head -c $((UP_MB * 1024 * 1024 / 600)) /dev/urandom > $A/public/$p/f$i.bin; done
done
mkdir -p $A/data/cache/relatorios $A/data/logs
head -c $((DATA_MB * 1024 * 1024)) /dev/urandom > $A/data/cache/relatorios/atendimentos.cache
echo 'log de la' > $A/data/logs/log_scripts.txt
for i in $(seq 1 50); do head -c 20000 /dev/urandom > $A/public/layout/img/avatar/foto$i.jpg; done
printf '[{"push":"ativo","versao_major":"2","versao_minor":"0","versao_patch":"9"}]' > $A/public/app.json
chown -R www-data:www-data $A/public/arquivos $A/data
printf '<?php\nreturn [];\n' > /tmp/local.php-da-release
echo '*/5 * * * * curl -s https://franquiabv.com.br/api/cronjobs/npsNotificacoes' > /root/crontab-antes-do-corte.txt
# O desta noite numa entrega, e o de duas noites atras (mais de 12 horas).
echo '*/5 * * * * curl -fsS "https://franquiabv.com.br/api/cronjobs/npsNotificacoes"' > /root/crontab-entrega.txt
cp /root/crontab-entrega.txt /root/crontab-velho.txt && touch -d '2 days ago' /root/crontab-velho.txt
echo 'location / { return 503; }' > /etc/nginx/manutencao.conf
contar() { find "$1" -type f 2>/dev/null | wc -l; }
UPLOADS=$(contar $A/public/arquivos)

P="bash $E/publicar-producao.sh"
# Um texto que faz as vezes do token das rotinas: nao pode aparecer em saida nenhuma.
export SEGREDO_DO_ENSAIO="ensaio$(printf '%s' 0b5e7a1c9d)semvalor"
export CONFIRMAR=sim ENTREGA_MIN=5 VOLTA_MIN=5 FRONT_RAIZ=$FR POOL_USUARIO=www-data POOL_GRUPO=www-data PHP_FPM_SERVICO=php8.1-fpm
export MANUTENCAO_ARQUIVO=/etc/nginx/manutencao.conf ESPERA_MAX_S=0 ENSAIO_HORA=0010
export CRONTAB_GUARDADO=/root/crontab-antes-do-corte.txt USUARIO_DB_NO_AR=franquiabv_antigo

# recusa <rotulo> <frase da saida> <comando...>: sai 1, diz a frase, e a arvore no ar nao mudou.
recusa() {
    local rotulo="$1" frase="$2" antes depois
    shift 2
    caso
    antes=$(ls $A/public | md5sum)
    "$@" > /tmp/saida.txt 2>&1
    local c=$?
    depois=$(ls $A/public | md5sum)
    [ "$c" = 1 ] || falhou "$rotulo: saiu $c, e devia sair 1 ($(tail -n 1 /tmp/saida.txt))"
    grep -qF -- "$frase" /tmp/saida.txt || falhou "$rotulo: a saida nao diz '$frase' ($(grep -m1 ABORTADO /tmp/saida.txt))"
    [ "$antes" = "$depois" ] || falhou "$rotulo: a arvore no ar mudou"
}

recusa 'levar as 23:50' 'depois das 00:05' env ENSAIO_HORA=2350 $P levar $E/pacote1.tar.gz
[ ! -e $N ] || falhou "levar as 23:50: a release foi ao lado"
# A OUTRA METADE DA GUARDA: as 00:02 cabe antes do limite, e e antes das 00:05.
recusa 'levar as 00:02' 'depois das 00:05' env ENSAIO_HORA=0002 $P levar $E/pacote1.tar.gz
[ ! -e $N ] || falhou "levar as 00:02: a release foi ao lado"
cp $E/pacote1.tar.gz /tmp/quebrado.tar.gz; echo "0000000000000000000000000000000000000000000000000000000000000000  quebrado.tar.gz" > /tmp/quebrado.tar.gz.sha256
recusa 'levar com o sha256 errado' 'a cópia veio quebrada' $P levar /tmp/quebrado.tar.gz
caso
tl0=$(date +%s%N)
LOCAL_PHP=/tmp/local.php-da-release $P levar $E/pacote1.tar.gz > /tmp/saida.txt 2>&1 || falhou "levar as 00:10: saiu $? ($(grep -m1 ABORTADO /tmp/saida.txt))"
tl1=$(date +%s%N)
[ "$(cat $N/.publicar/release 2>/dev/null)" = "$HEAD" ] || falhou "levar: a release ao lado nao e o HEAD"
[ "$(stat -c '%U:%G %a' $N/config/autoload/local.php 2>/dev/null)" = "root:www-data 640" ] || falhou "levar: o local.php nao ficou root:www-data 640 ($(stat -c '%U:%G %a' $N/config/autoload/local.php 2>/dev/null))"
[ "$(stat -c %U $N/module 2>/dev/null)" = root ] || falhou "levar: os arquivos da release nao sao do root"

recusa 'entregar sem MANUTENCAO_ARQUIVO' 'não existe ainda' env -u MANUTENCAO_ARQUIVO $P entregar
recusa 'entregar com o nginx sem a manutencao' 'não carrega /etc/nginx/manutencao.conf' env ENSAIO_MANUTENCAO_CARREGADA=nao $P entregar
recusa 'entregar com o crontab ativo' 'ainda tem linha ativa' env ENSAIO_CRON_ATIVO=sim $P entregar
recusa 'entregar sem o crontab guardado' 'não existe ou está vazio' env CRONTAB_GUARDADO=/root/nao-existe $P entregar
# O GUARDADO SEM PADRAO, E DESTA NOITE.
recusa 'entregar sem CRONTAB_GUARDADO' 'CRONTAB_GUARDADO: o arquivo' env -u CRONTAB_GUARDADO $P entregar
recusa 'entregar com o crontab de duas noites atras' 'mais de 12 horas' env CRONTAB_GUARDADO=/root/crontab-velho.txt $P entregar
recusa 'entregar com conexao da aplicacao' 'as rotinas em curso não terminaram' env ENSAIO_CONEXOES=1 $P entregar
# O CODIGO ANTIGO NO AR: o usuario dele, e nao so o do local.php da release (a leitura 10).
recusa 'entregar na etapa 1 sem USUARIO_DB_NO_AR' 'USUARIO_DB_NO_AR' env -u USUARIO_DB_NO_AR $P entregar
recusa 'entregar com uma rotina do codigo antigo em curso' 'as rotinas em curso não terminaram' env ENSAIO_CONEXAO_DE=franquiabv_antigo $P entregar
recusa 'entregar as 01:00, 5 + 10 min' 'não cabe' env ENSAIO_HORA=0100 VOLTA_MIN=10 $P entregar
recusa 'entregar sem PHP_FPM_SERVICO' 'PHP_FPM_SERVICO' env -u PHP_FPM_SERVICO $P entregar
recusa 'entregar sem os numeros do ensaio' 'ENTREGA_MIN e VOLTA_MIN' env -u VOLTA_MIN $P entregar
# O trocar, o subcomando da janela, recusa como o entregar.
recusa 'trocar sem MANUTENCAO_ARQUIVO' 'não existe ainda' env -u MANUTENCAO_ARQUIVO $P trocar
recusa 'trocar com o crontab ativo' 'ainda tem linha ativa' env ENSAIO_CRON_ATIVO=sim $P trocar
recusa 'trocar com conexao da aplicacao' 'as rotinas em curso não terminaram' env ENSAIO_CONEXOES=1 $P trocar
recusa 'trocar as 00:02' 'depois das 00:05' env ENSAIO_HORA=0002 $P trocar
[ -e $N ] && [ ! -f $EST/passo ] || falhou "as recusas do trocar mexeram na release ao lado ou marcaram passo"
# A LINHA DA FORMA NOVA SAI SEM O TOKEN: no crontab do root e no /etc/cron.d.
recusa 'conferir com o crontab na forma nova' 'ainda tem linha ativa' env ENSAIO_CRON_ATIVO=bearer $P conferir
! grep -qF "$SEGREDO_DO_ENSAIO" /tmp/saida.txt || falhou "conferir com o crontab na forma nova: a saida mostrou o token"
grep -qF 'Authorization: <tirado>' /tmp/saida.txt || falhou "conferir com o crontab na forma nova: a saida nao mostra a linha com o token tirado"
mkdir -p /etc/cron.d
printf '*/10 * * * * root curl -fsS "https://franquiabv.com.br/api/cronjobs/npsContabilizar" -H "Authorization: Bearer %s"\n' "$SEGREDO_DO_ENSAIO" > /etc/cron.d/franquiabv-ensaio
recusa 'conferir com o /etc/cron.d na forma nova' 'o /etc/cron.d ainda chama o site' $P conferir
! grep -qF "$SEGREDO_DO_ENSAIO" /tmp/saida.txt || falhou "conferir com o /etc/cron.d na forma nova: a saida mostrou o token"
rm -f /etc/cron.d/franquiabv-ensaio
cp -p $A/module/ISBase/src/Module.php /tmp/Module.php
echo '// mudado direto no servidor' >> $A/module/ISBase/src/Module.php
recusa 'entregar com a producao divergente' 'diferente: module/ISBase/src/Module.php' $P entregar
recusa 'trocar com a producao divergente' 'diferente: module/ISBase/src/Module.php' $P trocar
caso
echo 'module/ISBase/src/Module.php' > /tmp/aceitas.txt
DIFERENCAS_ACEITAS=/tmp/aceitas.txt $P conferir > /tmp/saida.txt 2>&1 || falhou "conferir com a divergencia aceita: saiu $? ($(grep -m1 ABORTADO /tmp/saida.txt))"
cp -p /tmp/Module.php $A/module/ISBase/src/Module.php
caso
$P conferir > /tmp/saida.txt 2>&1 || falhou "conferir: saiu $? ($(grep -m1 ABORTADO /tmp/saida.txt))"

# A pasta que nao muda: um banners na release ao lado faz o mv -T parar no meio.
caso
mkdir -p $N/public/banners && echo x > $N/public/banners/estorvo
$P entregar > /tmp/saida.txt 2>&1 && falhou "entregar com a pasta que nao muda: passou"
grep -q 'pastas' $EST/passo 2>/dev/null || falhou "entregar com a pasta que nao muda: o passo nao ficou marcado em 'pastas'"
[ -e $A/public/arquivos ] && falhou "entregar com a pasta que nao muda: o arquivos nao tinha ido para a release (o caso nao reproduz o meio)"
# AS GUARDAS DO voltar NESTA METADE (a manutencao, o cron, as rotinas).
recusa 'voltar do meio das pastas sem a manutencao' 'não carrega /etc/nginx/manutencao.conf' env ENSAIO_MANUTENCAO_CARREGADA=nao $P voltar
recusa 'voltar do meio das pastas com o crontab ativo' 'ainda tem linha ativa' env ENSAIO_CRON_ATIVO=sim $P voltar
recusa 'voltar do meio das pastas com conexao' 'as rotinas em curso não terminaram' env ENSAIO_CONEXOES=1 $P voltar
[ ! -e $A/public/arquivos ] && grep -q 'pastas' $EST/passo 2>/dev/null || falhou "as recusas do voltar do meio das pastas mexeram nas pastas ou na marca"
$P voltar > /tmp/saida.txt 2>&1 || falhou "voltar do meio das pastas: saiu $? ($(grep -m1 ABORTADO /tmp/saida.txt))"
[ "$(contar $A/public/arquivos)" = "$UPLOADS" ] || falhou "voltar do meio das pastas: o arquivos nao voltou inteiro"
[ "$(contar $A/public/layout/img/avatar)" -ge 53 ] || falhou "voltar do meio das pastas: o avatar nao voltou"
grep -q "versao_patch\":\"9" $A/public/app.json || falhou "voltar do meio das pastas: o app.json de la foi trocado pelo do repositorio"
[ ! -f $EST/passo ] || falhou "voltar do meio das pastas: a marca ficou"
rm -rf $N/public/banners

# A ENTREGA, cronometrada.
caso
: > $REG
t0=$(date +%s%N)
$P entregar > /tmp/saida-entregar.txt 2>&1 || falhou "entregar: saiu $? ($(grep -m1 ABORTADO /tmp/saida-entregar.txt))"
t1=$(date +%s%N)
ANTIGO=$(ls -d $SITE/public_html.antigo-* 2>/dev/null | head -n 1)
[ "$(cat $A/.publicar/release 2>/dev/null)" = "$HEAD" ] || falhou "entregar: a release nao esta no lugar"
[ -n "$ANTIGO" ] && [ -f "$ANTIGO/module/ISBase/src/Module.php" ] || falhou "entregar: a arvore antiga nao ficou inteira em public_html.antigo-<data>"
[ ! -e "$ANTIGO/public/arquivos" ] || falhou "entregar: o arquivos ficou na antiga"
[ "$(contar $A/public/arquivos)" = "$UPLOADS" ] || falhou "entregar: o arquivos nao veio inteiro"
[ "$(stat -c %U $A/public/arquivos)" = www-data ] || falhou "entregar: o arquivos mudou de dono"
[ -f $A/public/layout/img/avatar/foto1.jpg ] || falhou "entregar: as fotos do avatar nao vieram"
ls -d $EST/avatar-da-release-* >/dev/null 2>&1 || falhou "entregar: o avatar da release nao ficou de lado"
grep -q '"2","versao_minor":"0","versao_patch":"9"' $A/public/app.json || falhou "entregar: o app.json nao e o de la"
cmp -s $ANTIGO/data/cache/relatorios/atendimentos.cache $A/data/cache/relatorios/atendimentos.cache || falhou "entregar: o data/ nao veio"
for g in data/cache data/logs/agenda_json data/DoctrineORMModule/Proxy public/layout/img/avatar/cache public/layout/img/avatar/tmp; do
    [ -d $A/$g ] || falhou "entregar: falta a gravavel $g"
done
[ "$(stat -c %U $A/data/DoctrineORMModule/Proxy)" = www-data ] || falhou "entregar: o Proxy nao e do pool"
[ -f $FR/novo/index.html ] || falhou "entregar: a tela nova nao esta em $FR/novo"
grep -q 'systemctl reload php8.1-fpm' $REG || falhou "entregar: nao recarregou o php-fpm"
grep -q 'curl .*npsContabilizar' $REG || falhou "entregar: nao conferiu o npsContabilizar"
[ ! -f $EST/passo ] || falhou "entregar: a marca do passo ficou"
[ ! -e $N ] || falhou "entregar: a release ao lado ficou"

# AS GUARDAS DA VOLTA AO CODIGO ANTIGO: nada sai do lugar.
recusa 'voltar sem a manutencao' 'não carrega /etc/nginx/manutencao.conf' env ENSAIO_MANUTENCAO_CARREGADA=nao $P voltar
recusa 'voltar com o crontab ativo' 'ainda tem linha ativa' env ENSAIO_CRON_ATIVO=sim $P voltar
recusa 'voltar com conexao da aplicacao' 'as rotinas em curso não terminaram' env ENSAIO_CONEXOES=1 $P voltar
recusa 'voltar ao codigo antigo sem o bloqueio do migrar-senhas' 'bloqueio do migrar-senhas' env ENSAIO_BLOQUEIO=nao $P voltar
recusa 'voltar ao codigo antigo com o crontab de uma entrega' 'o crontab dele é o da janela' env CRONTAB_GUARDADO=/root/crontab-entrega.txt $P voltar
echo "$(date -Iseconds) voltando" > $EST/passo
recusa 'voltar com uma volta parada no meio' 'uma volta anterior parou no meio' $P voltar
rm -f $EST/passo
[ "$(cat $A/.publicar/release 2>/dev/null)" = "$HEAD" ] || falhou "as recusas do voltar tiraram a release do lugar"

# A VOLTA, cronometrada: ao codigo antigo, sem recarregar (o item 4 de "A volta" vem antes).
caso
t2=$(date +%s%N)
$P voltar > /tmp/saida-voltar.txt 2>&1 || falhou "voltar: saiu $? ($(grep -m1 ABORTADO /tmp/saida-voltar.txt))"
t3=$(date +%s%N)
[ ! -f $A/.publicar/release ] || falhou "voltar: o codigo no lugar nao e o antigo"
[ "$(contar $A/public/arquivos)" = "$UPLOADS" ] || falhou "voltar: o arquivos nao voltou inteiro"
[ -f $A/public/layout/img/avatar/foto1.jpg ] || falhou "voltar: as fotos do avatar nao voltaram"
[ "$(grep -c reload $REG)" = 1 ] || falhou "voltar ao codigo antigo: recarregou o php-fpm antes dos nomes das permissoes (o item 4 de \"A volta\")"
# O NOME DE "A volta" do procedimento: public_html.novo-<data>, o que o item 4 dela usa.
DEVOLVIDA=$(ls -d $SITE/public_html.novo-* 2>/dev/null | head -n 1)
[ -n "$DEVOLVIDA" ] || falhou "voltar ao codigo antigo: a arvore nova nao ficou em public_html.novo-<data>, o nome de \"A volta\""
DEVOLVER=$(sed -n 's/.*< \([^ ]*devolver-nomes-das-permissoes-das-telas-novas\.sql\).*/\1/p' /tmp/saida-voltar.txt | head -n 1)
[ -n "$DEVOLVER" ] && [ "${DEVOLVER%/scripts/*}" = "$DEVOLVIDA" ] && [ -f "$DEVOLVER" ] \
    || falhou "voltar ao codigo antigo: a saida nao manda o devolver-nomes pela arvore devolvida ('$DEVOLVER', devolvida '$DEVOLVIDA')"

# A SEGUNDA ENTREGA, sobre a primeira.
caso
rm -rf $SITE/public_html.novo-* $SITE/public_html.antigo-*
LOCAL_PHP=/tmp/local.php-da-release $P levar $E/pacote1.tar.gz > /tmp/saida.txt 2>&1 && $P entregar > /tmp/saida.txt 2>&1 \
    || falhou "a primeira entrega de novo: $(grep -m1 ABORTADO /tmp/saida.txt)"
$P levar $E/pacote2.tar.gz > /tmp/saida.txt 2>&1 || falhou "levar o segundo: $(grep -m1 ABORTADO /tmp/saida.txt)"
echo 'segunda' > $N/.publicar/novo/segunda.txt
# UMA ENTREGA DEPOIS DA ETAPA 1: o crontab da janela e da volta ao codigo
# antigo, e nao o desta noite; e o usuario do local.php no ar conta.
recusa 'a segunda com o crontab da janela' 'é o arquivo da janela da etapa 1' $P trocar
export CRONTAB_GUARDADO=/root/crontab-entrega.txt
recusa 'a segunda com uma rotina do local.php no ar em curso' 'as rotinas em curso não terminaram' env ENSAIO_CONEXAO_DE=franquiabv_no_ar $P trocar
# PELO trocar (o da janela da etapa 1): troca, e nao recarrega o php-fpm.
: > $REG
$P trocar > /tmp/saida.txt 2>&1 || falhou "a segunda entrega, pelo trocar: $(grep -m1 ABORTADO /tmp/saida.txt)"
! grep -q 'systemctl reload' $REG || falhou "o trocar recarregou o php-fpm (na janela, o 9 vem depois dos .sql do 7 e do vhost do 8)"
ls -d $SITE/public_html.anterior-* >/dev/null 2>&1 || falhou "a segunda entrega: a primeira nao ficou em public_html.anterior-<hora>"
[ -f $FR/novo/segunda.txt ] && [ -d $FR/novo.anterior ] || falhou "a segunda entrega: a tela nova nao trocou com a anterior de lado"
: > $REG
$P voltar > /tmp/saida.txt 2>&1 || falhou "voltar da segunda: $(grep -m1 ABORTADO /tmp/saida.txt)"
[ "$(cat $A/.publicar/release 2>/dev/null)" = "$HEAD" ] || falhou "voltar da segunda: a primeira nao esta no lugar"
grep -q 'systemctl reload php8.1-fpm' $REG || falhou "voltar da segunda (entre duas releases): nao recarregou o php-fpm"
ls -d $SITE/public_html.devolvida-* >/dev/null 2>&1 || falhou "voltar da segunda: a release devolvida nao ficou em public_html.devolvida-<hora>"
[ ! -f $FR/novo/segunda.txt ] || falhou "voltar da segunda: a tela nova nao voltou"
[ "$(contar $A/public/arquivos)" = "$UPLOADS" ] || falhou "voltar da segunda: o arquivos nao voltou inteiro"

echo "TEMPOS levar=$(( (tl1 - tl0) / 1000000 )) entrega=$(( (t1 - t0) / 1000000 )) volta=$(( (t3 - t2) / 1000000 )) uploads_mb=$UP_MB data_mb=$DATA_MB pacote_kb=$(( $(stat -c %s $E/pacote1.tar.gz) / 1024 ))"
if [ "$falhas" -gt 0 ]; then echo "FALHAS=$falhas CASOS=$casos"; exit 1; fi
echo "CASOS=$casos"
exit 0
FIM
)

SAIDA=$(printf '%s\n' "$DENTRO" | docker run --rm -i --pull=never --network none --entrypoint bash \
    -e ENSAIO_UPLOAD_MB="${ENSAIO_UPLOAD_MB:-120}" -e ENSAIO_DATA_MB="${ENSAIO_DATA_MB:-40}" \
    -v "$T/ensaio:/ensaio:ro" "$IMAGEM" -s 2>&1)
CODIGO=$?
[ -z "$falhas_maquina" ] || { printf "$falhas_maquina\n"; [ "$CODIGO" != 0 ] || CODIGO=1; }
printf '%s\n' "$SAIDA" | grep -v '^CASOS=\|^FALHAS=\|^TEMPOS '
TEMPOS=$(printf '%s\n' "$SAIDA" | sed -n 's/^TEMPOS //p')
ms() { printf '%s' "$TEMPOS" | tr ' ' '\n' | sed -n "s/^$1=//p"; }
case "$CODIGO" in
    0) printf 'ok: os %s casos -- o levar (desempacotar ao lado) levou %s ms, a entrega %s ms e a volta %s ms (no conteiner, com %s MB de upload, %s MB de data/ e um pacote de %s KB)\n' \
           "$(printf '%s\n' "$SAIDA" | sed -n 's/^CASOS=//p')" "$(ms levar)" "$(ms entrega)" "$(ms volta)" "$(ms uploads_mb)" "$(ms data_mb)" "$(ms pacote_kb)" ;;
    1) echo "O ROTEIRO DE PUBLICAR NA PRODUCAO NAO FAZ O QUE DIZ ($PUBLICAR): $(printf '%s\n' "$SAIDA" | sed -n 's/^FALHAS=//p' | sed 's/ CASOS=/ falha(s) em /') caso(s)" ;;
    *) echo "NAO CONSEGUI MEDIR: o conteiner saiu $CODIGO" >&2; printf '%s\n' "$SAIDA" | tail -n 5 >&2; exit 2 ;;
esac
exit "$CODIGO"
