# -*- coding: utf-8 -*- from odoo.tests.common import TransactionCase, tagged @tagged('post_install', '-at_install') class TestFusionLoginAuditModel(TransactionCase): def test_model_exists_and_creates(self): """Audit row can be created with all expected fields.""" Audit = self.env['fusion.login.audit'].sudo() rec = Audit.create({ 'attempted_login': 'demo@example.com', 'result': 'success', 'ip_address': '203.0.113.5', 'user_agent_raw': 'Mozilla/5.0 Test', 'browser': 'Test 1.0', 'os': 'TestOS', 'device_type': 'desktop', 'database': self.env.cr.dbname, 'geo_lookup_state': 'pending', }) self.assertTrue(rec.id) self.assertEqual(rec.result, 'success') self.assertEqual(rec.geo_lookup_state, 'pending') self.assertEqual(rec.database, self.env.cr.dbname) self.assertTrue(rec.event_time) # default fires def test_failure_reason_optional(self): """failure_reason is null on success rows.""" rec = self.env['fusion.login.audit'].sudo().create({ 'attempted_login': 'demo@example.com', 'result': 'success', }) self.assertFalse(rec.failure_reason) def test_geo_state_internal_value(self): """`internal` is an accepted geo_lookup_state value (distinct from private_ip).""" rec = self.env['fusion.login.audit'].sudo().create({ 'attempted_login': 'demo@example.com', 'result': 'success', 'geo_lookup_state': 'internal', }) self.assertEqual(rec.geo_lookup_state, 'internal') def test_build_event_vals_with_no_request(self): """Without a live request, geo_lookup_state is 'internal'.""" ResUsers = self.env['res.users'] vals = ResUsers._fc_build_event_vals( result='success', attempted_login='cron@example.com', ) self.assertEqual(vals['result'], 'success') self.assertEqual(vals['attempted_login'], 'cron@example.com') self.assertEqual(vals['ip_address'], 'internal') self.assertEqual(vals['user_agent_raw'], '') self.assertEqual(vals['geo_lookup_state'], 'internal') self.assertEqual(vals['database'], self.env.cr.dbname) def test_build_event_vals_parses_user_agent(self): """Parser fills browser/os/device_type from a stub UA dict.""" ResUsers = self.env['res.users'] vals = ResUsers._fc_build_event_vals( result='success', attempted_login='ua@example.com', _override_ip='203.0.113.5', _override_ua='Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' 'AppleWebKit/537.36 Chrome/140.0 Safari/537.36', ) self.assertEqual(vals['ip_address'], '203.0.113.5') self.assertIn('Chrome', vals['browser']) self.assertIn('Windows', vals['os']) self.assertEqual(vals['device_type'], 'desktop') self.assertEqual(vals['geo_lookup_state'], 'pending') def test_build_event_vals_strips_password(self): """If a credential dict sneaks in, no password leaks into vals.""" ResUsers = self.env['res.users'] vals = ResUsers._fc_build_event_vals( result='failure', attempted_login='leak@example.com', failure_reason='bad_password', _credential={'login': 'leak@example.com', 'password': 'super-secret-pw', 'type': 'password'}, ) serialized = repr(vals) self.assertNotIn('super-secret-pw', serialized) self.assertEqual(vals['failure_reason'], 'bad_password')