diff --git a/README.md b/README.md index 42de18d..4160a98 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,21 @@ infra cert renew - **Input Validation:** All IPs, MACs, and Ports are validated before execution. - **Pre-flight Checks:** The CLI verifies SSH connectivity to nodes before attempting changes. +## Pro-Tips for Developers + +### Environment Selection +- **Staging:** Use `--node la-vmh-07` for experiments. +- **Public Production:** Use `--node la-vmh-12`. +- **Private Production:** Use `--node la-vmh-13`. + +### Programmatic Integration +The CLI is designed to be consumed by other scripts. Use the `--config` flag or `INFRA_CONFIG` environment variable to point to your configuration. + +```bash +# Get just the IP for scripting +NEW_IP=$(infra ip next-free) +``` + ## Development ### Running Tests diff --git a/tests/unit/test_cloudflare_logic.py b/tests/unit/test_cloudflare_logic.py index 242295d..8062347 100644 --- a/tests/unit/test_cloudflare_logic.py +++ b/tests/unit/test_cloudflare_logic.py @@ -5,11 +5,11 @@ from infra_cli.cloudflare import CloudflareManager class MockConfig: def get(self, key, default=None): if key == 'cloudflare.token': return 'test-token' + if key == 'cloudflare.ddns_state_file': return '/tmp/test_ddns.json' 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, @@ -21,35 +21,38 @@ def test_cloudflare_zone_id_retrieval(mock_requests): 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): + # Setup state file cleanup + state_file = '/tmp/test_ddns.json' + if os.path.exists(state_file): os.remove(state_file) + mgr = CloudflareManager(MockConfig()) mgr.add_domain("example.com") - # Mock external IP check - mock_requests.get.return_value.text = "1.2.3.4" + def mocked_get(url, **kwargs): + res = MagicMock() + if "checkip.amazonaws.com" in url: + res.text = "1.2.3.4" + elif "zones?name=" in url: + res.json.return_value = {"success": True, "result": [{"id": "zone-123"}]} + elif "dns_records" in url: + res.json.return_value = { + "result": [{"id": "rec-456", "content": "9.9.9.9", "proxied": True}] + } + return res + + mock_requests.get.side_effect = mocked_get - # 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 + # Mock PUT + mock_put_res = MagicMock() + mock_put_res.json.return_value = {"success": True} + mock_requests.put.return_value = mock_put_res + + res = mgr.update_ddns() + assert "Updated to 1.2.3.4" in res + + if os.path.exists(state_file): os.remove(state_file) + +import os \ No newline at end of file