furtka-gateway/tests/test_wgeasy.py

122 lines
3.9 KiB
Python
Raw Normal View History

import json
import threading
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import pytest
from control_plane.wgeasy import WgEasyClient, WgEasyError
FAKE_CONF = """[Interface]
PrivateKey = client-private-key==
Address = 10.8.0.5/32
DNS = 1.1.1.1
[Peer]
PublicKey = server-public-key==
Endpoint = gateway.example.com:51820
AllowedIPs = 10.8.0.0/24
PersistentKeepalive = 25
"""
class FakeWgEasyHandler(BaseHTTPRequestHandler):
def log_message(self, format, *args):
pass
def _json(self, status, payload):
body = json.dumps(payload).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def do_POST(self):
self.server.requests.append(("POST", self.path))
if self.path == "/api/auth/password":
self.send_response(200)
self.send_header("Set-Cookie", "wg-easy-session=abc123; Path=/; HttpOnly")
self.send_header("Content-Length", "0")
self.end_headers()
return
if self.path == "/api/client":
self._json(200, {"success": True, "clientId": "client-1"})
return
self._json(404, {"error": "not found"})
def do_GET(self):
self.server.requests.append(("GET", self.path))
if self.path == "/api/client/client-1":
self._json(200, {"id": "client-1", "publicKey": "client-public-key=="})
return
if self.path == "/api/client/client-1/configuration":
body = FAKE_CONF.encode()
self.send_response(200)
self.send_header("Content-Type", "application/octet-stream")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
return
self._json(404, {"error": "not found"})
def do_DELETE(self):
self.server.requests.append(("DELETE", self.path))
if self.path == "/api/client/client-1":
self._json(200, {"success": True})
return
self._json(404, {"error": "not found"})
@pytest.fixture
def fake_wgeasy():
server = ThreadingHTTPServer(("127.0.0.1", 0), FakeWgEasyHandler)
server.requests = []
thread = threading.Thread(target=server.serve_forever, daemon=True)
thread.start()
try:
yield server
finally:
server.shutdown()
thread.join()
def _client(server):
port = server.server_address[1]
return WgEasyClient(f"http://127.0.0.1:{port}", "admin", "hunter2")
def test_create_client_logs_in_and_parses_configuration(fake_wgeasy):
client = _client(fake_wgeasy)
peer = client.create_client("box-1")
assert peer["id"] == "client-1"
assert peer["public_key"] == "client-public-key=="
assert peer["private_key"] == "client-private-key=="
assert peer["address"] == "10.8.0.5/32"
assert peer["server_public_key"] == "server-public-key=="
assert peer["endpoint"] == "gateway.example.com:51820"
assert peer["allowed_ips"] == "10.8.0.0/24"
methods_and_paths = [(m, p) for m, p in fake_wgeasy.requests]
assert ("POST", "/api/auth/password") in methods_and_paths
assert ("POST", "/api/client") in methods_and_paths
def test_delete_client_swallows_not_found(fake_wgeasy):
client = _client(fake_wgeasy)
client.delete_client("does-not-exist") # 404 from fake server — must not raise
def test_delete_client_calls_endpoint(fake_wgeasy):
client = _client(fake_wgeasy)
client.delete_client("client-1")
assert ("DELETE", "/api/client/client-1") in [(m, p) for m, p in fake_wgeasy.requests]
def test_bad_endpoint_raises_wgeasy_error(fake_wgeasy):
port = fake_wgeasy.server_address[1]
client = WgEasyClient(f"http://127.0.0.1:{port}", "admin", "hunter2")
with pytest.raises(WgEasyError):
client._authed_request("GET", "/api/does-not-exist")