Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ jobs:
run: |
docker run --rm \
--volume ${{ github.workspace }}:/${{ github.event.repository.name }} \
-e CI=true \
debian:${{ matrix.debian }} \
/bin/bash -c " \
apt-get update && \
Expand All @@ -32,7 +33,7 @@ jobs:
# Install from our source until they release their latest version to PyPI
pip3 install bluez-peripheral==0.1.8 --extra-index-url=https://packagecloud.io/pi-top/pypi/pypi/simple && \
pip3 install .[test] && \
pytest -v --cov=further_link && \
CI=true pytest -v --cov=further_link && \
coverage xml \
"

Expand Down
5 changes: 3 additions & 2 deletions further_link/runner/process_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,10 @@
# wait a little for the io tasks to complete to let them send
# output produced right before the process stopped
# but cancel them after a timeout if they don't stop themselves
await timeout(output_tasks, 1)
cleanup_timeout = float(os.environ.get("FURTHER_LINK_CLEANUP_TIMEOUT", "1"))
await timeout(output_tasks, cleanup_timeout)

Check warning on line 253 in further_link/runner/process_handler.py

View check run for this annotation

Codecov / codecov/patch

further_link/runner/process_handler.py#L252-L253

Added lines #L252 - L253 were not covered by tests
if hasattr(self, "ipc_tasks"):
await timeout(self.ipc_tasks, 0.1)
await timeout(self.ipc_tasks, cleanup_timeout * 0.1)

Check warning on line 255 in further_link/runner/process_handler.py

View check run for this annotation

Codecov / codecov/patch

further_link/runner/process_handler.py#L255

Added line #L255 was not covered by tests

await self._handle_process_end()

Expand Down
5 changes: 5 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
os.environ["FURTHER_LINK_WORK_DIR"] = WORKING_DIRECTORY
os.environ["FURTHER_LINK_MINISCREEN_PROJECTS_DIR"] = PROJECTS_DIR

# Set shorter timeouts for CI environments to prevent hanging tests
if os.environ.get("CI") == "true":
os.environ["FURTHER_LINK_CLEANUP_TIMEOUT"] = "0.2" # 200ms instead of default 1s
os.environ["FURTHER_LINK_TEST_TIMEOUT"] = "2" # 2s timeout for test operations


@pytest.fixture(autouse=True)
def create_working_directory():
Expand Down
24 changes: 22 additions & 2 deletions tests/e2e/helpers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import asyncio
import json
import os
from concurrent.futures import TimeoutError
from time import time

Expand Down Expand Up @@ -39,10 +40,29 @@ async def receive_data(ws, channel, data_key=None, data_value=None, process=""):
async def wait_for_data(
ws, channel, data_key=None, data_value=None, timeout=0, process=""
):
# Get timeout from environment if in CI mode
if os.environ.get("CI") == "true" and timeout == 0:
try:
timeout = int(os.environ.get("FURTHER_LINK_TEST_TIMEOUT", "2"))
except (ValueError, TypeError):
timeout = 2

start_time = round(time())
max_time = timeout if timeout > 0 else 120 # Set a maximum timeout for safety

while timeout <= 0 or (round(time()) - start_time) <= timeout:
# Prevent tests from hanging indefinitely
if round(time()) - start_time > max_time:
raise TimeoutError(f"Test operation timed out after {max_time}s")

try:
message = await ws.receive()
# Set a reasonable receive timeout to prevent indefinite hangs
receive_timeout = min(0.5, max_time - (round(time()) - start_time))
if receive_timeout <= 0:
raise TimeoutError("Receive timeout expired")

# Use wait_for to prevent indefinite blocking
message = await asyncio.wait_for(ws.receive(), timeout=receive_timeout)
m_type, m_data, m_process, m_client = parse_message(message.data)

assert m_process == process, f"{m_process} != {process}"
Expand Down Expand Up @@ -71,7 +91,7 @@ async def wait_for_data(
return await receive_data(ws, channel, data_key, remaining_data, process)
except (TimeoutError, asyncio.TimeoutError):
continue
raise TimeoutError
raise TimeoutError(f"Test operation timed out after {timeout}s")


async def send_formatted_bluetooth_message(
Expand Down
Loading