import sys from unittest.mock import patch import pytest sys.path.insert(0, "/home/wall/vacuum-wall") from webui.api.certs import bp as certs_bp from webui.api.dhcp import bp as dhcp_bp from webui.api.firewall import bp from webui.api.proxy import bp as proxy_bp from webui.api.wireguard import bp as wg_bp @pytest.fixture def client(): from flask import Flask app = Flask(__name__) app.register_blueprint(bp, url_prefix="/api/firewall") app.register_blueprint(dhcp_bp, url_prefix="/api/dhcp") app.register_blueprint(proxy_bp, url_prefix="/api/proxy") app.register_blueprint(certs_bp, url_prefix="/api/certs") app.register_blueprint(wg_bp, url_prefix="/api/wireguard") return app.test_client() class TestFirewallListZones: @patch("webui.api.firewall.get_active_zones") @patch("webui.api.firewall.get_available_zones") def test_success(self, mock_available, mock_active, client): mock_active.return_value = {"public": ["eth0"]} mock_available.return_value = ["public", "internal"] resp = client.get("/api/firewall/zones") assert resp.status_code == 200 data = resp.get_json() assert data["ok"] is True assert "public" in data["data"]["active"] @patch("webui.api.firewall.get_active_zones") def test_runtime_error(self, mock_active, client): mock_active.side_effect = RuntimeError("no sudo") resp = client.get("/api/firewall/zones") assert resp.status_code == 500 data = resp.get_json() assert data["ok"] is False class TestFirewallZoneDetails: @patch("webui.api.firewall.get_zone_info") @patch("webui.api.firewall.get_available_zones") def test_success(self, mock_available, mock_info, client): mock_available.return_value = ["public", "internal"] mock_info.return_value = {"name": "public", "services": ["ssh"]} resp = client.get("/api/firewall/zones/public") assert resp.status_code == 200 data = resp.get_json() assert data["data"]["name"] == "public" class TestFirewallCreateZone: @patch("webui.api.firewall.create_zone") @patch("webui.api.firewall.get_available_zones") def test_success(self, mock_zones, mock_create, client): mock_zones.return_value = ["public", "internal"] mock_create.return_value = None resp = client.post( "/api/firewall/zones", json={"name": "dmz", "target": "default"}, ) assert resp.status_code == 200 data = resp.get_json() assert data["ok"] is True def test_missing_name(self, client): resp = client.post( "/api/firewall/zones", json={"target": "default"}, ) assert resp.status_code == 400 data = resp.get_json() assert data["ok"] is False class TestFirewallDeleteZone: @patch("webui.api.firewall.delete_zone") @patch("webui.api.firewall.get_available_zones") def test_success(self, mock_zones, mock_delete, client): mock_zones.return_value = ["public", "dmz"] mock_delete.return_value = None resp = client.delete("/api/firewall/zones/dmz") assert resp.status_code == 200 @patch("webui.api.firewall.get_available_zones") def test_not_found(self, mock_zones, client): mock_zones.return_value = ["public"] resp = client.delete("/api/firewall/zones/dmz") assert resp.status_code == 404 class TestFirewallRichRules: @patch("webui.api.firewall.add_rich_rule") def test_add(self, mock_add, client): mock_add.return_value = None resp = client.post( "/api/firewall/rich-rules", json={ "zone": "public", "rule": 'rule family="ipv4" port protocol="tcp" port="443" accept', }, ) assert resp.status_code == 200 data = resp.get_json() assert data["ok"] is True def test_missing_fields(self, client): resp = client.post("/api/firewall/rich-rules", json={}) assert resp.status_code == 400 @patch("webui.api.firewall.get_rich_rules") def test_list(self, mock_list, client): mock_list.return_value = ["rule1", "rule2"] resp = client.get("/api/firewall/rich-rules/public") assert resp.status_code == 200 data = resp.get_json() assert data["data"] == ["rule1", "rule2"] class TestFirewallServices: @patch("webui.api.firewall.get_services") def test_list(self, mock_services, client): mock_services.return_value = ["ssh", "http", "dns"] resp = client.get("/api/firewall/services") assert resp.status_code == 200 assert resp.get_json()["data"] == ["ssh", "http", "dns"] class TestFirewallInterfaces: @patch("webui.api.firewall.get_interfaces") def test_list(self, mock_ifaces, client): mock_ifaces.return_value = ["eth0", "eth1"] resp = client.get("/api/firewall/interfaces") assert resp.status_code == 200 assert resp.get_json()["data"] == ["eth0", "eth1"] class TestFirewallMasquerade: @patch("webui.api.firewall.set_masquerade") def test_enable(self, mock_set, client): mock_set.return_value = None resp = client.post( "/api/firewall/masquerade", json={"zone": "internal", "enable": True}, ) assert resp.status_code == 200 def test_missing_fields(self, client): resp = client.post("/api/firewall/masquerade", json={}) assert resp.status_code == 400 class TestFirewallForwardPort: @patch("webui.api.firewall.add_forward_port") def test_add(self, mock_add, client): mock_add.return_value = None resp = client.post( "/api/firewall/forward-port", json={"zone": "public", "port": 443, "proto": "tcp"}, ) assert resp.status_code == 200 def test_missing_fields(self, client): resp = client.post( "/api/firewall/forward-port", json={"zone": "public"}, ) assert resp.status_code == 400 class TestDhcpConfig: @patch("webui.api.dhcp.get_config") def test_get(self, mock_get, client): mock_get.return_value = {"dhcp": {}, "dns": {}} resp = client.get("/api/dhcp/config") assert resp.status_code == 200 assert resp.get_json()["ok"] is True def test_post_invalid_body(self, client): resp = client.post( "/api/dhcp/config", data="not json", content_type="text/plain" ) data = resp.get_json() assert data is not None class TestDhcpStaticLease: @patch("webui.api.dhcp.add_static_lease") def test_add(self, mock_add, client): mock_add.return_value = None resp = client.post( "/api/dhcp/static-lease", json={"mac": "AA:BB:CC", "ip": "10.0.0.5"}, ) assert resp.status_code == 200 def test_missing_mac(self, client): resp = client.post("/api/dhcp/static-lease", json={"ip": "10.0.0.5"}) assert resp.status_code == 400 @patch("webui.api.dhcp.remove_static_lease") @patch("webui.api.dhcp.get_config") def test_remove(self, mock_get, mock_remove, client): mock_get.return_value = { "dhcp": {"static_leases": [{"mac": "AA:BB:CC", "ip": "10.0.0.5"}]} } mock_remove.return_value = None resp = client.delete("/api/dhcp/static-lease?mac=AA:BB:CC") assert resp.status_code == 200 @patch("webui.api.dhcp.get_config") def test_remove_not_found(self, mock_get, client): mock_get.return_value = {"dhcp": {"static_leases": []}} resp = client.delete("/api/dhcp/static-lease?mac=AA:BB:CC") assert resp.status_code == 404 def test_remove_missing_mac(self, client): resp = client.delete("/api/dhcp/static-lease") assert resp.status_code == 400 class TestDhcpDnsRecord: @patch("webui.api.dhcp.add_dns_record") def test_add(self, mock_add, client): mock_add.return_value = None resp = client.post( "/api/dhcp/dns-record", json={"name": "host.local", "address": "10.0.0.10"}, ) assert resp.status_code == 200 def test_missing_fields(self, client): resp = client.post("/api/dhcp/dns-record", json={}) assert resp.status_code == 400 class TestProxyDomains: @patch("webui.api.proxy.get_domains") def test_list(self, mock_get, client): mock_get.return_value = [] resp = client.get("/api/proxy/domains") assert resp.status_code == 200 @patch("webui.api.proxy.add_domain") def test_add(self, mock_add, client): mock_add.return_value = None resp = client.post( "/api/proxy/domains", json={"domain": "ex.com", "backend_host": "10.0.0.1", "backend_port": 80}, ) assert resp.status_code == 200 def test_add_missing_domain(self, client): resp = client.post("/api/proxy/domains", json={}) assert resp.status_code == 400 class TestProxyApply: @patch("webui.api.proxy.apply") def test_apply(self, mock_apply, client): mock_apply.return_value = None resp = client.post("/api/proxy/apply") assert resp.status_code == 200 class TestCertsList: @patch("webui.api.certs.list_certs") def test_list(self, mock_list, client): mock_list.return_value = [] resp = client.get("/api/certs/list") assert resp.status_code == 200 @patch("webui.api.certs.get_cert_info") def test_details_not_found(self, mock_info, client): mock_info.side_effect = ValueError("not found") resp = client.get("/api/certs/example.com") assert resp.status_code == 404 class TestCertsIssue: def test_missing_domain(self, client): resp = client.post("/api/certs/issue", json={}) assert resp.status_code == 400 class TestCertsEmail: def test_missing_email(self, client): resp = client.post("/api/certs/email", json={}) assert resp.status_code == 400 class TestWireguardConfig: @patch("webui.api.wireguard.get_config") def test_get(self, mock_get, client): mock_get.return_value = { "interface": {"name": "wg0", "private_key": "secret"}, "peers": {}, } resp = client.get("/api/wireguard/config") data = resp.get_json() assert data["ok"] is True assert "private_key" not in data["data"]["interface"] @patch("webui.api.wireguard.save_config") def test_post(self, mock_save, client): mock_save.return_value = None resp = client.post("/api/wireguard/config", json={"peers": {}}) assert resp.status_code == 200 class TestWireguardPeers: @patch("webui.api.wireguard.get_peers") def test_list(self, mock_get, client): mock_get.return_value = [] resp = client.get("/api/wireguard/peers") assert resp.status_code == 200 @patch("webui.api.wireguard.add_peer") def test_add(self, mock_add, client): mock_add.return_value = {"public_key": "pub", "private_key": "priv"} resp = client.post( "/api/wireguard/add-peer", json={"name": "client1"}, ) data = resp.get_json() assert data["ok"] is True assert "private_key" not in data["data"] def test_add_missing_name(self, client): resp = client.post("/api/wireguard/add-peer", json={}) assert resp.status_code == 400 class TestWireguardInitialize: @patch("webui.api.wireguard.initialize") def test_initialize(self, mock_init, client): mock_init.return_value = { "interface": {"name": "wg0", "private_key": "priv"}, "peers": {}, } resp = client.post("/api/wireguard/initialize") data = resp.get_json() assert data["ok"] is True assert data["data"] is None class TestWireguardGenerateClient: def test_missing_name(self, client): resp = client.post("/api/wireguard/generate-client", json={}) assert resp.status_code == 400 class TestWireguardStatus: @patch("webui.api.wireguard.status") def test_get(self, mock_status, client): mock_status.return_value = {"up": True, "interface": {}, "peers": []} resp = client.get("/api/wireguard/status") assert resp.status_code == 200 class TestResponseHelpers: @patch("webui.api.firewall.get_active_zones") @patch("webui.api.firewall.get_available_zones") def test_error_response_format(self, mock_a, mock_b, client): mock_a.side_effect = RuntimeError("fail") resp = client.get("/api/firewall/zones") data = resp.get_json() assert "error" in data assert "ok" in data assert data["ok"] is False