Problem running pytests in GitHub environment
writeson opened this issue · 2 comments
I have a FastAPI application that's using httpx, and I'm having trouble getting the pytests to run successfully in the GitHub environment when I push the code. The tests run fine when run in a local Docker container.
Here's my Dockerfile
FROM python:3.9.7-slim
WORKDIR /app/
ENV PYTHONPATH "${PYTHONPATH}:/"
COPY requirements.txt .
RUN pip install -r requirements.txt
CMD ["uvicorn", "main:app", "--reload", "--host", "0.0.0.0"]
And here's the requirements.txt
file it uses to get the modules the application needs:
fastapi==0.82.0
uvicorn==0.18.3
pydantic==1.10.2
pylint==2.15.2
pytest==7.1.3
boto3==1.24.68
python-dotenv==0.21.0
pytest-mock==3.8.2
sseclient==0.0.27
pytest-asyncio==0.19.0
wheel==0.37.1
httpx==0.23.0
pytest-httpx==0.21.0
pytest-trio==0.7.0
Here's the .github/workflows/unit-tests.yml
file that runs the tests in the GitHub environment:
name: unit-tests
on: [push]
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
ref: ${{ github.event.inputs.branch_name }}
- name: Set up Python 3.9.x
uses: actions/setup-python@v1
with:
python-version: 3.9.x
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install fastapi==0.82.0
pip install pydantic==1.10.2
pip install pytest==7.1.3
pip install boto3==1.24.68
pip install python-dotenv==0.21.0
pip install pytest-mock==3.8.2
pip install sseclient==0.0.27
pip install pytest-asyncio==0.19.0
pip install httpx==0.23.0
pip install pytest-httpx==0.21.0
pip install pytest-cov==4.0.0
pip install pytest-trio==0.7.0
- name: Running unit tests
run: |
pytest -v --cov=app tests/unit/ --asyncio-mode=strict
And here's part of the errors generated when run in the GitHub environment:
Run pytest --cov=app tests/unit/ --asyncio-mode=strict
============================= test session starts ==============================
platform linux -- Python 3.9.14, pytest-7.1.3, pluggy-1.0.0
rootdir: /home/runner/work/integration-engine/integration-engine
plugins: httpx-0.21.0, anyio-3.[6](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:7).1, cov-4.0.0, asyncio-0.19.0, mock-3.8.2, trio-0.[7](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:8).0
asyncio: mode=strict
collected 69 items
tests/unit/test_main.py . [ 1%]
tests/unit/dependencies/test_validate_requests.py .. [ 4%]
tests/unit/helpers/test_agent_command_helper.py ....... [ 14%]
tests/unit/helpers/test_agent_message_helper.py .... [ 20%]
tests/unit/helpers/test_cognito_helper.py ssFF [ 26%]
tests/unit/helpers/test_mercure_helper.py ..... [ 33%]
tests/unit/helpers/test_pmb_helper.py .... [ 39%]
tests/unit/helpers/test_repository_helper.py ....... [ 49%]
tests/unit/repositories/test_agent_message_repository.py ... [ 53%]
tests/unit/repositories/test_agent_repository.py ..... [ 60%]
tests/unit/routers/test_agent_communication.py .............. [ [8](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:9)1%]
tests/unit/routers/test_agent_search.py .... [ 86%]
tests/unit/routers/test_authentication.py .. [ 8[9](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:10)%]
tests/unit/routers/test_diagnostics.py .. [ 92%]
tests/unit/routers/test_healthz.py .. [ 95%]
tests/unit/routers/test_registration.py ... [[10](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:11)0%]
=================================== FAILURES ===================================
____ test_get_token_with_invalid_credentials_returns_error_message[asyncio] ____
httpx_mock = <pytest_httpx._httpx_mock.HTTPXMock object at 0x7f9346b296d0>
@pytest.mark.anyio
async def test_get_token_with_invalid_credentials_returns_error_message(httpx_mock: HTTPXMock):
"""Test that get token with invalid credentials returns error message"""
mock_valid_response = {
"errorMessage": "test_error_message"
}
mock_user_auth_request = UserAuthenticationRequest(
username="test_invalid_username",
***
)
httpx_mock.add_response(json=mock_valid_response)
> response = await get_token(mock_user_auth_request)
tests/unit/helpers/test_cognito_helper.py:50:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
app/helpers/cognito_helper.py:37: in get_token
data = await call_cognito(url=url, body=body)
app/helpers/cognito_helper.py:59: in call_cognito
request = httpx.Request("GET", url=url, json=body)
/opt/hostedtoolcache/Python/3.9.[14](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:15)/x64/lib/python3.9/site-packages/httpx/_models.py:326: in __init__
self.url = URL(url)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <[AttributeError("'URL' object has no attribute '_uri_reference'") raised in repr()] URL object at 0x7f9346aa[23](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:24)70>
url = None, kwargs = {}
def __init__(
self, url: typing.Union["URL", str, RawURL] = "", **kwargs: typing.Any
) -> None:
if isinstance(url, (str, tuple)):
if isinstance(url, tuple):
raw_scheme, raw_host, port, raw_path = url
scheme = raw_scheme.decode("ascii")
host = raw_host.decode("ascii")
if host and ":" in host and host[0] != "[":
# it's an IPv6 address, so it should be enclosed in "[" and "]"
# ref: https://tools.ietf.org/html/rfc[27](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:28)[32](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:33)#section-2
# ref: https://tools.ietf.org/html/rfc[39](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:40)86#section-3.2.2
host = f"[{host}]"
port_str = "" if port is None else f":{port}"
path = raw_path.decode("ascii")
url = f"{scheme}://{host}{port_str}{path}"
try:
self._uri_reference = rfc3986.iri_reference(url).encode()
except rfc3986.exceptions.InvalidAuthority as exc:
raise InvalidURL(message=str(exc)) from None
if self.is_absolute_url:
# We don't want to normalize relative URLs, since doing so
# removes any leading `../` portion.
self._uri_reference = self._uri_reference.normalize()
elif isinstance(url, URL):
self._uri_reference = url._uri_reference
else:
> raise TypeError(
f"Invalid type for url. Expected str or httpx.URL, got {type(url)}: {url!r}"
)
E TypeError: Invalid type for url. Expected str or httpx.URL, got <class 'NoneType'>: None
/opt/hostedtoolcache/Python/3.9.14/x[64](https://github.com/rectanglehealth/integration-engine/actions/runs/3207285033/jobs/5242003697#step:5:65)/lib/python3.9/site-packages/httpx/_urls.py:102: TypeError
My apologies if this isn't the right forum to be asking this, but I'm at my wits end trying to resolve this. Any ideas, pointers or suggestions are welcome.
Hello @writeson ,
According to your stacktrace the issue comes from your code, the url you provide is None and obviously it makes no sense ;)
> response = await get_token(mock_user_auth_request)
tests/unit/helpers/test_cognito_helper.py:50:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
app/helpers/cognito_helper.py:37: in get_token
data = await call_cognito(url=url, body=body)
Colin-b,
Thanks for the response, I'll have to look into that as I thought the URL was coming from an environment variable, but maybe not in the GitHub environment.