erplibre/test
Mathieu Benoit ad63236375 [ADD] analyse: le socle des outils d'analyse d'une base Odoo
Premier fichier de script/analyse/, le paquet d'outils qui répondent à « qu'y
a-t-il dans cette base, et qu'est-ce qui cassera à la montée de version ». Ce
commit ne livre que ce que le premier outil consommera, pas une bibliothèque
spéculative.

psql en sous-processus, pas psycopg2. La raison est déjà écrite dans
reset_stale_cow_views.py : ces outils tournent sur des bases dont le registre
Odoo ne charge PAS — une base 12.0 sur un checkout 18.0 — et c'est précisément
le moment où on veut les analyser. Accessoirement psycopg2 n'est pas dans
.venv.erplibre, qui est l'interpréteur de ces outils.

La lecture seule est une garantie du serveur, pas une promesse du code.
PGOPTIONS porte default_transaction_read_only=on, donc PostgreSQL refuse toute
écriture sur la connexion. Un SET dans le même -c n'aurait rien donné : psql -c
ouvre une transaction implicite unique, et default_transaction_read_only ne vaut
que pour les transactions suivantes. PGOPTIONS borne aussi statement_timeout —
un scan parti en vrille ne doit pas figer un menu.

Le résultat voyage en JSON, pas en champs séparés. Une arch de vue contient des
sauts de ligne et des « | » : tout séparateur maison finit par couper au mauvais
endroit. json_agg côté PostgreSQL, json.loads côté Python, et le problème
n'existe plus. C'est le même choix que snapshot_cow_views.py.

Les sondes lisent pg_attribute, pas information_schema, qui est filtré par les
droits : avec un rôle non propriétaire elle rendrait un ensemble vide, et
l'analyse concluerait « aucune colonne website, donc aucune vue COW » sans le
moindre avertissement. Faux, et silencieux.

tr_col décide sur le TYPE réel de la colonne, pas sur un numéro de version. Un
champ traduit est du jsonb à partir de 16.0 et du texte avant ; une base à
moitié migrée porte les deux, et un numéro de version mentirait. Une colonne
inconnue rend NULL::text plutôt que du SQL invalide, ce qui permet de sonder et
d'interroger d'un trait.

MODEL_TABLE_OVERRIDE est dérivée des sources, pas écrite de mémoire : parcours
AST des 27 843 .py de odoo18.0/ et addons/, en ne gardant que les classes dont
le _table diffère du défaut. Onze entrées. Beaucoup de modules déclarent un
_table égal au défaut — les compter ferait croire à 22 surcharges là où il y en
a 11. Un modèle absent de la table et dont la table est introuvable est classé
« table inconnue », un fait, jamais « table orpheline », une anomalie.

Le nom de base est validé au lieu d'être échappé : il finit dans une commande
lancée avec shell=True, et l'alphabet qu'une base Odoo utilise vraiment est
court. Ce contrôle attrape aussi « Traceback (most recent call last): », que la
liste des bases pouvait offrir jusqu'au commit précédent.

Pas de __init__.py : script/todo/, script/database/ et script/odoo/migration/
n'en ont pas et sont importés tous les jours. Paquets d'espace de noms.

Vérifié. 31 tests sans base — fonctions pures, construction de SQL,
« False » de config.conf traité comme non défini, nom de base hostile refusé.
Puis à la main sur une base synthétique dont le SQL est dans le docstring du
test et a été rejoué tel quel : jsonb et text distingués, le « | » et le saut de
ligne préservés à travers json_query, ir.actions.act_window résolu en
ir_act_window, une base sans ir_module_module refusée, et un CREATE TABLE
refusé par le serveur. La suite passe de 262 à 293 tests, sans nouvel échec.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 08:11:20 +00:00
..
code_generator [FIX] make test with coverage: missing coverage parameter 2023-03-04 23:34:37 -05:00
test_analyse_lib.py [ADD] analyse: le socle des outils d'analyse d'une base Odoo 2026-08-03 08:11:20 +00:00
test_check_addons_exist.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_code_generator_tools.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_config_file.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_database_tools.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_docker_update_version.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_execute.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_format_file_to_commit.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_git_tool.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_iscompatible.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_kill_process_by_port.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_plan.base.md [ADD] test: add bilingual test plan with mmg 2026-03-11 23:07:01 -04:00
test_plan.fr.md [ADD] test: add bilingual test plan with mmg 2026-03-11 23:07:01 -04:00
test_plan.md [ADD] test: add bilingual test plan with mmg 2026-03-11 23:07:01 -04:00
test_todo.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_todo_i18n.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00
test_version.py [IMP] script: update copyright year to 2026 2026-03-11 23:16:05 -04:00