Skip to content

Commit b1c0ed7

Browse files
committed
test: add integration tests
1 parent d0a208d commit b1c0ed7

File tree

3 files changed

+90
-12
lines changed

3 files changed

+90
-12
lines changed

.github/workflows/test.yml

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,14 @@ jobs:
4848
run: poetry install --no-interaction
4949

5050
- name: Run tests
51-
run: |
52-
poetry run pytest
51+
run: poetry run pytest
52+
53+
- name: Run integration tests
54+
env:
55+
BRING_USERNAME: ${{ secrets.BRING_TESTING_USERNAME}}
56+
BRING_PASSWORD: ${{ secrets.BRING_TESTING_PASSWORD}}
57+
BRING_LIST_NAME: Zuhause
58+
run: poetry run pytest tests/test_integration.py
5359

5460
validate-docker-image:
5561
runs-on: ubuntu-latest
@@ -63,34 +69,35 @@ jobs:
6369
- name: Run Docker container and validate successful startup
6470
run: |
6571
readonly TIMEOUT=20
66-
72+
6773
CONTAINER_ID=$(docker run \
6874
-e BRING_USERNAME=${{ secrets.BRING_TESTING_USERNAME}} \
6975
-e BRING_PASSWORD=${{ secrets.BRING_TESTING_PASSWORD}} \
7076
-e BRING_LIST_NAME=Zuhause \
7177
-d mealie-bring-api:test)
72-
78+
7379
echo "Started container: ${CONTAINER_ID}"
7480
echo "Waiting up to ${TIMEOUT} seconds for expected output ..."
75-
81+
7682
FOUND=0
7783
for i in $(seq 1 ${TIMEOUT}); do
7884
LOGS=$(docker logs "${CONTAINER_ID}" 2>&1 || true)
79-
85+
8086
if echo "${LOGS}" | grep -q "Listening on 0.0.0.0:8742"; then
8187
echo "✅ Expected output found!"
8288
FOUND=1
8389
break
8490
fi
85-
91+
8692
sleep 1
8793
done
88-
94+
8995
docker stop "${CONTAINER_ID}" >/dev/null
90-
96+
97+
echo "---- Container logs ----"
98+
echo "${LOGS}"
99+
91100
if [ "${FOUND}" -ne 1 ]; then
92101
echo "❌ Expected output not found!"
93102
exit 1
94103
fi
95-
echo "---- Container logs ----"
96-
echo "${LOGS}"

tests/conftest.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ def ingredient_raw_base_data(food_name_singular: str, food_name_plural: str, uni
5151
@pytest.fixture
5252
def example_request(ingredient_raw_base_data: dict, unit: dict) -> dict:
5353
return {
54+
"action": {"action_type": "post"},
5455
"content": {
56+
"name": "My testing recipe",
5557
"recipe_servings": 5.0,
5658
"recipe_yield_quantity": 0.0,
5759
"recipe_yield": None,
@@ -65,7 +67,7 @@ def example_request(ingredient_raw_base_data: dict, unit: dict) -> dict:
6567
"plural_name": None,
6668
},
6769
"note": "",
68-
"display": "1 Agavendicksaft",
70+
"display": "1 Apple",
6971
},
7072
{
7173
"quantity": 5.0,

tests/test_integration.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import asyncio
2+
import os
3+
import subprocess # nosec B404
4+
import time
5+
6+
import pytest
7+
import requests
8+
from source.bring_handler import BringHandler
9+
10+
11+
@pytest.mark.skipif(
12+
not os.getenv("BRING_USERNAME") or not os.getenv("BRING_PASSWORD") or not os.getenv("BRING_LIST_NAME"),
13+
reason="The necessary environment variables are not set.",
14+
)
15+
def test_example_request_against_server(example_request):
16+
server_process = subprocess.Popen( # nosec B603, B607
17+
["python", "-m", "source.mealie_bring_api"],
18+
stdout=subprocess.PIPE,
19+
stderr=subprocess.STDOUT,
20+
text=True,
21+
env=os.environ.copy(),
22+
)
23+
24+
timeout_seconds = 10
25+
start = time.time()
26+
response = None
27+
while time.time() - start < timeout_seconds:
28+
try:
29+
response = requests.post("http://localhost:8742/", json=example_request, timeout=5)
30+
break
31+
except requests.exceptions.ConnectionError:
32+
print("Waiting for server to start...")
33+
time.sleep(1)
34+
35+
assert response is not None, f"Server did not respond within {timeout_seconds}s"
36+
response.raise_for_status()
37+
assert response.status_code == 200
38+
assert response.text == "OK"
39+
40+
server_process.terminate()
41+
stdout, _ = server_process.communicate(timeout=10)
42+
43+
for message_to_find in [
44+
"Listening on 0.0.0.0:8742",
45+
"Adding ingredients to Bring:",
46+
"Received SIGTERM. Exiting now...",
47+
]:
48+
assert message_to_find in stdout, f"Expected message {message_to_find} not found in server output"
49+
for message_not_to_find in ["[WARNING]", "[ERROR]", "[FATAL]"]:
50+
assert message_not_to_find not in stdout, f"Unexpected log level {message_not_to_find} found in server output"
51+
52+
clean_bring_list()
53+
54+
55+
def clean_bring_list():
56+
loop = asyncio.new_event_loop()
57+
asyncio.set_event_loop(loop)
58+
59+
bring_handler = BringHandler(loop)
60+
61+
for item in loop.run_until_complete(bring_handler.bring.get_list(bring_handler.list_uuid)).items.purchase:
62+
loop.run_until_complete(
63+
bring_handler.bring.remove_item(
64+
list_uuid=bring_handler.list_uuid, item_name="placeholder", item_uuid=item.uuid
65+
)
66+
)
67+
68+
loop.run_until_complete(bring_handler.logout())
69+
loop.close()

0 commit comments

Comments
 (0)