Files
dns-sync/tests/test_npm_client.py
T

272 lines
7.6 KiB
Python

import os
import unittest
from unittest.mock import Mock, patch
from dns_sync.adapters import Endpoint
from dns_sync.config import AppConfig
from dns_sync.npm_client import NpmClient
class NpmClientEndpointTests(unittest.TestCase):
def config(self):
return AppConfig.from_env()
def test_default_client_uses_first_configured_endpoint(self):
with patch.dict(
os.environ,
{
"NPM_ENDPOINTS": "192.168.1.3,192.168.1.4:8081",
"DNS_TARGET_IP": "192.168.1.101",
"NPM_IDENTITY": "test@example.com",
"NPM_SECRET": "not-a-real-secret",
},
clear=True,
):
config = self.config()
with patch(
"dns_sync.npm_client.requests.Session.request"
) as request:
client = NpmClient(config)
request.assert_not_called()
self.assertEqual(client.api_url, "http://192.168.1.3:81/api")
def test_client_can_select_specific_configured_endpoint(self):
with patch.dict(
os.environ,
{
"NPM_ENDPOINTS": "192.168.1.3,192.168.1.4:8081",
"DNS_TARGET_IP": "192.168.1.101",
"NPM_IDENTITY": "test@example.com",
"NPM_SECRET": "not-a-real-secret",
},
clear=True,
):
config = self.config()
client = NpmClient(config, config.npm_endpoints[1])
self.assertEqual(
client.api_url,
"http://192.168.1.4:8081/api",
)
self.assertEqual(
client.endpoint.identity,
"npm://192.168.1.4:8081",
)
def test_client_rejects_non_npm_endpoint(self):
with patch.dict(
os.environ,
{
"PROXY_IP": "192.168.1.101",
"NPM_IDENTITY": "test@example.com",
"NPM_SECRET": "not-a-real-secret",
},
clear=True,
):
config = self.config()
endpoint = Endpoint("verizon", "192.168.1.1")
with self.assertRaisesRegex(RuntimeError, "npm endpoint"):
NpmClient(config, endpoint)
class NpmClientMutationTests(unittest.TestCase):
def client(self):
with patch.dict(
os.environ,
{
"NPM_ENDPOINTS": "192.168.1.3",
"DNS_TARGET_IP": "192.168.1.101",
"NPM_IDENTITY": "test@example.com",
"NPM_SECRET": "not-a-real-secret",
},
clear=True,
):
config = AppConfig.from_env()
return NpmClient(
config,
config.npm_endpoints[0],
)
@staticmethod
def response(data):
response = Mock()
response.json.return_value = data
return response
def test_gets_one_proxy_host_by_endpoint_local_id(self):
client = self.client()
client.get_json = Mock(
return_value={
"id": 12,
"domain_names": ["app.example.com"],
}
)
result = client.proxy_host("12")
client.get_json.assert_called_once_with(
"/nginx/proxy-hosts/12"
)
self.assertEqual(result["id"], 12)
def test_creates_proxy_host_with_json_payload(self):
client = self.client()
payload = {
"domain_names": ["app.example.com"],
"forward_scheme": "http",
"forward_host": "192.168.1.20",
"forward_port": 8080,
"certificate_id": 67,
}
client.request = Mock(
return_value=self.response({"id": 12})
)
result = client.create_proxy_host(payload)
client.request.assert_called_once_with(
"POST",
"/nginx/proxy-hosts",
expected_status=201,
json=payload,
)
self.assertEqual(result["id"], 12)
def test_updates_proxy_host_with_json_payload(self):
client = self.client()
payload = {
"forward_host": "192.168.1.30",
}
client.request = Mock(
return_value=self.response({"id": 12})
)
result = client.update_proxy_host(
"12",
payload,
)
client.request.assert_called_once_with(
"PUT",
"/nginx/proxy-hosts/12",
expected_status=200,
json=payload,
)
self.assertEqual(result["id"], 12)
def test_gets_one_certificate_by_endpoint_local_id(self):
client = self.client()
client.get_json = Mock(
return_value={
"id": 67,
"domain_names": ["app.example.com"],
}
)
result = client.certificate("67")
client.get_json.assert_called_once_with(
"/nginx/certificates/67"
)
self.assertEqual(result["id"], 67)
def test_creates_certificate_metadata_with_json_payload(self):
client = self.client()
payload = {
"provider": "other",
"nice_name": "cluster copy",
"domain_names": ["app.example.com"],
"meta": {
"cluster_managed": True,
},
}
client.request = Mock(
return_value=self.response({"id": 84})
)
result = client.create_certificate(payload)
client.request.assert_called_once_with(
"POST",
"/nginx/certificates",
expected_status=201,
json=payload,
)
self.assertEqual(result["id"], 84)
def test_uploads_certificate_material_as_multipart(self):
client = self.client()
client.request = Mock(
return_value=self.response({"id": 84})
)
result = client.upload_certificate(
"84",
certificate=b"CERTIFICATE",
certificate_key=b"PRIVATE-KEY",
intermediate_certificate=b"INTERMEDIATE",
)
client.request.assert_called_once_with(
"POST",
"/nginx/certificates/84/upload",
expected_status=200,
files={
"certificate": (
"certificate.pem",
b"CERTIFICATE",
),
"certificate_key": (
"certificate_key.pem",
b"PRIVATE-KEY",
),
"intermediate_certificate": (
"intermediate_certificate.pem",
b"INTERMEDIATE",
),
},
)
self.assertEqual(result["id"], 84)
def test_certificate_upload_requires_both_required_parts(self):
client = self.client()
with self.assertRaisesRegex(
RuntimeError,
"requires certificate data",
):
client.upload_certificate(
"84",
certificate=b"",
certificate_key=b"PRIVATE-KEY",
)
with self.assertRaisesRegex(
RuntimeError,
"requires certificate key data",
):
client.upload_certificate(
"84",
certificate=b"CERTIFICATE",
certificate_key=b"",
)
def test_rejects_invalid_endpoint_local_ids(self):
client = self.client()
for local_id in ("", "abc", True, -1):
with self.subTest(local_id=local_id):
with self.assertRaisesRegex(
RuntimeError,
"id is invalid",
):
client.certificate(local_id)
if __name__ == "__main__":
unittest.main()