Skip to content

Commit

Permalink
tests: Add HTTP/HTTPS Proxy Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
holesch committed Apr 14, 2024
1 parent 71a0881 commit 8994eb7
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 15 deletions.
6 changes: 5 additions & 1 deletion .github/workflows/on-push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,11 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install qemu-system
sudo apt-get install \
qemu-system \
openssl \
tinyproxy \
;
pip install .[test]
- name: Allow kvm usage
run: |
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
/scripts/_vmctl/img/
/dist/
/doc/_build
/tests/.cache/
/.coverage
8 changes: 5 additions & 3 deletions not_my_board/_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ class ProtocolError(Exception):


class Client:
def __init__(self, ca_files=None):
def __init__(self, ca_files=None, proxies=None):
self._ssl_ctx = ssl.create_default_context()
if ca_files:
for ca_file in ca_files:
self._ssl_ctx.load_verify_locations(cafile=ca_file)

if proxies is None:
proxies = urllib.request.getproxies()
self._proxies = {
scheme: self._parse_url(url)
for scheme, url in urllib.request.getproxies().items()
scheme: self._parse_url(url) for scheme, url in proxies.items()
}

async def get_json(self, url):
Expand Down
13 changes: 2 additions & 11 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import not_my_board._util as util

from .util import ClientVM, ExporterVM, HubVM, VMs
from .util import ClientVM, ExporterVM, HubVM, VMs, wait_for_ports


@pytest.fixture(scope="session")
Expand All @@ -19,16 +19,7 @@ def event_loop():
@pytest.fixture(scope="session")
async def vms():
async with HubVM() as hub:
while True:
try:
async with util.connect("127.0.0.1", 5001):
pass
async with util.connect("127.0.0.1", 5002):
pass
except ConnectionRefusedError:
await asyncio.sleep(0.1)
continue
break
await wait_for_ports(5001, 5002)
async with ExporterVM() as exporter:
async with ClientVM() as client:
await util.run_concurrently(
Expand Down
79 changes: 79 additions & 0 deletions tests/test_http.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import pathlib

import pytest

import not_my_board._http as http

from .util import sh, sh_task, wait_for_ports

project_dir = pathlib.Path(__file__).parents[1]


@pytest.fixture(scope="session")
async def tinyproxy():
conf = project_dir / "tests/tinyproxy.conf"
async with sh_task(f"tinyproxy -d -c {conf}", "tinyproxy"):
await wait_for_ports(8888)
yield "http://127.0.0.1:8888"


async def test_proxy_connect(tinyproxy):
async with sh_task("not-my-board hub", "hub"):
await wait_for_ports(2092)

client = http.Client(proxies={"http": tinyproxy})
response = await client.get_json("http://127.0.0.1:2092/api/v1/places")
assert response == {"places": []}


async def test_proxy_connect_https(tinyproxy):
root_key = project_dir / "tests/.cache/not-my-board-root-ca.key"
root_cert = project_dir / "tests/.cache/not-my-board-root-ca.crt"
key_file = project_dir / "tests/.cache/not-my-board.key"
cert_file = project_dir / "tests/.cache/not-my-board.crt"
if not key_file.exists():
key_file.parent.mkdir(exist_ok=True)
await sh(
"openssl req "
"-x509 "
"-newkey ec "
"-pkeyopt ec_paramgen_curve:secp384r1 "
"-days 365000 "
"-nodes "
f"-keyout {root_key} "
f"-out {root_cert} "
"-subj '/CN=not-my-board-root-ca'"
)
hostname = "hub.local"
await sh(
"openssl req "
"-x509 "
f"-CA {root_cert} "
f"-CAkey {root_key} "
"-newkey ec "
"-pkeyopt ec_paramgen_curve:prime256v1 "
"-days 365000 "
"-nodes "
f"-keyout {key_file} "
f"-out {cert_file} "
f"-subj '/CN={hostname}' "
f"-addext 'subjectAltName=DNS:{hostname},DNS:*.{hostname},IP:127.0.0.1' "
"-addext 'basicConstraints=CA:FALSE' "
"-addext 'keyUsage=digitalSignature,keyEncipherment' "
"-addext 'extendedKeyUsage=serverAuth'"
)

async with sh_task(
(
"uvicorn --port 2092 "
f"--ssl-keyfile {key_file} "
f"--ssl-certfile {cert_file} "
"not_my_board:asgi_app"
),
"hub",
):
await wait_for_ports(2092)

client = http.Client(ca_files=[root_cert], proxies={"https": tinyproxy})
response = await client.get_json("https://127.0.0.1:2092/api/v1/places")
assert response == {"places": []}
4 changes: 4 additions & 0 deletions tests/tinyproxy.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Port 8888
Listen 127.0.0.1
Timeout 600
Allow 127.0.0.1
13 changes: 13 additions & 0 deletions tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,16 @@ async def _log_output(stream, cmd, prefix):
async for line in stream:
sys.stderr.buffer.write(prefix + line)
sys.stderr.buffer.flush()


async def wait_for_ports(*ports, timeout=7):
async with util.timeout(timeout):
while True:
try:
for port in ports:
async with util.connect("127.0.0.1", port):
pass
except ConnectionRefusedError:
await asyncio.sleep(0.1)
continue
break

0 comments on commit 8994eb7

Please sign in to comment.