From 2382e178300b27ce17319dd39e21c857ad4f2f44 Mon Sep 17 00:00:00 2001 From: Fredrick Amnehagen Date: Fri, 6 Feb 2026 00:46:16 +0100 Subject: [PATCH] test: add comprehensive unit tests for all managers --- tests/unit/test_cloudflare_logic.py | 55 +++++++++++++++++++++++++++++ tests/unit/test_dns_logic.py | 46 ++++++++++++++++++++++++ tests/unit/test_samba_logic.py | 36 +++++++++++++++++++ 3 files changed, 137 insertions(+) create mode 100644 tests/unit/test_cloudflare_logic.py create mode 100644 tests/unit/test_dns_logic.py create mode 100644 tests/unit/test_samba_logic.py diff --git a/tests/unit/test_cloudflare_logic.py b/tests/unit/test_cloudflare_logic.py new file mode 100644 index 0000000..242295d --- /dev/null +++ b/tests/unit/test_cloudflare_logic.py @@ -0,0 +1,55 @@ +import pytest +from unittest.mock import MagicMock, patch +from infra_cli.cloudflare import CloudflareManager + +class MockConfig: + def get(self, key, default=None): + if key == 'cloudflare.token': return 'test-token' + return default + +@patch('infra_cli.cloudflare.requests') +def test_cloudflare_zone_id_retrieval(mock_requests): + # Mock API response + mock_res = MagicMock() + mock_res.json.return_value = { + "success": True, + "result": [{"id": "zone-123"}] + } + mock_requests.get.return_value = mock_res + + mgr = CloudflareManager(MockConfig()) + zone_id = mgr.get_zone_id("example.com") + + assert zone_id == "zone-123" + mock_requests.get.assert_called_with( + "https://api.cloudflare.com/client/v4/zones?name=example.com", + headers={"Authorization": "Bearer test-token", "Content-Type": "application/json"} + ) + +@patch('infra_cli.cloudflare.requests') +def test_cloudflare_update_logic(mock_requests): + mgr = CloudflareManager(MockConfig()) + mgr.add_domain("example.com") + + # Mock external IP check + mock_requests.get.return_value.text = "1.2.3.4" + + # Mock Zone ID and DNS Records + with patch.object(CloudflareManager, 'get_zone_id', return_value="zone-123"): + # Mock finding existing A record + mock_get_records = MagicMock() + mock_get_records.json.return_value = { + "result": [{"id": "rec-456", "content": "9.9.9.9", "proxied": True}] + } + + # Setup specific returns for consecutive calls + mock_requests.get.side_effect = [ + MagicMock(text="1.2.3.4"), # External IP + mock_get_records # List records + ] + + # Mock successful update + mock_requests.put.return_value.json.return_value = {"success": True} + + res = mgr.update_ddns() + assert "Updated to 1.2.3.4" in res diff --git a/tests/unit/test_dns_logic.py b/tests/unit/test_dns_logic.py new file mode 100644 index 0000000..f1f4fca --- /dev/null +++ b/tests/unit/test_dns_logic.py @@ -0,0 +1,46 @@ +import pytest +from unittest.mock import MagicMock, patch +from infra_cli.dns import DNSManager + +class MockConfig: + def get_node(self, name): + return {"host": "10.32.2.1", "pass": "secret"} + def get(self, key, default=None): + if key == 'proxmox.dnsmasq_lxc_id': return '11209' + return default + +@patch('infra_cli.dns.SSHClient') +def test_dns_add_host_logic(mock_ssh): + mock_instance = mock_ssh.return_value + + # Calls in order: + # 1. touch (success 0) + # 2. grep (fail 1, not found) + # 3. echo (success 0) + # 4. test (success 0) + # 5. reload (success 0) + res_touch = MagicMock(returncode=0) + res_mac_check = MagicMock(returncode=1) + res_echo = MagicMock(returncode=0) + res_test = MagicMock(returncode=0) + res_reload = MagicMock(returncode=0) + + mock_instance.run.side_effect = [res_touch, res_mac_check, res_echo, res_test, res_reload] + + mgr = DNSManager(MockConfig()) + mgr.add_host("aa:bb:cc:11:22:33", "10.32.70.100", "test-host") + + # Verify the commands called + calls = [str(c) for c in mock_instance.run.call_args_list] + assert any("dhcp-host=aa:bb:cc:11:22:33,test-host,10.32.70.100" in c for c in calls) + +@patch('infra_cli.dns.SSHClient') +def test_dns_duplicate_mac_prevention(mock_ssh): + mock_instance = mock_ssh.return_value + # 1. touch (0) + # 2. grep (0, exists) + mock_instance.run.side_effect = [MagicMock(returncode=0), MagicMock(returncode=0)] + + mgr = DNSManager(MockConfig()) + with pytest.raises(ValueError, match="already exists"): + mgr.add_host("aa:bb:cc:11:22:33", "10.32.70.100", "test-host") \ No newline at end of file diff --git a/tests/unit/test_samba_logic.py b/tests/unit/test_samba_logic.py new file mode 100644 index 0000000..4d5a78a --- /dev/null +++ b/tests/unit/test_samba_logic.py @@ -0,0 +1,36 @@ +import pytest +from unittest.mock import MagicMock, patch +from infra_cli.samba import SambaManager + +class MockConfig: + def get_node(self, name): + return {"host": "10.32.2.1", "pass": "secret"} + def get(self, key, default=None): + mapping = { + 'samba.host': '10.32.1.101', + 'samba.user': 'Administrator', + 'samba.domain': 'FE.LOOPAWARE.COM' + } + return mapping.get(key, default) + +@patch('infra_cli.samba.SSHClient') +def test_samba_add_user_logic(mock_ssh): + mock_instance = mock_ssh.return_value + mock_instance.run.return_value.returncode = 0 + + mgr = SambaManager(MockConfig()) + mgr.add_user("testuser", "testpass") + + assert any("samba-tool user create testuser testpass" in str(call) + for call in mock_instance.run.call_args_list) + +@patch('infra_cli.samba.SSHClient') +def test_samba_add_to_group_logic(mock_ssh): + mock_instance = mock_ssh.return_value + mock_instance.run.return_value.returncode = 0 + + mgr = SambaManager(MockConfig()) + mgr.add_to_group("testgroup", "testuser") + + assert any("samba-tool group addmembers testgroup testuser" in str(call) + for call in mock_instance.run.call_args_list) \ No newline at end of file