This commit is contained in:
2026-05-06 22:16:58 +03:30
commit 2ce93b51d7
10 changed files with 277 additions and 0 deletions
+47
View File
@@ -0,0 +1,47 @@
FROM docker.iranserver.com/python:3.10
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
# ------------------------
# APT MIRRORS (runflare)
# ------------------------
RUN rm -f /etc/apt/sources.list /etc/apt/sources.list.d/* && \
printf '%s\n' \
'deb https://mirror-linux.runflare.com/debian/ bookworm main contrib non-free non-free-firmware' \
'deb https://mirror-linux.runflare.com/debian/ bookworm-updates main contrib non-free non-free-firmware' \
'deb https://mirror-linux.runflare.com/debian-security/ bookworm-security main contrib non-free non-free-firmware' \
'' \
> /etc/apt/sources.list
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
curl \
jq \
&& rm -rf /var/lib/apt/lists/*
# ------------------------
# Copy requirements
# ------------------------
COPY requirements.txt .
# ------------------------
# PIP MIRROR
# ------------------------
ENV PIP_INDEX_URL=https://mirror-pypi.runflare.com/simple
ENV PIP_TRUSTED_HOST=mirror-pypi.runflare.com
RUN pip install --upgrade pip && \
pip install --prefer-binary -r requirements.txt
# ------------------------
# Copy test code
# ------------------------
COPY . .
# Expose is optional for test container
# EXPOSE 8000
CMD bash -c "pytest tests -v --maxfail=1 | tee /logs/test.log"
+37
View File
@@ -0,0 +1,37 @@
base_url: http://backend:8000/api/auth
flows:
register_login:
register:
method: POST
path: /register/
body:
username: "{random_username}"
email: "{random_username}@example.com"
phone_number: "09120000000"
password: "test123456"
first_name: "test"
last_name: "user"
expected_status: 201
expected_json:
msg: success
login:
method: POST
path: /login/
body:
identifier: "{random_username}"
password: "test123456"
expected_status: 200
extract:
token: token
store_redis:
key: "test_token:{random_username}"
ttl: 3600
+24
View File
@@ -0,0 +1,24 @@
services:
integration-tests:
image: integration-tests
build: .
container_name: integration_tests
restart: "no"
environment:
REDIS_HOST: redis
REDIS_PORT: 6379
volumes:
- .:/app
- ./logs:/logs
networks:
- crop_network
tty: true
stdin_open: true
networks:
crop_network:
external: true
+36
View File
@@ -0,0 +1,36 @@
============================= test session starts ==============================
platform linux -- Python 3.10.20, pytest-9.0.3, pluggy-1.6.0 -- /usr/local/bin/python3.10
cachedir: .pytest_cache
rootdir: /app
configfile: pytest.ini
collecting ... collected 0 items / 1 error
==================================== ERRORS ====================================
________________ ERROR collecting tests/test_authentication.py _________________
ImportError while importing test module '/app/tests/test_authentication.py'.
Hint: make sure your test modules/packages have valid Python names.
Traceback:
/usr/local/lib/python3.10/site-packages/_pytest/python.py:507: in importtestmodule
mod = import_path(
/usr/local/lib/python3.10/site-packages/_pytest/pathlib.py:587: in import_path
importlib.import_module(module_name)
/usr/local/lib/python3.10/importlib/__init__.py:126: in import_module
return _bootstrap._gcd_import(name[level:], package, level)
<frozen importlib._bootstrap>:1050: in _gcd_import
???
<frozen importlib._bootstrap>:1027: in _find_and_load
???
<frozen importlib._bootstrap>:1006: in _find_and_load_unlocked
???
<frozen importlib._bootstrap>:688: in _load_unlocked
???
/usr/local/lib/python3.10/site-packages/_pytest/assertion/rewrite.py:197: in exec_module
exec(co, module.__dict__)
tests/test_authentication.py:5: in <module>
from utils.yaml_loader import load_config
E ImportError: cannot import name 'load_config' from 'utils.yaml_loader' (/app/utils/yaml_loader.py)
=========================== short test summary info ============================
ERROR tests/test_authentication.py
!!!!!!!!!!!!!!!!!!!!!!!!!! stopping after 1 failures !!!!!!!!!!!!!!!!!!!!!!!!!!!
!!!!!!!!!!!!!!!!!!!! Interrupted: 1 error during collection !!!!!!!!!!!!!!!!!!!!
=============================== 1 error in 0.52s ===============================
+8
View File
@@ -0,0 +1,8 @@
[pytest]
pythonpath = .
testpaths = tests
python_files = test_*.py
addopts = -v
markers =
ai: tests that use AI validation
slow: slow integration tests
+5
View File
@@ -0,0 +1,5 @@
pytest
requests
redis
python-dotenv
pyyaml
+80
View File
@@ -0,0 +1,80 @@
import uuid
import redis
from utils.http_client import http_request
from utils.yaml_loader import load_config
from utils.template import render
config = load_config()
BASE_URL = config["base_url"]
flow = config["flows"]["register_login"]
redis_client = redis.Redis(
host="redis",
port=6379,
decode_responses=True
)
def test_auth_flow():
context = {}
context["random_username"] = f"user_{uuid.uuid4().hex[:6]}"
# -------- register --------
register = flow["register"]
body = render(register["body"], context)
res = http_request(
register["method"],
BASE_URL + register["path"],
json=body
)
assert res["status_code"] == register["expected_status"]
assert res["json"]["msg"] == register["expected_json"]["msg"]
# -------- login --------
login = flow["login"]
body = render(login["body"], context)
res = http_request(
login["method"],
BASE_URL + login["path"],
json=body
)
assert res["status_code"] == login["expected_status"]
token_field = login["extract"]["token"]
token = res["json"][token_field]
assert token is not None
context["token"] = token
# -------- redis store --------
redis_cfg = login["store_redis"]
key = render(redis_cfg["key"], context)
redis_client.set(
key,
token,
ex=redis_cfg["ttl"]
)
saved_token = redis_client.get(key)
assert saved_token == token
+21
View File
@@ -0,0 +1,21 @@
import requests
import time
def http_request(method, url, **kwargs):
start = time.time()
response = requests.request(method, url, **kwargs)
latency = time.time() - start
try:
data = response.json()
except:
data = response.text
return {
"status": response.status_code,
"data": data,
"latency": latency
}
+13
View File
@@ -0,0 +1,13 @@
def render(obj, context):
if isinstance(obj, dict):
return {k: render(v, context) for k, v in obj.items()}
if isinstance(obj, list):
return [render(i, context) for i in obj]
if isinstance(obj, str):
return obj.format(**context)
return obj
+6
View File
@@ -0,0 +1,6 @@
import yaml
def load_apis():
with open("apis.yaml", "r") as f:
return yaml.safe_load(f)