test: make consolidated workspace self-contained
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
"""Missão 6 — Bloco A: Testes de Higiene (Migrations e Inventário dos 9 Datasets)."""
|
"""Missão 6 — Bloco A: Testes de Higiene (Migrations e Inventário dos 9 Datasets)."""
|
||||||
import subprocess
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from alembic.config import Config
|
from alembic.config import Config
|
||||||
from alembic.script import ScriptDirectory
|
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}"
|
assert heads == ["0035_cfop_ippt_write_mode"], f"Esperado head única 0035, obtido: {heads}"
|
||||||
|
|
||||||
|
|
||||||
def test_feature_branch_migration_chains_to_0034():
|
def test_migration_0035_chains_to_0034_and_0033_is_gone():
|
||||||
"""Garante que na branch feature/cfop-ippt-write a migração 0035 encadeia exatamente em 0034."""
|
"""Garante que 0035 encadeia exatamente em 0034 e que a numeração antiga (0033) não existe mais.
|
||||||
# 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
|
|
||||||
|
|
||||||
# Verifica que 0033 não existe mais na branch
|
Historicamente (Missão 8) este teste lia o arquivo via `git show
|
||||||
res_old = subprocess.run(
|
feature/cfop-ippt-write:...` para confirmar a correção *antes* do merge
|
||||||
["git", "show", "feature/cfop-ippt-write:central/alembic/versions/0033_cfop_ippt_write_mode.py"],
|
daquela branch em master. A branch foi mesclada integralmente (0
|
||||||
capture_output=True,
|
commits exclusivos — confirmado na auditoria de consolidação do
|
||||||
text=True,
|
monorepo) e master já carrega o resultado correto diretamente em
|
||||||
cwd=str(ROOT),
|
`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
|
||||||
assert res_old.returncode != 0, "Migração 0033 não deve mais existir na branch feature"
|
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():
|
def test_inventory_9_datasets_coverage():
|
||||||
|
|||||||
+30
-1
@@ -61,7 +61,36 @@ a tabela ficar vazia. Login checa primeiro o admin do `.env`, depois
|
|||||||
pytest -v
|
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
|
## Rodando via Docker
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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;
|
||||||
Reference in New Issue
Block a user