Test report
What is tested in Access X-Ray, and how to run the suite.
Module: technovision_access_xray 18.0.1.0.0 Tests: 45 across 2 files Command:
odoo-bin -d test_db -i technovision_access_xray \
--test-enable --test-tags /technovision_access_xray --stop-after-initShape of the suite
| File | Tests | Kind |
|---|---|---|
| tests/test_resolver_core.py | 33 | Pure functions, no database |
| tests/test_resolver_odoo.py | 12 | TransactionCase, against a real Odoo registry |
The split is deliberate. The hard part of this product is not talking to Odoo — it is the resolution logic: transitive closure over the group graph, union semantics for access rules, and the different composition of global versus group record rules. That logic lives in resolver_core.py as pure functions over plain data, so it can be tested exhaustively without a database, including cases that are awkward to construct in a live registry.
test_resolver_core.py — the resolution logic
Group closure
| Test | Asserts |
|---|---|
| test_direct_groups_are_held | Direct membership is included |
| test_inheritance_is_transitive | Implied groups are followed |
| test_deep_chain | Multi-level chains resolve fully |
| test_diamond_is_not_double_counted | A group reachable by two paths appears once |
| test_cycle_terminates | A cyclic implied_ids graph does not hang |
| test_self_reference_terminates | A group implying itself does not hang |
| test_empty_input / test_none_ids_ignored | Degenerate inputs are safe |
Cycles are not hypothetical. Odoo does not forbid them, and a naive traversal loops forever on a database where someone has made one.
Grant paths
test_same_group, test_direct, test_chain, test_shortest_path_wins, test_unreachable, test_cycle_does_not_hang — the "because X implies Y, which grants Z" explanation, including that the shortest path is the one reported and that an unreachable grant is reported as such rather than invented.
Model access — union semantics
| Test | Asserts |
|---|---|
| test_permission_is_a_union_not_an_intersection | Rights accumulate across groups |
| test_there_is_no_deny | No rule can subtract a permission — the single most misunderstood fact about Odoo ACLs |
| test_every_granting_group_is_recorded | All granting groups are named, not just the first |
| test_duplicate_group_recorded_once | No duplicates in the explanation |
| test_rows_for_groups_not_held_are_ignored | Rules for groups the user lacks do not apply |
| test_global_row_applies_to_everyone | A row with no group applies to all |
| test_no_rows_grants_nothing | Absence of a rule is absence of permission |
Record rules — composition
| Test | Asserts |
|---|---|
| test_global_rules_are_collected | Global rules are found |
| test_group_rule_applies_only_when_group_held | Group rules apply conditionally |
| test_extra_group_widens_rather_than_narrows | Adding a group can widen visibility — group rules OR |
| test_global_and_group_rules_are_kept_apart | The two kinds are not merged, because they compose differently |
| test_no_group_rules_is_not_a_denial | No group rule is not a restriction |
Bypass accounts
test_superuser_is_reported_as_a_bypass, test_settings_group_is_reported_as_a_bypass, test_bypass_beats_absent_acls, test_ordinary_user_with_grant — an account that bypasses access control is reported as such rather than given a permission list that would imply limits it does not have.
test_resolver_odoo.py — against a real registry
| Test | Asserts |
|---|---|
| test_implied_map_shape | The group graph is read correctly from res.groups |
| test_held_groups_include_the_whole_chain | Closure works on real Odoo groups |
| test_acl_rows_normalise_false_group_to_none | Odoo's False group id becomes a global rule, not a group rule |
| test_admin_group_resolves | The Settings group resolves |
| test_resolve_user_reports_bypass_for_admin | Admin is reported as a bypass |
| test_resolve_user_lists_only_granted_models | No phantom models in the output |
| test_resolve_model_separates_bypassed_accounts | Unconstrained accounts are listed apart |
| test_explain_grant_returns_a_path | The explanation is produced end to end |
| test_module_writes_nothing_to_odoo_security_tables | The read-only guarantee, enforced by test |
| test_scan_produces_findings_with_recommendations | Every finding carries an action |
| test_scan_replaces_rather_than_accumulates | Re-scanning does not pile up stale findings |
| test_administrators_finding_excludes_root | The root account is not reported as a finding about itself |
test_module_writes_nothing_to_odoo_security_tables is the one that matters. The central product claim is that this is safe to run on production because it cannot change permissions. That claim is asserted by a test rather than by this sentence.
Known gaps
| Gap | Status |
|---|---|
| Field-level groups= resolution | Not implemented, so not tested. Stated in FAQ.md and on the listing. |
| Performance on very large directories | Not covered by an automated test. See TROUBLESHOOTING.md. |
| Odoo 17 and 19 | No build, so no test run. |
Density is 30 tests per 1,000 production lines. Stated here rather than claimed as "well tested", so it can be compared.