11# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
22
33from pathlib import Path
4+ from unittest .mock import patch
45
56from lxml import etree
67from odoo_test_helper import FakeModelLoader
78
9+ from odoo .exceptions import ValidationError
10+ from odoo .tools .config import config
11+
812from odoo .addons .data_encryption .tests .common import CommonDataEncrypted
913
1014
@@ -14,18 +18,17 @@ def setUpClass(cls):
1418 super ().setUpClass ()
1519 cls .loader = FakeModelLoader (cls .env , cls .__module__ )
1620 cls .loader .backup_registry ()
17-
21+ cls . addClassCleanup ( cls . loader . restore_registry )
1822 # The fake class is imported here !! After the backup_registry
1923 from .models import FakePartner
2024
2125 cls .loader .update_registry ((FakePartner ,))
2226 cls .set_new_key_env ("prod" )
2327 cls .set_new_key_env ("preprod" )
2428
25- @classmethod
26- def tearDownClass (cls ):
27- cls .loader .restore_registry ()
28- super ().tearDownClass ()
29+ cls .partner = cls .env ["res.partner" ].create (
30+ {"name" : "Test Partner" , "city" : "Test City" }
31+ )
2932
3033 def test_env_dependent_value (self ):
3134 partner = self .env ["res.partner" ].create (
@@ -110,3 +113,130 @@ def test_view_with_env_update(self):
110113 confirm_button .get ("invisible" ),
111114 "context.get(\" environment\" , 'test') != 'test'" ,
112115 )
116+
117+ def test_missing_encryption_key (self ):
118+ """Test behavior when encryption key is missing for current env"""
119+ with patch .object (
120+ config ,
121+ "get" ,
122+ side_effect = lambda key , default = None : "missing_env"
123+ if key == "running_env"
124+ else (None if key .startswith ("encryption_key_" ) else default ),
125+ ):
126+ # This should trigger the warning in _current_env_encrypted_key_exists
127+ self .assertFalse (self .partner ._current_env_encrypted_key_exists ())
128+
129+ # Test fallbacks
130+ # Since we can't easily mock super(), we just verify it doesn't crash
131+ self .partner ._compute_server_env_from_default ("city" , {})
132+ self .partner ._inverse_server_env ("city" )
133+
134+ # Test warning div in view
135+ mixin_obj = self .env ["server.env.mixin" ]
136+ elem = mixin_obj ._get_extra_environment_info_div ("test" , ["test" , "prod" ])
137+ self .assertIn (
138+ "The encryption key for current environement is not defined" ,
139+ etree .tostring (elem , encoding = "unicode" ),
140+ )
141+
142+ def test_action_change_env_data_encrypted_fields (self ):
143+ """Test action_change_env_data_encrypted_fields"""
144+ # Case 1: No action in context
145+ action = self .partner .action_change_env_data_encrypted_fields ()
146+ self .assertEqual (action .get ("res_id" ), self .partner .id )
147+
148+ # Case 2: Action in context
149+ # We need a real action id to browse
150+ act_window = self .env ["ir.actions.act_window" ].search ([], limit = 1 )
151+ if act_window :
152+ # Mock the read result to have multiple views including a non-form one
153+ with patch .object (
154+ type (self .env ["ir.actions.act_window" ]),
155+ "read" ,
156+ return_value = [
157+ {
158+ "views" : [(1 , "tree" ), (2 , "form" )],
159+ "type" : "ir.actions.act_window" ,
160+ }
161+ ],
162+ ):
163+ partner_with_ctx = self .partner .with_context (
164+ params = {"action" : act_window .id }
165+ )
166+ action = partner_with_ctx .action_change_env_data_encrypted_fields ()
167+ self .assertEqual (action .get ("res_id" ), self .partner .id )
168+ self .assertEqual (action .get ("view_mode" ), "form" )
169+ self .assertEqual (len (action ["views" ]), 1 )
170+ self .assertEqual (action ["views" ][0 ][1 ], "form" )
171+
172+ def test_view_processing_edge_cases (self ):
173+ """Test various edge cases in view processing"""
174+ mixin_obj = self .env ["server.env.mixin" ]
175+ arch = etree .XML ("<form><sheet><field name='test'/></sheet></form>" )
176+
177+ # 1. view_type != "form"
178+ res = mixin_obj ._update_form_view_from_env (arch , "tree" )
179+ self .assertEqual (res , arch )
180+
181+ # 2. missing running_env
182+ with patch .dict (config .options , {"running_env" : "" }):
183+ with self .assertRaises (ValidationError ):
184+ mixin_obj ._update_form_view_from_env (arch , "form" )
185+
186+ # 3. missing sheet
187+ bad_arch = etree .XML ("<form><group><field name='test'/></group></form>" )
188+ with self .assertLogs (
189+ "odoo.addons.server_environment_data_encryption.models.server_env_mixin" ,
190+ level = "ERROR" ,
191+ ) as cm :
192+ mixin_obj ._update_form_view_from_env (bad_arch , "form" )
193+ self .assertTrue (
194+ any ("Missing sheet for form view" in output for output in cm .output )
195+ )
196+
197+ def test_set_readonly_form_view_skip_existing (self ):
198+ """Test that _set_readonly_form_view skips fields already
199+ in _server_env_fields"""
200+ mixin_obj = self .env ["res.partner" ] # This one has 'city' in _server_env_fields
201+ arch = etree .XML (
202+ "<form><sheet><field name='city'/><field name='name'/></sheet></form>"
203+ )
204+ mixin_obj ._set_readonly_form_view (arch , "test" , ["test" ])
205+
206+ city_field = arch .find (".//field[@name='city']" )
207+ name_field = arch .find (".//field[@name='name']" )
208+
209+ # city should NOT have readonly added by
210+ # this method specifically (it's handled differently or skipped)
211+ self .assertNotIn (
212+ "context.get(\" environment\" , 'test') != 'test'" ,
213+ city_field .get ("readonly" , "" ),
214+ )
215+ # name SHOULD have it
216+ self .assertIn (
217+ "context.get(\" environment\" , 'test') != 'test'" ,
218+ name_field .get ("readonly" , "" ),
219+ )
220+
221+ def test_inverse_server_env_not_editable (self ):
222+ """Test _inverse_server_env when field is not editable"""
223+ with patch .object (
224+ type (self .partner ),
225+ "_server_env_is_editable_fieldname" ,
226+ return_value = "is_company" ,
227+ ):
228+ self .partner .is_company = False
229+ # This should skip the loop body
230+ self .partner ._inverse_server_env ("city" )
231+
232+ def test_get_view_integration (self ):
233+ """Test integration via _get_view"""
234+ arch_res , view = self .env ["res.partner" ]._get_view (view_type = "form" )
235+ # Check if our extra div was inserted
236+ self .assertTrue (
237+ any (
238+ "action_change_env_data_encrypted_fields"
239+ in etree .tostring (node , encoding = "unicode" )
240+ for node in arch_res .xpath ("//button" )
241+ )
242+ )
0 commit comments