Skip to content

Commit

Permalink
Fix http request handle issue (#42)
Browse files Browse the repository at this point in the history
* Fix http request handle issue

* Add docker tests and coverage upload only on ubuntu
  • Loading branch information
Ananto30 authored Oct 22, 2023
1 parent 81d5129 commit 042009b
Show file tree
Hide file tree
Showing 13 changed files with 117 additions and 15 deletions.
12 changes: 9 additions & 3 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,21 @@ jobs:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.8", "3.9", "3.10"]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Generate Report
timeout-minutes: 10
cache: pip
- name: Install dependencies
timeout-minutes: 5
run: |
python -m pip install pip==23.3.1
pip install -r tests/requirements.txt
- name: Run tests
timeout-minutes: 5
run: |
make test
- name: Upload Coverage to Codecov
if: ${{ matrix.os == 'ubuntu-latest' && matrix.python-version == '3.9' }}
uses: codecov/codecov-action@v3
9 changes: 9 additions & 0 deletions Dockerfile.test.py310
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM python:3.10-slim

COPY tests/requirements.txt .
RUN pip install -r requirements.txt

COPY zero ./zero
COPY tests ./tests

CMD ["pytest", "tests", "--cov=zero", "--cov-report=term-missing", "-vv"]
9 changes: 9 additions & 0 deletions Dockerfile.test.py38
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM python:3.8-slim

COPY tests/requirements.txt .
RUN pip install -r requirements.txt

COPY zero ./zero
COPY tests ./tests

CMD ["pytest", "tests", "--cov=zero", "--cov-report=term-missing", "-vv"]
9 changes: 9 additions & 0 deletions Dockerfile.test.py39
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
FROM python:3.9-slim

COPY tests/requirements.txt .
RUN pip install -r requirements.txt

COPY zero ./zero
COPY tests ./tests

CMD ["pytest", "tests", "--cov=zero", "--cov-report=term-missing", "-vv"]
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,18 @@ setup:
)

test:
python3 -m pytest tests --cov=zero --cov-report=term-missing -vv
python3 -m pytest tests --cov=zero --cov-report=term-missing -vv --durations=10 --timeout=280

docker-test:
docker build -t zero-test -f Dockerfile.test.py38 .
docker run --rm zero-test
docker rmi zero-test
docker build -t zero-test -f Dockerfile.test.py39 .
docker run --rm zero-test
docker rmi zero-test
docker build -t zero-test -f Dockerfile.test.py310 .
docker run --rm zero-test
docker rmi zero-test

format:
isort . --profile black -l 99
Expand Down
3 changes: 3 additions & 0 deletions tests/functional/single_server/client_generation_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ def error(self, msg: str) -> str:
def msgspec_struct(self, start: datetime.datetime) -> Message:
return self._zero_client.call("msgspec_struct", start)
def send_bytes(self, msg: bytes) -> bytes:
return self._zero_client.call("send_bytes", msg)
def echo(self, msg: str) -> str:
return self._zero_client.call("echo", msg)
Expand Down
28 changes: 28 additions & 0 deletions tests/functional/single_server/client_server_test.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import datetime

import pytest
import requests

import zero.error
from zero import AsyncZeroClient, ZeroClient
Expand Down Expand Up @@ -100,3 +101,30 @@ def test_msgspec_struct():
msg = zero_client.call("msgspec_struct", now, return_type=Message)
assert msg.msg == "hello world"
assert msg.start_time == now


def test_send_bytes():
zero_client = ZeroClient(server.HOST, server.PORT)
msg = zero_client.call("send_bytes", b"hello")
assert msg == b"hello"


def test_send_http_request():
with pytest.raises(requests.exceptions.ReadTimeout):
requests.get(f"http://{server.HOST}:{server.PORT}", timeout=2)


def test_server_works_after_multiple_http_requests():
"""Because of this issue https://github.com/Ananto30/zero/issues/41"""
try:
requests.get(f"http://{server.HOST}:{server.PORT}", timeout=2)
requests.get(f"http://{server.HOST}:{server.PORT}", timeout=2)
requests.get(f"http://{server.HOST}:{server.PORT}", timeout=2)
requests.get(f"http://{server.HOST}:{server.PORT}", timeout=2)
requests.get(f"http://{server.HOST}:{server.PORT}", timeout=2)
requests.get(f"http://{server.HOST}:{server.PORT}", timeout=2)
except requests.exceptions.ReadTimeout:
pass
zero_client = ZeroClient(server.HOST, server.PORT)
msg = zero_client.call("hello_world", "")
assert msg == "hello world"
15 changes: 13 additions & 2 deletions tests/functional/single_server/client_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,26 @@ async def test_concurrent_divide():
(534, 11): 48,
}

total_pass = 0

async def divide(semaphore, req):
async with semaphore:
assert await async_client.call("divide", req, timeout=500) == req_resp[req]
try:
assert (
await async_client.call("divide", req, timeout=500) == req_resp[req]
)
nonlocal total_pass
total_pass += 1
except zero.error.TimeoutException:
pass

semaphore = asyncio.BoundedSemaphore(3)
semaphore = asyncio.BoundedSemaphore(4)

tasks = [divide(semaphore, req) for req in req_resp]
await asyncio.gather(*tasks)

assert total_pass > 2


def test_server_error():
client = ZeroClient(server.HOST, server.PORT)
Expand Down
5 changes: 5 additions & 0 deletions tests/functional/single_server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ def msgspec_struct(start: datetime.datetime) -> Message:
return Message(msg="hello world", start_time=start)


@app.register_rpc
def send_bytes(msg: bytes) -> bytes:
return msg


def run(port):
print("Starting server on port", port)
app.register_rpc(echo)
Expand Down
4 changes: 3 additions & 1 deletion tests/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,6 @@ pytest
pytest-cov
PyJWT
pytest-asyncio
tornado>=6.1
tornado>=6.1
requests
pytest-timeout
10 changes: 5 additions & 5 deletions tests/unit/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing import Any, Tuple
from unittest.mock import patch

# import pytest
import zmq

from zero import ZeroServer
Expand Down Expand Up @@ -177,10 +178,7 @@ def add(msg: Tuple[int, int]) -> int:
return msg[0] + msg[1]

with self.assertRaises(ValueError):

@server.register_rpc
def add(msg: Tuple[int, int]) -> int:
return msg[0] + msg[1]
server.register_rpc(add)

def test_register_rpc_with_invalid_input_type(self):
server = ZeroServer()
Expand Down Expand Up @@ -216,7 +214,7 @@ class Message:

@server.register_rpc
def add(msg: Message) -> Message:
return Message("1")
return Message()

def test_server_run(self):
server = ZeroServer()
Expand All @@ -239,6 +237,8 @@ def add(msg: Tuple[int, int]) -> int:
server._broker.backend, # type: ignore
)

# @pytest.mark.skipif(sys.platform == "win32", reason="Does not run on windows")
# @pytest.mark.skip
def test_server_run_keyboard_interrupt(self):
server = ZeroServer()

Expand Down
10 changes: 7 additions & 3 deletions zero/client_server/worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from zero import config
from zero.codegen.codegen import CodeGen
from zero.encoder.protocols import Encoder
from zero.error import SERVER_PROCESSING_ERROR
from zero.zero_mq.factory import get_worker


Expand Down Expand Up @@ -40,10 +41,13 @@ def process_message(data: bytes) -> Optional[bytes]:
req_id, func_name, msg = decoded
response = self.handle_msg(func_name, msg)
return self._encoder.encode([req_id, response])
except Exception as inner_exc: # pylint: disable=broad-except
except (
Exception
) as inner_exc: # pragma: no cover pylint: disable=broad-except
logging.exception(inner_exc)
# TODO what to return
return None
return self._encoder.encode(
["", {"__zerror__server_exception": SERVER_PROCESSING_ERROR}]
)

worker = get_worker(config.ZEROMQ_PATTERN, worker_id)
try:
Expand Down
5 changes: 5 additions & 0 deletions zero/error.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
SERVER_PROCESSING_ERROR = (
"server cannot process message, check server logs for more details"
)


class ZeroException(Exception):
pass

Expand Down

0 comments on commit 042009b

Please sign in to comment.