From 016bfc756c1e77abfce06beaa85cafe3f984a4d1 Mon Sep 17 00:00:00 2001 From: gti Date: Tue, 29 Sep 2026 15:14:54 -0300 Subject: [PATCH] test: make consolidated workspace self-contained --- .../central/tests/test_mission_06_hygiene.py | 39 +++--- gerenciador/README.md | 31 ++++- gerenciador/docker-compose.test.yml | 28 ++++ gerenciador/tests/db/schema.sql | 128 ++++++++++++++++++ 4 files changed, 203 insertions(+), 23 deletions(-) create mode 100644 gerenciador/docker-compose.test.yml create mode 100644 gerenciador/tests/db/schema.sql diff --git a/fiscal/central/tests/test_mission_06_hygiene.py b/fiscal/central/tests/test_mission_06_hygiene.py index 6d5927e..5b58440 100644 --- a/fiscal/central/tests/test_mission_06_hygiene.py +++ b/fiscal/central/tests/test_mission_06_hygiene.py @@ -1,5 +1,4 @@ """Missão 6 — Bloco A: Testes de Higiene (Migrations e Inventário dos 9 Datasets).""" -import subprocess from pathlib import Path from alembic.config import Config from alembic.script import ScriptDirectory @@ -15,28 +14,24 @@ def test_alembic_master_head_is_single(): assert heads == ["0035_cfop_ippt_write_mode"], f"Esperado head única 0035, obtido: {heads}" -def test_feature_branch_migration_chains_to_0034(): - """Garante que na branch feature/cfop-ippt-write a migração 0035 encadeia exatamente em 0034.""" - # Obter conteúdo de 0035 na branch feature/cfop-ippt-write via git show - result = subprocess.run( - ["git", "show", "feature/cfop-ippt-write:central/alembic/versions/0035_cfop_ippt_write_mode.py"], - capture_output=True, - text=True, - cwd=str(ROOT), - ) - assert result.returncode == 0, f"Arquivo 0035_cfop_ippt_write_mode.py deve existir na branch feature/cfop-ippt-write: {result.stderr}" - content = result.stdout - assert 'revision = "0035_cfop_ippt_write_mode"' in content - assert 'down_revision = "0034_reference_data_registry"' in content +def test_migration_0035_chains_to_0034_and_0033_is_gone(): + """Garante que 0035 encadeia exatamente em 0034 e que a numeração antiga (0033) não existe mais. - # Verifica que 0033 não existe mais na branch - res_old = subprocess.run( - ["git", "show", "feature/cfop-ippt-write:central/alembic/versions/0033_cfop_ippt_write_mode.py"], - capture_output=True, - text=True, - cwd=str(ROOT), - ) - assert res_old.returncode != 0, "Migração 0033 não deve mais existir na branch feature" + Historicamente (Missão 8) este teste lia o arquivo via `git show + feature/cfop-ippt-write:...` para confirmar a correção *antes* do merge + daquela branch em master. A branch foi mesclada integralmente (0 + commits exclusivos — confirmado na auditoria de consolidação do + monorepo) e master já carrega o resultado correto diretamente em + `central/alembic/versions/`, então a checagem passou a ler o estado + versionado atual em vez de depender de uma ref Git externa — necessário + para o teste funcionar também num clone que não tenha essa branch (como + o monorepo). A invariante validada é a mesma de antes. + """ + versions_dir = ROOT / "central" / "alembic" / "versions" + current = (versions_dir / "0035_cfop_ippt_write_mode.py").read_text(encoding="utf-8") + assert 'revision = "0035_cfop_ippt_write_mode"' in current + assert 'down_revision = "0034_reference_data_registry"' in current + assert not (versions_dir / "0033_cfop_ippt_write_mode.py").exists(), "Migração 0033 não deve mais existir" def test_inventory_9_datasets_coverage(): diff --git a/gerenciador/README.md b/gerenciador/README.md index 3386ad8..2289122 100644 --- a/gerenciador/README.md +++ b/gerenciador/README.md @@ -61,7 +61,36 @@ a tabela ficar vazia. Login checa primeiro o admin do `.env`, depois pytest -v ``` -Os testes usam defaults definidos em `tests/conftest.py` (equivalentes ao `.env.example`) e incluem testes de integração que precisam do container MySQL de dev (`licenciamento-mysql-dev`, `127.0.0.1:3307`) rodando. +Os testes usam defaults definidos em `tests/conftest.py` (equivalentes ao `.env.example`) e incluem testes de integração que precisam de um MySQL em `127.0.0.1:3307`. + +### Ambiente de teste local (MySQL descartável) + +Fora do repositório original (`BLOQUEIO SGV`), este subtree não tem acesso ao container +`licenciamento-mysql-dev` nem ao dump real de clientes — nem deveria, dado que este monorepo +não importa dado real de nenhum cliente. Para rodar a suíte de forma autocontida, este +diretório traz um MySQL de teste **descartável**, separado do `docker-compose.yml` de +produção: + +``` +docker compose -f docker-compose.test.yml up -d +``` + +Isso sobe um `mysql:5.7` só com a estrutura das tabelas (`CLIENTE`, `CLIENTE_CONTATO`, +`Clientes_Chaves`, `FUNCIONARIO_PAINEL`, `LOG_PAINEL`) a partir de `tests/db/schema.sql` — +**DDL apenas, nenhum dado de cliente**. Cada tabela do schema.sql tem, em comentário, a fonte +exata de onde a definição foi extraída (docstring do módulo Python correspondente, ou a +documentação de schema do sistema legado). O banco roda em `tmpfs` (nunca grava em disco, +nunca sobrevive a um restart do container) e só escuta em `127.0.0.1:3307` — sem rede externa, +sem volume nomeado, sem credencial real (senha `devpassword123`, válida só para este banco +descartável). + +Depois de rodar os testes: + +``` +docker compose -f docker-compose.test.yml down -v +``` + +remove o container e a rede — nada persiste. ## Rodando via Docker diff --git a/gerenciador/docker-compose.test.yml b/gerenciador/docker-compose.test.yml new file mode 100644 index 0000000..9ba91da --- /dev/null +++ b/gerenciador/docker-compose.test.yml @@ -0,0 +1,28 @@ +# MySQL de TESTE, exclusivamente local e descartável, para rodar a suíte +# de integração do painel-clientes-web ("GTI Gerenciador") de forma +# autocontida -- sem depender de nenhum container externo ao monorepo. +# +# NÃO é o compose de produção (esse continua sendo docker-compose.yml, +# inalterado). NÃO expõe rede externa, NÃO usa volume nomeado persistente, +# NÃO tem credencial real -- a senha aqui só existe neste banco descartável. +# +# Uso: ver README.md, seção "Ambiente de teste local (MySQL descartável)". +name: gerenciador-test + +services: + mysql-test: + image: mysql:5.7 + environment: + MYSQL_ROOT_PASSWORD: devpassword123 + MYSQL_DATABASE: gtisoftw_clientes_dev + ports: + - "127.0.0.1:3307:3306" + volumes: + - ./tests/db/schema.sql:/docker-entrypoint-initdb.d/schema.sql:ro + tmpfs: + - /var/lib/mysql + healthcheck: + test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-pdevpassword123"] + interval: 5s + timeout: 5s + retries: 10 diff --git a/gerenciador/tests/db/schema.sql b/gerenciador/tests/db/schema.sql new file mode 100644 index 0000000..8a0761e --- /dev/null +++ b/gerenciador/tests/db/schema.sql @@ -0,0 +1,128 @@ +-- Schema DDL-only para o MySQL de TESTE local do painel-clientes-web ("GTI Gerenciador"). +-- +-- Nenhum dado real de cliente. Nenhum INSERT. Só estrutura, reconstruída +-- a partir de fontes autoritativas já existentes no próprio código-fonte +-- (nunca inventada) -- a origem de cada tabela está anotada abaixo. +-- +-- Uso: ver gerenciador/README.md, seção "Ambiente de teste local (MySQL descartável)". + +-- ===================================================================== +-- CLIENTE +-- Fonte: licenciamento-n8n/docs/MAPEAMENTO_BANCO.md (CREATE TABLE original, +-- SHOW CREATE TABLE confirmado contra o banco de dev) + coluna ATIVO +-- documentada como ALTER TABLE manual em app/db/clientes.py (docstring do +-- módulo). Ambas as fontes vivem fora deste subtree (repositório original +-- BLOQUEIO SGV) -- lidas apenas como referência de schema, nunca copiadas +-- como dado. +-- ===================================================================== +CREATE TABLE CLIENTE ( + ID int(10) unsigned NOT NULL AUTO_INCREMENT, + CODIGO varchar(6) NOT NULL, + CNPJ varchar(20) NOT NULL, + RAZAO varchar(60) NOT NULL, + FANTASIA varchar(45) NOT NULL, + IE varchar(20) NOT NULL, + ENDERECO varchar(45) NOT NULL, + CIDADE varchar(45) NOT NULL, + BAIRRO varchar(45) NOT NULL, + UF char(2) NOT NULL, + CONTATO varchar(45) NOT NULL, + TELEFONE varchar(14) NOT NULL, + CELULAR varchar(14) NOT NULL, + CEP varchar(10) NOT NULL, + IMPLANTACAO decimal(15,2) NOT NULL, + MENSALIDADE decimal(15,2) NOT NULL, + JUROS_MORA decimal(15,2) NOT NULL, + JUROS_MULTA decimal(15,2) NOT NULL, + DATA_CONTRATO date NOT NULL, + EMAIL varchar(80) NOT NULL, + OBS varchar(250) DEFAULT NULL, + VENCIMENTO_CONTRATO date NOT NULL, + DIA_VENCIMENTO char(2) NOT NULL, + ATIVO TINYINT(1) NOT NULL DEFAULT 1, + PRIMARY KEY (ID) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- ===================================================================== +-- CLIENTE_CONTATO +-- Fonte: NÃO existe um CREATE TABLE literal documentado em nenhum arquivo +-- encontrado (docs/CANDIDATO_CLIENTE_CONTATO.md descreve a tabela e cita +-- "ver mensagem anterior" para o DDL exato, que não está em nenhum arquivo +-- do repositório). Reconstruída a partir do uso real e exclusivo da tabela +-- em app/db/contatos.py (todas as colunas referenciadas em SELECT/INSERT/ +-- UPDATE: ID, CLIENTE_ID, NOME, TELEFONE, EMAIL) + o comportamento de FK +-- descrito no docstring do mesmo módulo ("CLIENTE_ID FK real, ON DELETE +-- RESTRICT ON UPDATE CASCADE" para CLIENTE.ID). Nenhuma coluna foi +-- inventada além do que o próprio código exige para funcionar. +-- ===================================================================== +CREATE TABLE CLIENTE_CONTATO ( + ID int(10) unsigned NOT NULL AUTO_INCREMENT, + CLIENTE_ID int(10) unsigned NOT NULL, + NOME varchar(80) DEFAULT NULL, + TELEFONE varchar(20) NOT NULL, + EMAIL varchar(80) DEFAULT NULL, + PRIMARY KEY (ID), + KEY IDX_CLIENTE_CONTATO_CLIENTE_ID (CLIENTE_ID), + CONSTRAINT FK_CLIENTE_CONTATO_CLIENTE FOREIGN KEY (CLIENTE_ID) + REFERENCES CLIENTE (ID) ON DELETE RESTRICT ON UPDATE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- ===================================================================== +-- Clientes_Chaves (legado, o painel só LÊ, nunca escreve) +-- Fonte: licenciamento-n8n/docs/MAPEAMENTO_BANCO.md (CREATE TABLE original, +-- SHOW CREATE TABLE confirmado contra o banco de dev). +-- ===================================================================== +CREATE TABLE Clientes_Chaves ( + ID varchar(6) NOT NULL, + M1 varchar(30) NOT NULL, + M2 varchar(30) NOT NULL, + M3 varchar(30) NOT NULL, + M4 varchar(30) NOT NULL, + M5 varchar(30) NOT NULL, + M6 varchar(30) NOT NULL, + M7 varchar(30) NOT NULL, + M8 varchar(30) NOT NULL, + M9 varchar(30) NOT NULL, + M10 varchar(30) NOT NULL, + M11 varchar(30) NOT NULL, + M12 varchar(30) NOT NULL, + Cliente varchar(40) NOT NULL, + Prorrogacao date NOT NULL, + PRIMARY KEY (ID) +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- ===================================================================== +-- FUNCIONARIO_PAINEL +-- Fonte: CREATE TABLE + ALTER TABLE (coluna PERFIL) documentados +-- integralmente no docstring de app/db/funcionarios.py (dentro deste +-- mesmo subtree, gerenciador/), já com a coluna PERFIL incorporada. +-- ===================================================================== +CREATE TABLE FUNCIONARIO_PAINEL ( + ID INT UNSIGNED NOT NULL AUTO_INCREMENT, + NOME VARCHAR(80) NOT NULL, + LOGIN VARCHAR(40) NOT NULL, + SENHA_HASH VARCHAR(255) NOT NULL, + PERFIL ENUM('ADMIN','PADRAO') NOT NULL DEFAULT 'ADMIN', + ATIVO TINYINT(1) NOT NULL DEFAULT 1, + CRIADO_EM DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (ID), + UNIQUE KEY UQ_FUNCIONARIO_PAINEL_LOGIN (LOGIN) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-- ===================================================================== +-- LOG_PAINEL +-- Fonte: CREATE TABLE documentado integralmente no docstring de +-- app/db/log.py (dentro deste mesmo subtree, gerenciador/). +-- ===================================================================== +CREATE TABLE LOG_PAINEL ( + ID INT UNSIGNED NOT NULL AUTO_INCREMENT, + CRIADO_EM DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, + USUARIO VARCHAR(60) NOT NULL, + ACAO VARCHAR(40) NOT NULL, + ENTIDADE VARCHAR(20) NOT NULL, + ENTIDADE_ID VARCHAR(20) DEFAULT NULL, + SUCESSO TINYINT(1) NOT NULL, + DETALHE VARCHAR(500) DEFAULT NULL, + PRIMARY KEY (ID), + KEY IDX_LOG_PAINEL_CRIADO_EM (CRIADO_EM) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;