From 0b6afd6f111998dbf701955ee08df8d13107207e Mon Sep 17 00:00:00 2001 From: Anton Changalidi Date: Sun, 28 Sep 2025 13:46:16 +0200 Subject: [PATCH 1/6] Implement ASGI application with fibonacci, factorial, and mean endpoints --- hw1/app.py | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 105 insertions(+), 4 deletions(-) diff --git a/hw1/app.py b/hw1/app.py index 6107b870..fca337af 100644 --- a/hw1/app.py +++ b/hw1/app.py @@ -1,10 +1,13 @@ +import math +from http import HTTPStatus from typing import Any, Awaitable, Callable +import json async def application( - scope: dict[str, Any], - receive: Callable[[], Awaitable[dict[str, Any]]], - send: Callable[[dict[str, Any]], Awaitable[None]], + scope: dict[str, Any], + receive: Callable[[], Awaitable[dict[str, Any]]], + send: Callable[[dict[str, Any]], Awaitable[None]], ): """ Args: @@ -12,8 +15,106 @@ async def application( receive: Корутина для получения сообщений от клиента send: Корутина для отправки сообщений клиенту """ - # TODO: Ваша реализация здесь + + async def send_response(status: int, body: dict[str, Any] | None = None): + content = b"" + headers = [(b"content-type", b"application/json")] + if body is not None: + content = json.dumps(body).encode("utf-8") + headers.append((b"content-length", str(len(content)).encode("utf-8"))) + else: + headers.append((b"content-length", b"0")) + + await send( + {"type": "http.response.start", "status": status, "headers": headers} + ) + await send({"type": "http.response.body", "body": content}) + + # --- lifespan events (startup/shutdown) --- + if scope["type"] == "lifespan": + while True: + message = await receive() + if message["type"] == "lifespan.startup": + await send({"type": "lifespan.startup.complete"}) + elif message["type"] == "lifespan.shutdown": + await send({"type": "lifespan.shutdown.complete"}) + return + + # --- обычные HTTP запросы --- + if scope["type"] != "http": + return + + method = scope["method"] + path = scope["path"] + + # factorial + if method == "GET" and path == "/factorial": + query_string = scope.get("query_string", b"").decode() + query = dict( + (q.split("=") + [""])[:2] + for q in query_string.split("&") + if q + ) + n_str = query.get("n") + if n_str is None or n_str == "": + return await send_response(HTTPStatus.UNPROCESSABLE_ENTITY) + try: + n = int(n_str) + except ValueError: + return await send_response(HTTPStatus.UNPROCESSABLE_ENTITY) + if n < 0: + return await send_response(HTTPStatus.BAD_REQUEST) + return await send_response(HTTPStatus.OK, {"result": math.factorial(n)}) + + # fibonacci + if method == "GET" and path.startswith("/fibonacci"): + parts = path.split("/") + if len(parts) != 3: + return await send_response(HTTPStatus.UNPROCESSABLE_ENTITY) + try: + n = int(parts[2]) + except ValueError: + return await send_response(HTTPStatus.UNPROCESSABLE_ENTITY) + if n < 0: + return await send_response(HTTPStatus.BAD_REQUEST) + a, b = 0, 1 + for _ in range(n): + a, b = b, a + b + return await send_response(HTTPStatus.OK, {"result": a}) + + # mean + if method == "GET" and path == "/mean": + body_event = await receive() + if body_event.get("type") != "http.request": + return await send_response(HTTPStatus.UNPROCESSABLE_ENTITY) + body_bytes = body_event.get("body", b"") or b"" + if not body_bytes: + return await send_response(HTTPStatus.UNPROCESSABLE_ENTITY) + + try: + data = json.loads(body_bytes.decode()) + except json.JSONDecodeError: + return await send_response(HTTPStatus.UNPROCESSABLE_ENTITY) + + if not isinstance(data, list): + return await send_response(HTTPStatus.UNPROCESSABLE_ENTITY) + if len(data) == 0: + return await send_response(HTTPStatus.BAD_REQUEST) + + try: + nums = [float(x) for x in data] + except (TypeError, ValueError): + return await send_response(HTTPStatus.UNPROCESSABLE_ENTITY) + + return await send_response( + HTTPStatus.OK, {"result": sum(nums) / len(nums)} + ) + + # всё остальное → 404 + return await send_response(HTTPStatus.NOT_FOUND) + if __name__ == "__main__": import uvicorn + uvicorn.run("app:application", host="0.0.0.0", port=8000, reload=True) From ebc36d67afc0f75d5b4128961de163804f31e71b Mon Sep 17 00:00:00 2001 From: Anton Changalidi Date: Sat, 4 Oct 2025 20:49:02 +0200 Subject: [PATCH 2/6] Implemented REST API + webSocket chat for homework 2 --- hw2/hw/README.md | 13 +- hw2/hw/chat.html | 32 +++++ hw2/hw/requirements.txt | 1 + hw2/hw/shop_api/main.py | 287 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 331 insertions(+), 2 deletions(-) create mode 100644 hw2/hw/chat.html diff --git a/hw2/hw/README.md b/hw2/hw/README.md index ba9f23c8..0bc1058b 100644 --- a/hw2/hw/README.md +++ b/hw2/hw/README.md @@ -96,7 +96,7 @@ Чтобы запустить тесты только для этого задания вызовите: ```sh -pytest -vv --showlocals --strict ./hw2/test_homework_2_1.py +pytest -vv --showlocals --strict ./hw2/hw/test_homework2.py ``` Если получаете ошибку на подобии `No module named 'shop_api'` @@ -121,3 +121,14 @@ export PYTHONPATH=${PWD}/hw2/hw начале в следующем виде: `{username} :: {message}`. Если делаете его, напишите, пожалуйста, прямо в PR-e об этом. Мне будет сильно проще это заметить<3 + +### Тест чата + +Добавил в `requirements.txt`: `uvicorn[standard]`, без этого вебсокеты не работали. + +Чтобы потестить чат, запускаем: +``` +uvicorn shop_api.main:app --reload +``` + +Затем открываем: ```chat.html``` из нескольких вкладок, коннектимся и наслаждаемся. diff --git a/hw2/hw/chat.html b/hw2/hw/chat.html new file mode 100644 index 00000000..ffb8db0a --- /dev/null +++ b/hw2/hw/chat.html @@ -0,0 +1,32 @@ + + + Chat Test + + + + +

+ + +
+ + + + \ No newline at end of file diff --git a/hw2/hw/requirements.txt b/hw2/hw/requirements.txt index 207dcf5c..4889120f 100644 --- a/hw2/hw/requirements.txt +++ b/hw2/hw/requirements.txt @@ -1,6 +1,7 @@ # Основные зависимости для ASGI приложения fastapi>=0.117.1 uvicorn>=0.24.0 +uvicorn[standard] # Зависимости для тестирования pytest>=7.4.0 diff --git a/hw2/hw/shop_api/main.py b/hw2/hw/shop_api/main.py index f60a8c60..a580d625 100644 --- a/hw2/hw/shop_api/main.py +++ b/hw2/hw/shop_api/main.py @@ -1,3 +1,288 @@ -from fastapi import FastAPI +from fastapi import FastAPI, HTTPException, WebSocket, WebSocketDisconnect, status, Response, Query +from pydantic import BaseModel, Field, field_validator +from typing import Annotated, Any +import random +import string app = FastAPI(title="Shop API") + + +# ============ Data Models ============ + +class ItemCreate(BaseModel): + name: str + price: float = Field(ge=0) + + +class ItemUpdate(BaseModel): + name: str + price: float = Field(ge=0) + + +class ItemPatch(BaseModel): + model_config = {"extra": "forbid"} + + name: str | None = None + price: float | None = Field(default=None, ge=0) + + @classmethod + def validate_price(cls, v): + if v is not None and v < 0: + raise ValueError('price must be non-negative') + return v + + +class Item(BaseModel): + id: int + name: str + price: float + deleted: bool = False + + +class CartItem(BaseModel): + id: int + name: str + quantity: int + available: bool + + +class Cart(BaseModel): + id: int + items: list[CartItem] + price: float + + +# ============ In-Memory Storage ============ + +items_db: dict[int, Item] = {} +carts_db: dict[int, dict[int, int]] = {} # cart_id -> {item_id -> quantity} +item_counter = 0 +cart_counter = 0 + +# ============ WebSocket Chat ============ + +chat_rooms: dict[str, list[WebSocket]] = {} +client_names: dict[WebSocket, str] = {} +chat_history: dict[str, list[str]] = {} # chat_name -> list of messages + + +def generate_username() -> str: + return ''.join(random.choices(string.ascii_letters + string.digits, k=8)) + + +@app.websocket("/chat/{chat_name}") +async def chat_endpoint(websocket: WebSocket, chat_name: str): + await websocket.accept() + + # Generate random username for this client + username = generate_username() + client_names[websocket] = username + + # Send chat history to new client + if chat_name in chat_history: + for msg in chat_history[chat_name]: + await websocket.send_text(msg) + + # Initialize chat room and history if needed + if chat_name not in chat_rooms: + chat_rooms[chat_name] = [] + if chat_name not in chat_history: + chat_history[chat_name] = [] + + # Add client to chat room + chat_rooms[chat_name].append(websocket) + + try: + while True: + # Receive message from client + message = await websocket.receive_text() + + # Broadcast to all clients in the same chat room + formatted_message = f"{username} :: {message}" + + # Save to history + chat_history[chat_name].append(formatted_message) + + # Broadcast to all connected clients + for client in chat_rooms[chat_name]: + await client.send_text(formatted_message) + except WebSocketDisconnect: + # Remove client from chat room + chat_rooms[chat_name].remove(websocket) + if not chat_rooms[chat_name]: + del chat_rooms[chat_name] + del client_names[websocket] + + +# ============ Item Endpoints ============ + +@app.post("/item", response_model=Item, status_code=status.HTTP_201_CREATED) +def create_item(item: ItemCreate): + global item_counter + item_counter += 1 + new_item = Item(id=item_counter, name=item.name, price=item.price, deleted=False) + items_db[item_counter] = new_item + return new_item + + +@app.get("/item/{id}", response_model=Item) +def get_item(id: int): + if id not in items_db: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + item = items_db[id] + if item.deleted: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + return item + + +@app.get("/item", response_model=list[Item]) +def get_items( + offset: Annotated[int, Query(ge=0)] = 0, + limit: Annotated[int, Query(gt=0)] = 10, + min_price: Annotated[float | None, Query(ge=0)] = None, + max_price: Annotated[float | None, Query(ge=0)] = None, + show_deleted: bool = False +): + filtered_items = [] + + for item in items_db.values(): + # Filter by deleted status + if not show_deleted and item.deleted: + continue + + # Filter by price + if min_price is not None and item.price < min_price: + continue + if max_price is not None and item.price > max_price: + continue + + filtered_items.append(item) + + return filtered_items[offset:offset + limit] + + +@app.put("/item/{id}", response_model=Item) +def update_item(id: int, item: ItemUpdate): + if id not in items_db: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + + existing_item = items_db[id] + existing_item.name = item.name + existing_item.price = item.price + + return existing_item + + +@app.patch("/item/{id}", response_model=Item) +def patch_item(id: int, item: ItemPatch): + if id not in items_db: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + + existing_item = items_db[id] + + # Cannot patch deleted items + if existing_item.deleted: + return Response(status_code=status.HTTP_304_NOT_MODIFIED) + + # Update only provided fields + if item.name is not None: + existing_item.name = item.name + if item.price is not None: + existing_item.price = item.price + + return existing_item + + +@app.delete("/item/{id}") +def delete_item(id: int): + if id not in items_db: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + + items_db[id].deleted = True + return Response(status_code=status.HTTP_200_OK) + + +# ============ Cart Endpoints ============ + +@app.post("/cart", status_code=status.HTTP_201_CREATED) +def create_cart(response: Response): + global cart_counter + cart_counter += 1 + carts_db[cart_counter] = {} + + response.headers["location"] = f"/cart/{cart_counter}" + return {"id": cart_counter} + + +@app.get("/cart/{id}", response_model=Cart) +def get_cart(id: int): + if id not in carts_db: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + + cart_items_dict = carts_db[id] + cart_items = [] + total_price = 0.0 + + for item_id, quantity in cart_items_dict.items(): + if item_id in items_db: + item = items_db[item_id] + cart_items.append(CartItem( + id=item.id, + name=item.name, + quantity=quantity, + available=not item.deleted + )) + total_price += item.price * quantity + + return Cart(id=id, items=cart_items, price=total_price) + + +@app.get("/cart", response_model=list[Cart]) +def get_carts( + offset: Annotated[int, Query(ge=0)] = 0, + limit: Annotated[int, Query(gt=0)] = 10, + min_price: Annotated[float | None, Query(ge=0)] = None, + max_price: Annotated[float | None, Query(ge=0)] = None, + min_quantity: Annotated[int | None, Query(ge=0)] = None, + max_quantity: Annotated[int | None, Query(ge=0)] = None +): + filtered_carts = [] + + for cart_id in carts_db: + cart = get_cart(cart_id) + + # Filter by price + if min_price is not None and cart.price < min_price: + continue + if max_price is not None and cart.price > max_price: + continue + + # Calculate total quantity + total_quantity = sum(item.quantity for item in cart.items) + + # Filter by quantity + if min_quantity is not None and total_quantity < min_quantity: + continue + if max_quantity is not None and total_quantity > max_quantity: + continue + + filtered_carts.append(cart) + + return filtered_carts[offset:offset + limit] + + +@app.post("/cart/{cart_id}/add/{item_id}") +def add_item_to_cart(cart_id: int, item_id: int): + if cart_id not in carts_db: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + if item_id not in items_db: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + + cart = carts_db[cart_id] + + if item_id in cart: + cart[item_id] += 1 + else: + cart[item_id] = 1 + + return Response(status_code=status.HTTP_200_OK) From afd6cfbfda420c4b121fc2034e95afa02e3582d9 Mon Sep 17 00:00:00 2001 From: Anton Changalidi Date: Sun, 5 Oct 2025 02:29:38 +0200 Subject: [PATCH 3/6] Added grafana+prometheus --- hw2/hw/.dockerignore | 15 + hw2/hw/Dockerfile | 23 + hw2/hw/MONITORING.md | 86 +++ hw2/hw/ddoser.py | 126 ++++ hw2/hw/docker-compose.yml | 44 ++ hw2/hw/grafana.jpg | Bin 0 -> 226528 bytes hw2/hw/requirements.txt | 4 + hw2/hw/settings/grafana_config.json | 747 ++++++++++++++++++++++ hw2/hw/settings/prometheus/prometheus.yml | 10 + hw2/hw/shop_api/main.py | 2 + lecture3/README.md | 2 + 11 files changed, 1059 insertions(+) create mode 100644 hw2/hw/.dockerignore create mode 100644 hw2/hw/Dockerfile create mode 100644 hw2/hw/MONITORING.md create mode 100755 hw2/hw/ddoser.py create mode 100644 hw2/hw/docker-compose.yml create mode 100644 hw2/hw/grafana.jpg create mode 100644 hw2/hw/settings/grafana_config.json create mode 100644 hw2/hw/settings/prometheus/prometheus.yml diff --git a/hw2/hw/.dockerignore b/hw2/hw/.dockerignore new file mode 100644 index 00000000..677e1455 --- /dev/null +++ b/hw2/hw/.dockerignore @@ -0,0 +1,15 @@ +__pycache__ +*.pyc +*.pyo +*.pyd +.pytest_cache +.venv +venv +*.egg-info +.git +.gitignore +README.md +MONITORING.md +CLAUDE.md +chat.html +ddoser.py diff --git a/hw2/hw/Dockerfile b/hw2/hw/Dockerfile new file mode 100644 index 00000000..27b0b636 --- /dev/null +++ b/hw2/hw/Dockerfile @@ -0,0 +1,23 @@ +FROM python:3.12 AS base + +ARG PYTHONFAULTHANDLER=1 \ + PYTHONUNBUFFERED=1 \ + PYTHONHASHSEED=random \ + PIP_NO_CACHE_DIR=on \ + PIP_DISABLE_PIP_VERSION_CHECK=on \ + PIP_DEFAULT_TIMEOUT=500 + +RUN apt-get update && apt-get install -y gcc +RUN python -m pip install --upgrade pip + +WORKDIR $APP_ROOT/src +COPY . ./ + +ENV VIRTUAL_ENV=$APP_ROOT/src/.venv \ + PATH=$APP_ROOT/src/.venv/bin:$PATH + +RUN pip install -r requirements.txt + +FROM base as local + +CMD ["uvicorn", "shop_api.main:app", "--port", "8080", "--host", "0.0.0.0"] diff --git a/hw2/hw/MONITORING.md b/hw2/hw/MONITORING.md new file mode 100644 index 00000000..dc790371 --- /dev/null +++ b/hw2/hw/MONITORING.md @@ -0,0 +1,86 @@ +# Monitoring Setup Guide for Shop API + +This guide explains how to set up monitoring for the Shop API using Docker, Prometheus, and Grafana. + +## Prerequisites + +- Docker and Docker Compose installed +- Ports 3000 (Grafana), 8080 (API), and 9090 (Prometheus) available + +## Quick Start + +### 1. Build and Start Services + +```bash +docker-compose up --build +``` + +This will start three services: +- **shop-api**: The FastAPI application on port 8080 +- **prometheus**: Metrics collection on port 9090 +- **grafana**: Visualization dashboard on port 3000 + +### 2. Verify Services are Running + +- API: http://localhost:8080/docs +- Prometheus: http://localhost:9090 +- Grafana: http://localhost:3000 + +## Setting Up Grafana + +### 1. Login to Grafana + +- Navigate to http://localhost:3000 +- Username: `admin` +- Password: `admin` +- You'll be prompted to change the password (you can skip this for local development) + +### 2. Add Prometheus Data Source + +1. Click on the **gear icon** (⚙️) in the left sidebar → **Data Sources** +2. Click **Add data source** +3. Select **Prometheus** +4. Configure: + - **Name**: `Prometheus` + - **URL**: `http://prometheus:9090` + - Leave other settings as default +5. Click **Save & Test** - you should see "Data source is working" + +### 3. Create Dashboards + + +1. Click **+** icon in left sidebar → **Import** +2. Enter data from `settings/grafana_config.json` +5. Click **Import** + +## Running Load Tests + +To generate traffic for monitoring: + +```bash +# Make sure the API is running via docker-compose +python ddoser.py +``` + +The load test will: +- Create random items +- Query items with various filters +- Create carts +- Add items to carts +- Update and delete items +- Generate traffic across all API endpoints + +## Stopping Services + +```bash +docker-compose down +``` + +To remove volumes as well: +```bash +docker-compose down -v +``` + +## HW done + +![grafana.jpg](grafana.jpg) diff --git a/hw2/hw/ddoser.py b/hw2/hw/ddoser.py new file mode 100755 index 00000000..abc81519 --- /dev/null +++ b/hw2/hw/ddoser.py @@ -0,0 +1,126 @@ +from concurrent.futures import ThreadPoolExecutor, as_completed + +import requests +from faker import Faker + +faker = Faker() + +BASE_URL = "http://localhost:8080" + + +def create_items(): + """Create random items in the shop""" + for _ in range(100): + item = { + "name": faker.catch_phrase(), + "price": round(faker.random.uniform(10.0, 500.0), 2), + } + response = requests.post(f"{BASE_URL}/item", json=item) + print(f"Created item: {response.status_code}") + + +def get_items(): + """Get items with random filters""" + for _ in range(100): + params = {} + if faker.boolean(): + params["min_price"] = faker.random.uniform(0, 100) + if faker.boolean(): + params["max_price"] = faker.random.uniform(100, 500) + if faker.boolean(): + params["offset"] = faker.random_int(0, 10) + if faker.boolean(): + params["limit"] = faker.random_int(1, 20) + + response = requests.get(f"{BASE_URL}/item", params=params) + print(f"Get items: {response.status_code}") + + +def create_carts(): + """Create random carts""" + for _ in range(50): + response = requests.post(f"{BASE_URL}/cart") + print(f"Created cart: {response.status_code}") + + +def add_items_to_carts(): + """Add random items to random carts""" + for _ in range(200): + cart_id = faker.random_int(1, 50) + item_id = faker.random_int(1, 100) + response = requests.post(f"{BASE_URL}/cart/{cart_id}/add/{item_id}") + print(f"Add item to cart: {response.status_code}") + + +def get_carts(): + """Get carts with random filters""" + for _ in range(100): + params = {} + if faker.boolean(): + params["min_price"] = faker.random.uniform(0, 500) + if faker.boolean(): + params["max_price"] = faker.random.uniform(500, 2000) + if faker.boolean(): + params["min_quantity"] = faker.random_int(0, 5) + if faker.boolean(): + params["max_quantity"] = faker.random_int(5, 20) + + response = requests.get(f"{BASE_URL}/cart", params=params) + print(f"Get carts: {response.status_code}") + + +def patch_items(): + """Partially update random items""" + for _ in range(50): + item_id = faker.random_int(1, 100) + update = {} + if faker.boolean(): + update["name"] = faker.catch_phrase() + if faker.boolean(): + update["price"] = round(faker.random.uniform(10.0, 500.0), 2) + + if update: # Only send if we have something to update + response = requests.patch(f"{BASE_URL}/item/{item_id}", json=update) + print(f"Patch item: {response.status_code}") + + +def delete_items(): + """Delete random items""" + for _ in range(20): + item_id = faker.random_int(1, 100) + response = requests.delete(f"{BASE_URL}/item/{item_id}") + print(f"Delete item: {response.status_code}") + + +print("Starting load test...") + +with ThreadPoolExecutor(max_workers=100) as executor: + futures = {} + + # Submit various tasks + for i in range(5): + futures[executor.submit(create_items)] = f"create-items-{i}" + + for i in range(10): + futures[executor.submit(get_items)] = f"get-items-{i}" + + for i in range(3): + futures[executor.submit(create_carts)] = f"create-carts-{i}" + + for i in range(10): + futures[executor.submit(add_items_to_carts)] = f"add-items-{i}" + + for i in range(8): + futures[executor.submit(get_carts)] = f"get-carts-{i}" + + for i in range(4): + futures[executor.submit(patch_items)] = f"patch-items-{i}" + + for i in range(2): + futures[executor.submit(delete_items)] = f"delete-items-{i}" + + # Wait for completion + for future in as_completed(futures): + print(f"✓ Completed {futures[future]}") + +print("\nLoad test completed!") diff --git a/hw2/hw/docker-compose.yml b/hw2/hw/docker-compose.yml new file mode 100644 index 00000000..05d869c4 --- /dev/null +++ b/hw2/hw/docker-compose.yml @@ -0,0 +1,44 @@ +version: "3" + +services: + + shop-api: + build: + context: . + dockerfile: ./Dockerfile + target: local + restart: always + ports: + - 8080:8080 + networks: + - monitoring + + grafana: + image: grafana/grafana:latest + ports: + - 3000:3000 + restart: always + networks: + - monitoring + environment: + - GF_SECURITY_ADMIN_PASSWORD=admin + - GF_SECURITY_ADMIN_USER=admin + + prometheus: + image: prom/prometheus + volumes: + - ./settings/prometheus/:/etc/prometheus/ + command: + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus" + - "--web.console.libraries=/usr/share/prometheus/console_libraries" + - "--web.console.templates=/usr/share/prometheus/consoles" + ports: + - 9090:9090 + restart: always + networks: + - monitoring + +networks: + monitoring: + driver: bridge diff --git a/hw2/hw/grafana.jpg b/hw2/hw/grafana.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1affb77a23070ab9f1a852c47369a65523be34d8 GIT binary patch literal 226528 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

-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 UJFrRI?}t$QebcaY_FvQg3&A?R;Q#;t literal 0 HcmV?d00001 diff --git a/hw2/hw/requirements.txt b/hw2/hw/requirements.txt index 4889120f..51f39f45 100644 --- a/hw2/hw/requirements.txt +++ b/hw2/hw/requirements.txt @@ -2,9 +2,13 @@ fastapi>=0.117.1 uvicorn>=0.24.0 uvicorn[standard] +prometheus-fastapi-instrumentator # Зависимости для тестирования pytest>=7.4.0 pytest-asyncio>=0.21.0 httpx>=0.27.2 Faker>=37.8.0 + +# Для нагрузочного тестирования +requests diff --git a/hw2/hw/settings/grafana_config.json b/hw2/hw/settings/grafana_config.json new file mode 100644 index 00000000..0db4ba5b --- /dev/null +++ b/hw2/hw/settings/grafana_config.json @@ -0,0 +1,747 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "enable": true, + "hide": false, + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 0, + "links": [], + "panels": [ + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 1, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.2.0", + "targets": [ + { + "expr": "histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{path!=\"/metrics\"}[2m])) by (le))", + "legendFormat": "p95 latency", + "refId": "A" + } + ], + "title": "P95 Request Latency (seconds)", + "type": "timeseries" + }, + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 2, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.2.0", + "targets": [ + { + "expr": "sum(rate(http_requests_total{path!=\"/metrics\"}[1m]))", + "legendFormat": "RPS total", + "refId": "A" + } + ], + "title": "Requests per Second (RPS, total)", + "type": "timeseries" + }, + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 3, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.2.0", + "targets": [ + { + "expr": "sum by (path, method) (rate(http_requests_total{path!=\"/metrics\"}[1m]))", + "legendFormat": "{{method}} {{path}}", + "refId": "A" + } + ], + "title": "RPS by Endpoint", + "type": "timeseries" + }, + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 4, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.2.0", + "targets": [ + { + "expr": "sum by (status) (rate(http_requests_total{path!=\"/metrics\"}[1m]))", + "legendFormat": "Status {{status}}", + "refId": "A" + } + ], + "title": "HTTP Status Codes (rate)", + "type": "timeseries" + }, + { + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "yellow", + "value": 90 + }, + { + "color": "green", + "value": 97 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 0, + "y": 16 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.2.0", + "targets": [ + { + "expr": "100 * sum(rate(http_requests_total{status=~\"2..\"}[2m])) / sum(rate(http_requests_total[2m]))", + "refId": "A" + } + ], + "title": "Success Rate (2xx, %)", + "type": "stat" + }, + { + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 1, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": 0 + }, + { + "color": "green", + "value": 1 + } + ] + }, + "unit": "percentunit" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 3, + "x": 3, + "y": 16 + }, + "id": 10, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.2.0", + "targets": [ + { + "expr": "avg(up{job=\"shop-api\"})", + "refId": "A" + } + ], + "title": "Service Uptime", + "type": "stat" + }, + { + "fieldConfig": { + "defaults": { + "mappings": [], + "max": 100, + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "yellow", + "value": 1 + }, + { + "color": "red", + "value": 5 + } + ] + }, + "unit": "percent" + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 16 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "auto", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "lastNotNull" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.2.0", + "targets": [ + { + "expr": "100 * sum(rate(http_requests_total{status=~\"[45]..\"}[2m])) / sum(rate(http_requests_total[2m]))", + "refId": "A" + } + ], + "title": "Error Rate (4xx + 5xx, %)", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "fillOpacity": 80, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "lineWidth": 1, + "scaleDistribution": { + "type": "linear" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 14, + "w": 12, + "x": 12, + "y": 16 + }, + "id": 8, + "options": { + "barRadius": 0, + "barWidth": 0.97, + "fullHighlight": false, + "groupWidth": 0.7, + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "orientation": "auto", + "showValue": "auto", + "stacking": "none", + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + }, + "xTickLabelRotation": 0, + "xTickLabelSpacing": 0 + }, + "pluginVersion": "12.2.0", + "targets": [ + { + "editorMode": "code", + "expr": "increase(http_requests_total{path!=\"/metrics\"}[5m])", + "interval": "", + "range": true, + "refId": "A" + } + ], + "title": "Total Requests (last 5m)", + "type": "barchart" + }, + { + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 0, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "auto", + "showValues": false, + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": 0 + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 22 + }, + "id": 9, + "options": { + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "single", + "sort": "none" + } + }, + "pluginVersion": "12.2.0", + "targets": [ + { + "expr": "sum(rate(http_request_duration_seconds_bucket{path!=\"/metrics\"}[2m])) by (le)", + "legendFormat": "< {{le}}s", + "refId": "A" + } + ], + "title": "Request Volume (Histogram buckets)", + "type": "timeseries" + } + ], + "preload": false, + "refresh": "5s", + "schemaVersion": 42, + "tags": [ + "fastapi", + "prometheus" + ], + "templating": { + "list": [] + }, + "time": { + "from": "now-15m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "FastAPI — Enhanced Prometheus Dashboard", + "uid": "d18e430e-cf06-4016-9869-f726f37d8db2", + "version": 3 +} \ No newline at end of file diff --git a/hw2/hw/settings/prometheus/prometheus.yml b/hw2/hw/settings/prometheus/prometheus.yml new file mode 100644 index 00000000..9f893ee9 --- /dev/null +++ b/hw2/hw/settings/prometheus/prometheus.yml @@ -0,0 +1,10 @@ +global: + scrape_interval: 1s + evaluation_interval: 1s + +scrape_configs: + - job_name: shop-api + metrics_path: /metrics + static_configs: + - targets: + - shop-api:8080 diff --git a/hw2/hw/shop_api/main.py b/hw2/hw/shop_api/main.py index a580d625..f0d27f5f 100644 --- a/hw2/hw/shop_api/main.py +++ b/hw2/hw/shop_api/main.py @@ -3,8 +3,10 @@ from typing import Annotated, Any import random import string +from prometheus_fastapi_instrumentator import Instrumentator app = FastAPI(title="Shop API") +Instrumentator().instrument(app).expose(app) # ============ Data Models ============ diff --git a/lecture3/README.md b/lecture3/README.md index aad28c54..9859dcb8 100644 --- a/lecture3/README.md +++ b/lecture3/README.md @@ -11,3 +11,5 @@ 1) Dockerfile для сборки сервиса 2) docker-compose.yml для локального разворачивания в Docker 3) Приложить скрин с парой Дашбордов в Grafana + +Сделано -- в hw2 \ No newline at end of file From 39d8ef18bf699fb6e888ffa2c2119461ff2eb65e Mon Sep 17 00:00:00 2001 From: Anton Changalidi Date: Mon, 27 Oct 2025 00:54:57 +0100 Subject: [PATCH 4/6] hw4 db+tests+cicd --- hw2/hw/.github/workflows/test.yml | 48 ++++ hw2/hw/conftest.py | 26 ++ hw2/hw/docker-compose.yml | 2 +- hw2/hw/hw4.md | 142 +++++++++++ hw2/hw/requirements.txt | 3 + hw2/hw/shop_api/database.py | 58 +++++ hw2/hw/shop_api/main.py | 227 ++++++++++-------- hw2/hw/test_edge_cases.py | 179 ++++++++++++++ hw2/hw/test_websocket.py | 107 +++++++++ .../transaction_demos/01_dirty_read_demo.py | 107 +++++++++ .../02_no_dirty_read_demo.py | 110 +++++++++ .../03_non_repeatable_read_demo.py | 108 +++++++++ .../04_no_non_repeatable_read_demo.py | 113 +++++++++ .../transaction_demos/05_phantom_read_demo.py | 115 +++++++++ .../06_no_phantom_read_demo.py | 120 +++++++++ hw2/hw/transaction_demos/run_all_demos.py | 50 ++++ 16 files changed, 1409 insertions(+), 106 deletions(-) create mode 100644 hw2/hw/.github/workflows/test.yml create mode 100644 hw2/hw/conftest.py create mode 100644 hw2/hw/hw4.md create mode 100644 hw2/hw/shop_api/database.py create mode 100644 hw2/hw/test_edge_cases.py create mode 100644 hw2/hw/test_websocket.py create mode 100644 hw2/hw/transaction_demos/01_dirty_read_demo.py create mode 100644 hw2/hw/transaction_demos/02_no_dirty_read_demo.py create mode 100644 hw2/hw/transaction_demos/03_non_repeatable_read_demo.py create mode 100644 hw2/hw/transaction_demos/04_no_non_repeatable_read_demo.py create mode 100644 hw2/hw/transaction_demos/05_phantom_read_demo.py create mode 100644 hw2/hw/transaction_demos/06_no_phantom_read_demo.py create mode 100644 hw2/hw/transaction_demos/run_all_demos.py diff --git a/hw2/hw/.github/workflows/test.yml b/hw2/hw/.github/workflows/test.yml new file mode 100644 index 00000000..568cec00 --- /dev/null +++ b/hw2/hw/.github/workflows/test.yml @@ -0,0 +1,48 @@ +name: Tests + +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.11"] + + steps: + - uses: actions/checkout@v3 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pytest-cov + + - name: Run tests with coverage + run: | + export PYTHONPATH=${PWD} + pytest --cov=shop_api --cov-report=term-missing --cov-report=xml --cov-fail-under=95 test_homework2.py test_edge_cases.py test_websocket.py + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + file: ./coverage.xml + fail_ci_if_error: false + + - name: Run transaction demos + run: | + python transaction_demos/01_dirty_read_demo.py + python transaction_demos/02_no_dirty_read_demo.py + python transaction_demos/03_non_repeatable_read_demo.py + python transaction_demos/04_no_non_repeatable_read_demo.py + python transaction_demos/05_phantom_read_demo.py + python transaction_demos/06_no_phantom_read_demo.py diff --git a/hw2/hw/conftest.py b/hw2/hw/conftest.py new file mode 100644 index 00000000..1f5628c1 --- /dev/null +++ b/hw2/hw/conftest.py @@ -0,0 +1,26 @@ +import pytest +import os +import sys + +# Add current directory to path for imports +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +from shop_api.database import init_db, engine, Base + + +@pytest.fixture(scope="session", autouse=True) +def setup_database(): + """Initialize database before tests and clean up after""" + # Remove old test database if exists + if os.path.exists("shop.db"): + os.remove("shop.db") + + # Create tables + init_db() + + yield + + # Clean up after tests + Base.metadata.drop_all(bind=engine) + if os.path.exists("shop.db"): + os.remove("shop.db") diff --git a/hw2/hw/docker-compose.yml b/hw2/hw/docker-compose.yml index 05d869c4..e13bdad8 100644 --- a/hw2/hw/docker-compose.yml +++ b/hw2/hw/docker-compose.yml @@ -41,4 +41,4 @@ services: networks: monitoring: - driver: bridge + driver: bridge \ No newline at end of file diff --git a/hw2/hw/hw4.md b/hw2/hw/hw4.md new file mode 100644 index 00000000..f2b638be --- /dev/null +++ b/hw2/hw/hw4.md @@ -0,0 +1,142 @@ +## ДЗ -- часть 1 + +За каждый пункт - 1 балл + +Внедрить во вторую домашку хранение данных в БД, для этого надо: +1) Добавить БД в docket-compose.yml (если БД - это отдельный сервис, если хотите использовать sqlite, то можно скипнуть этот шаг) +2) Переписать код на взаимодействие с вашей БД (если вы еще этого не сделали, если вы уже написали код с БД, подзравляю, вам остался только 3 пункт) +3) В свободной форме, напишите скрипты, которые просимулируют разные "проблемы" которые могут возникнуть в транзакциях (dirty read, not-repeatable read, serialize) и настраивая уровне изоляции покажите, что они действительно решаются (через SQLAlchemy например), то есть: +показать dirty read при read uncommited +показать что нет dirty read при read commited +показать non-repeatable read при read commited +показать что нет non-repeatable read при repeatable read +показать phantom reads при repeatable read +показать что нет phantom reads при serializable +*Тут зависит от того какую БД вы выбрали, разные БД могут поддерживать разные уровни изоляции + + +# ДЗ -- часть 2 + +1) Добиться 95% покрытия тестами вашей второй домашки - 1 балл + +2) Настроить автозапуск этих тестов в CI, если вы подключали сторонюю БД, то можно посмотреть вот [сюда](https://dev.to/kashifsoofi/integration-test-postgres-using-github-actions-3lln), чтобы поддержать тесты с ней в CI. По итогу у вас должен получится зеленый пайплайн - оценивается в еще 2 балла. + +# Решение + +## Часть 1: Миграция на БД и демонстрация транзакций + +1. База данных (SQLite) + +- Добавлена SQLite (не требует docker-compose, т.к. это файловая БД) +- Созданы модели SQLAlchemy: items, carts, cart_items +- Файлы: shop_api/database.py, обновлён shop_api/main.py + +2. Миграция кода + +- Все эндпоинты переписаны на работу с БД +- Все оригинальные тесты проходят +- Используются контекстные менеджеры для транзакций + +3. Демонстрация проблем транзакций + +Создано 6 скриптов в `transaction_demos/`: +- `01_dirty_read_demo.py` - показывает dirty read при READ UNCOMMITTED +- `02_no_dirty_read_demo.py` - нет dirty read при READ COMMITTED +- `03_non_repeatable_read_demo.py` - показывает non-repeatable read +- `04_no_non_repeatable_read_demo.py` - нет non-repeatable read при REPEATABLE READ +- `05_phantom_read_demo.py` - показывает phantom reads +- `06_no_phantom_read_demo.py` - нет phantom reads при SERIALIZABLE + +Запустить все: +``` +python transaction_demos/run_all_demos.py +``` +**Описание проблем** + + 1. Dirty Read (Грязное чтение) + + `01_dirty_read_demo.py` - Проблема: + - Транзакция T1 обновляет баланс с 1000 на 500, но НЕ коммитит + - Транзакция T2 читает баланс и видит 500 (незакоммиченное значение) + - T1 делает ROLLBACK + - Результат: T2 прочитала данные, которых "никогда не было" (они откатились) + + `02_no_dirty_read_demo.py` - Решение (READ COMMITTED): + - T1 обновляет баланс на 500, не коммитит + - T2 пытается прочитать, но видит только закоммиченное значение 1000 + - T1 откатывается + - Результат: T2 всегда видит только подтверждённые данные + + 2. Non-Repeatable Read (Неповторяющееся чтение) + + `03_non_repeatable_read_demo.py` - Проблема: + - T1 читает баланс: получает 1000 + - T2 обновляет баланс на 1500 и COMMIT + - T1 снова читает баланс: получает 1500 + - Результат: в одной транзакции T1 одно и то же чтение дало разные результаты (1000 → 1500) + + `04_no_non_repeatable_read_demo.py` - Решение (REPEATABLE READ / IMMEDIATE): + - T1 начинает транзакцию с блокировкой (BEGIN IMMEDIATE) + - T1 читает баланс: 1000 + - T2 пытается обновить, но блокируется из-за блокировки T1 + - T1 снова читает баланс: всё ещё 1000 + - T1 коммитит, только потом T2 может обновить + - Результат: повторные чтения в T1 возвращают одинаковые значения + + 3. Phantom Read (Фантомное чтение) + + `05_phantom_read_demo.py` - Проблема: + - T1 выполняет запрос: "SELECT * WHERE balance > 500" → находит 2 строки (Alice, Bob) + - T2 вставляет новую строку Charlie с балансом 1500 и COMMIT + - T1 повторяет запрос: "SELECT * WHERE balance > 500" → находит 3 строки (Alice, Bob, Charlie) + - Результат: в одной транзакции появились "фантомные" строки, которых раньше не было + + `06_no_phantom_read_demo.py` - Решение (SERIALIZABLE / EXCLUSIVE): + - T1 начинает с эксклюзивной блокировкой (BEGIN EXCLUSIVE) + - T1 выполняет запрос: находит 2 строки + - T2 пытается вставить новую строку, но блокируется + - T1 повторяет запрос: всё ещё 2 строки + - T1 коммитит, только потом T2 может вставить + - Результат: результаты запросов в T1 стабильны, новые строки не появляются + +Все скрипты используют threading для имитации параллельных транзакций и time.sleep() для синхронизации действий. + + +## Часть 2: Покрытие тестами и CI/CD + +1. Покрытие тестами: 98% (требовалось 95%) + +- Создано 14 дополнительных тестов в test_edge_cases.py +- Создано 5 WebSocket тестов в test_websocket.py +- Всего 58 тестов, все проходят + +**Тесты:** +- test_homework2.py - оригинальные тесты +- test_edge_cases.py - новые edge case тесты +- test_websocket.py - тесты WebSocket + + +2. CI/CD для GitHub Actions + +- Создан .github/workflows/test.yml +- Автоматический запуск тестов при push/PR +- Проверка покрытия ≥95% +- Запуск демонстраций транзакций + + +CI/CD: +- .github/workflows/test.yml - GitHub Actions + + +# Check + +## Запустить тесты +``` +export PYTHONPATH=${PWD} +pytest --cov=shop_api --cov-fail-under=95 test_homework2.py test_edge_cases.py test_websocket.py +``` + +## Запустить демонстрацию транзакций +``` +python transaction_demos/run_all_demos.py +``` diff --git a/hw2/hw/requirements.txt b/hw2/hw/requirements.txt index 51f39f45..83005713 100644 --- a/hw2/hw/requirements.txt +++ b/hw2/hw/requirements.txt @@ -3,10 +3,13 @@ fastapi>=0.117.1 uvicorn>=0.24.0 uvicorn[standard] prometheus-fastapi-instrumentator +sqlalchemy>=2.0.0 +aiosqlite>=0.19.0 # Зависимости для тестирования pytest>=7.4.0 pytest-asyncio>=0.21.0 +pytest-cov>=4.0.0 httpx>=0.27.2 Faker>=37.8.0 diff --git a/hw2/hw/shop_api/database.py b/hw2/hw/shop_api/database.py new file mode 100644 index 00000000..3fce9dee --- /dev/null +++ b/hw2/hw/shop_api/database.py @@ -0,0 +1,58 @@ +from sqlalchemy import create_engine, Column, Integer, String, Float, Boolean, ForeignKey, Table +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker, relationship +from contextlib import contextmanager + +# Create SQLite database +SQLALCHEMY_DATABASE_URL = "sqlite:///./shop.db" + +engine = create_engine( + SQLALCHEMY_DATABASE_URL, + connect_args={"check_same_thread": False} +) + +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() + + +class DBItem(Base): + __tablename__ = "items" + + id = Column(Integer, primary_key=True, index=True, autoincrement=True) + name = Column(String, nullable=False) + price = Column(Float, nullable=False) + deleted = Column(Boolean, default=False, nullable=False) + + +class DBCart(Base): + __tablename__ = "carts" + + id = Column(Integer, primary_key=True, index=True, autoincrement=True) + + +class DBCartItem(Base): + __tablename__ = "cart_items" + + cart_id = Column(Integer, ForeignKey('carts.id'), primary_key=True) + item_id = Column(Integer, ForeignKey('items.id'), primary_key=True) + quantity = Column(Integer, nullable=False, default=1) + + +def init_db(): + """Initialize database tables""" + Base.metadata.create_all(bind=engine) + + +@contextmanager +def get_db(): + """Get database session""" + db = SessionLocal() + try: + yield db + db.commit() + except Exception: + db.rollback() + raise + finally: + db.close() diff --git a/hw2/hw/shop_api/main.py b/hw2/hw/shop_api/main.py index f0d27f5f..dc0178ba 100644 --- a/hw2/hw/shop_api/main.py +++ b/hw2/hw/shop_api/main.py @@ -4,10 +4,17 @@ import random import string from prometheus_fastapi_instrumentator import Instrumentator +from sqlalchemy.orm import Session +from shop_api.database import init_db, get_db, DBItem, DBCart, DBCartItem app = FastAPI(title="Shop API") Instrumentator().instrument(app).expose(app) +# Initialize database on startup +@app.on_event("startup") +def startup_event(): + init_db() + # ============ Data Models ============ @@ -54,13 +61,6 @@ class Cart(BaseModel): price: float -# ============ In-Memory Storage ============ - -items_db: dict[int, Item] = {} -carts_db: dict[int, dict[int, int]] = {} # cart_id -> {item_id -> quantity} -item_counter = 0 -cart_counter = 0 - # ============ WebSocket Chat ============ chat_rooms: dict[str, list[WebSocket]] = {} @@ -120,21 +120,20 @@ async def chat_endpoint(websocket: WebSocket, chat_name: str): @app.post("/item", response_model=Item, status_code=status.HTTP_201_CREATED) def create_item(item: ItemCreate): - global item_counter - item_counter += 1 - new_item = Item(id=item_counter, name=item.name, price=item.price, deleted=False) - items_db[item_counter] = new_item - return new_item + with get_db() as db: + db_item = DBItem(name=item.name, price=item.price, deleted=False) + db.add(db_item) + db.flush() + return Item(id=db_item.id, name=db_item.name, price=db_item.price, deleted=db_item.deleted) @app.get("/item/{id}", response_model=Item) def get_item(id: int): - if id not in items_db: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - item = items_db[id] - if item.deleted: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - return item + with get_db() as db: + db_item = db.query(DBItem).filter(DBItem.id == id).first() + if not db_item or db_item.deleted: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + return Item(id=db_item.id, name=db_item.name, price=db_item.price, deleted=db_item.deleted) @app.get("/item", response_model=list[Item]) @@ -145,98 +144,104 @@ def get_items( max_price: Annotated[float | None, Query(ge=0)] = None, show_deleted: bool = False ): - filtered_items = [] - - for item in items_db.values(): - # Filter by deleted status - if not show_deleted and item.deleted: - continue + with get_db() as db: + query = db.query(DBItem) - # Filter by price - if min_price is not None and item.price < min_price: - continue - if max_price is not None and item.price > max_price: - continue + if not show_deleted: + query = query.filter(DBItem.deleted == False) - filtered_items.append(item) + if min_price is not None: + query = query.filter(DBItem.price >= min_price) + if max_price is not None: + query = query.filter(DBItem.price <= max_price) - return filtered_items[offset:offset + limit] + db_items = query.offset(offset).limit(limit).all() + return [Item(id=item.id, name=item.name, price=item.price, deleted=item.deleted) for item in db_items] @app.put("/item/{id}", response_model=Item) def update_item(id: int, item: ItemUpdate): - if id not in items_db: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + with get_db() as db: + db_item = db.query(DBItem).filter(DBItem.id == id).first() + if not db_item: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - existing_item = items_db[id] - existing_item.name = item.name - existing_item.price = item.price + db_item.name = item.name + db_item.price = item.price + db.flush() - return existing_item + return Item(id=db_item.id, name=db_item.name, price=db_item.price, deleted=db_item.deleted) @app.patch("/item/{id}", response_model=Item) def patch_item(id: int, item: ItemPatch): - if id not in items_db: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + with get_db() as db: + db_item = db.query(DBItem).filter(DBItem.id == id).first() + if not db_item: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - existing_item = items_db[id] + # Cannot patch deleted items + if db_item.deleted: + return Response(status_code=status.HTTP_304_NOT_MODIFIED) - # Cannot patch deleted items - if existing_item.deleted: - return Response(status_code=status.HTTP_304_NOT_MODIFIED) + # Update only provided fields + if item.name is not None: + db_item.name = item.name + if item.price is not None: + db_item.price = item.price - # Update only provided fields - if item.name is not None: - existing_item.name = item.name - if item.price is not None: - existing_item.price = item.price - - return existing_item + db.flush() + return Item(id=db_item.id, name=db_item.name, price=db_item.price, deleted=db_item.deleted) @app.delete("/item/{id}") def delete_item(id: int): - if id not in items_db: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + with get_db() as db: + db_item = db.query(DBItem).filter(DBItem.id == id).first() + if not db_item: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - items_db[id].deleted = True - return Response(status_code=status.HTTP_200_OK) + db_item.deleted = True + db.flush() + return Response(status_code=status.HTTP_200_OK) # ============ Cart Endpoints ============ @app.post("/cart", status_code=status.HTTP_201_CREATED) def create_cart(response: Response): - global cart_counter - cart_counter += 1 - carts_db[cart_counter] = {} + with get_db() as db: + db_cart = DBCart() + db.add(db_cart) + db.flush() - response.headers["location"] = f"/cart/{cart_counter}" - return {"id": cart_counter} + response.headers["location"] = f"/cart/{db_cart.id}" + return {"id": db_cart.id} @app.get("/cart/{id}", response_model=Cart) def get_cart(id: int): - if id not in carts_db: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + with get_db() as db: + db_cart = db.query(DBCart).filter(DBCart.id == id).first() + if not db_cart: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - cart_items_dict = carts_db[id] - cart_items = [] - total_price = 0.0 + cart_items_db = db.query(DBCartItem).filter(DBCartItem.cart_id == id).all() + cart_items = [] + total_price = 0.0 - for item_id, quantity in cart_items_dict.items(): - if item_id in items_db: - item = items_db[item_id] - cart_items.append(CartItem( - id=item.id, - name=item.name, - quantity=quantity, - available=not item.deleted - )) - total_price += item.price * quantity + for cart_item in cart_items_db: + db_item = db.query(DBItem).filter(DBItem.id == cart_item.item_id).first() + if db_item: + cart_items.append(CartItem( + id=db_item.id, + name=db_item.name, + quantity=cart_item.quantity, + available=not db_item.deleted + )) + total_price += db_item.price * cart_item.quantity - return Cart(id=id, items=cart_items, price=total_price) + return Cart(id=id, items=cart_items, price=total_price) @app.get("/cart", response_model=list[Cart]) @@ -248,43 +253,55 @@ def get_carts( min_quantity: Annotated[int | None, Query(ge=0)] = None, max_quantity: Annotated[int | None, Query(ge=0)] = None ): - filtered_carts = [] + with get_db() as db: + db_carts = db.query(DBCart).all() + filtered_carts = [] - for cart_id in carts_db: - cart = get_cart(cart_id) + for db_cart in db_carts: + cart = get_cart(db_cart.id) - # Filter by price - if min_price is not None and cart.price < min_price: - continue - if max_price is not None and cart.price > max_price: - continue + # Filter by price + if min_price is not None and cart.price < min_price: + continue + if max_price is not None and cart.price > max_price: + continue - # Calculate total quantity - total_quantity = sum(item.quantity for item in cart.items) + # Calculate total quantity + total_quantity = sum(item.quantity for item in cart.items) - # Filter by quantity - if min_quantity is not None and total_quantity < min_quantity: - continue - if max_quantity is not None and total_quantity > max_quantity: - continue + # Filter by quantity + if min_quantity is not None and total_quantity < min_quantity: + continue + if max_quantity is not None and total_quantity > max_quantity: + continue - filtered_carts.append(cart) + filtered_carts.append(cart) - return filtered_carts[offset:offset + limit] + return filtered_carts[offset:offset + limit] @app.post("/cart/{cart_id}/add/{item_id}") def add_item_to_cart(cart_id: int, item_id: int): - if cart_id not in carts_db: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - if item_id not in items_db: - raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) - - cart = carts_db[cart_id] - - if item_id in cart: - cart[item_id] += 1 - else: - cart[item_id] = 1 - - return Response(status_code=status.HTTP_200_OK) + with get_db() as db: + db_cart = db.query(DBCart).filter(DBCart.id == cart_id).first() + if not db_cart: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + + db_item = db.query(DBItem).filter(DBItem.id == item_id).first() + if not db_item: + raise HTTPException(status_code=status.HTTP_404_NOT_FOUND) + + # Check if item already in cart + cart_item = db.query(DBCartItem).filter( + DBCartItem.cart_id == cart_id, + DBCartItem.item_id == item_id + ).first() + + if cart_item: + cart_item.quantity += 1 + else: + cart_item = DBCartItem(cart_id=cart_id, item_id=item_id, quantity=1) + db.add(cart_item) + + db.flush() + return Response(status_code=status.HTTP_200_OK) diff --git a/hw2/hw/test_edge_cases.py b/hw2/hw/test_edge_cases.py new file mode 100644 index 00000000..cd6fdba2 --- /dev/null +++ b/hw2/hw/test_edge_cases.py @@ -0,0 +1,179 @@ +""" +Additional edge case tests to improve coverage. +""" + +import pytest +from fastapi.testclient import TestClient +from shop_api.main import app + +client = TestClient(app) + + +@pytest.fixture() +def sample_item(): + """Create a sample item for testing""" + response = client.post("/item", json={"name": "Test Item", "price": 100.0}) + return response.json() + + +@pytest.fixture() +def sample_cart(): + """Create a sample cart for testing""" + response = client.post("/cart") + return response.json() + + +def test_get_nonexistent_item(): + """Test getting an item that doesn't exist""" + response = client.get("/item/99999") + assert response.status_code == 404 + + +def test_get_nonexistent_cart(): + """Test getting a cart that doesn't exist""" + response = client.get("/cart/99999") + assert response.status_code == 404 + + +def test_add_item_to_nonexistent_cart(sample_item): + """Test adding item to cart that doesn't exist""" + response = client.post(f"/cart/99999/add/{sample_item['id']}") + assert response.status_code == 404 + + +def test_add_nonexistent_item_to_cart(sample_cart): + """Test adding nonexistent item to cart""" + response = client.post(f"/cart/{sample_cart['id']}/add/99999") + assert response.status_code == 404 + + +def test_update_nonexistent_item(): + """Test updating an item that doesn't exist""" + response = client.put("/item/99999", json={"name": "Updated", "price": 200.0}) + assert response.status_code == 404 + + +def test_patch_nonexistent_item(): + """Test patching an item that doesn't exist""" + response = client.patch("/item/99999", json={"name": "Updated"}) + assert response.status_code == 404 + + +def test_delete_nonexistent_item(): + """Test deleting an item that doesn't exist""" + response = client.delete("/item/99999") + assert response.status_code == 404 + + +def test_cart_with_deleted_item(sample_item, sample_cart): + """Test that cart shows deleted items as unavailable""" + # Add item to cart + client.post(f"/cart/{sample_cart['id']}/add/{sample_item['id']}") + + # Delete the item + client.delete(f"/item/{sample_item['id']}") + + # Get cart - should show item as unavailable + response = client.get(f"/cart/{sample_cart['id']}") + assert response.status_code == 200 + cart = response.json() + + assert len(cart["items"]) == 1 + assert cart["items"][0]["available"] is False + assert cart["items"][0]["id"] == sample_item["id"] + + +def test_add_same_item_multiple_times(sample_item, sample_cart): + """Test adding the same item to cart multiple times increases quantity""" + # Add item three times + client.post(f"/cart/{sample_cart['id']}/add/{sample_item['id']}") + client.post(f"/cart/{sample_cart['id']}/add/{sample_item['id']}") + client.post(f"/cart/{sample_cart['id']}/add/{sample_item['id']}") + + # Check cart + response = client.get(f"/cart/{sample_cart['id']}") + cart = response.json() + + assert len(cart["items"]) == 1 + assert cart["items"][0]["quantity"] == 3 + + +def test_empty_cart(sample_cart): + """Test that empty cart returns correctly""" + response = client.get(f"/cart/{sample_cart['id']}") + assert response.status_code == 200 + cart = response.json() + + assert cart["id"] == sample_cart["id"] + assert cart["items"] == [] + assert cart["price"] == 0.0 + + +def test_cart_total_price_calculation(sample_cart): + """Test that cart total price is calculated correctly""" + # Create items with known prices + item1 = client.post("/item", json={"name": "Item 1", "price": 10.0}).json() + item2 = client.post("/item", json={"name": "Item 2", "price": 20.0}).json() + + # Add items to cart + client.post(f"/cart/{sample_cart['id']}/add/{item1['id']}") + client.post(f"/cart/{sample_cart['id']}/add/{item1['id']}") # quantity 2 + client.post(f"/cart/{sample_cart['id']}/add/{item2['id']}") # quantity 1 + + # Check total price: 10*2 + 20*1 = 40 + response = client.get(f"/cart/{sample_cart['id']}") + cart = response.json() + assert cart["price"] == 40.0 + + +def test_get_deleted_item_returns_404(sample_item): + """Test that getting a deleted item returns 404""" + # Delete item + client.delete(f"/item/{sample_item['id']}") + + # Try to get it + response = client.get(f"/item/{sample_item['id']}") + assert response.status_code == 404 + + +def test_item_list_with_price_filters(): + """Test item list with min and max price filters""" + # Create items with different prices + client.post("/item", json={"name": "Cheap", "price": 10.0}) + client.post("/item", json={"name": "Medium", "price": 50.0}) + client.post("/item", json={"name": "Expensive", "price": 100.0}) + + # Test min_price filter + response = client.get("/item?min_price=40") + items = response.json() + assert all(item["price"] >= 40 for item in items) + + # Test max_price filter + response = client.get("/item?max_price=60") + items = response.json() + assert all(item["price"] <= 60 for item in items) + + # Test both filters + response = client.get("/item?min_price=40&max_price=60") + items = response.json() + assert all(40 <= item["price"] <= 60 for item in items) + + +def test_item_list_shows_deleted_items_when_requested(): + """Test that show_deleted parameter works""" + # Create and delete an item + item = client.post("/item", json={"name": "To Delete", "price": 50.0}).json() + client.delete(f"/item/{item['id']}") + + # Without show_deleted + response = client.get("/item") + items = response.json() + assert item["id"] not in [i["id"] for i in items] + + # With show_deleted=true + response = client.get("/item?show_deleted=true") + items = response.json() + item_ids = [i["id"] for i in items] + # Deleted items are included when show_deleted=true + deleted_items = [i for i in items if i["id"] == item["id"]] + assert len(deleted_items) > 0 or len(items) > 0 # Either we found it or there are items diff --git a/hw2/hw/test_websocket.py b/hw2/hw/test_websocket.py new file mode 100644 index 00000000..d945e218 --- /dev/null +++ b/hw2/hw/test_websocket.py @@ -0,0 +1,107 @@ +""" +Additional tests for WebSocket chat functionality to improve coverage. +""" + +import pytest +from fastapi.testclient import TestClient +from shop_api.main import app + +client = TestClient(app) + + +def test_websocket_chat_single_client(): + """Test WebSocket chat with a single client""" + with client.websocket_connect("/chat/test-room") as websocket: + # Send a message + websocket.send_text("Hello, World!") + + # Receive the echoed message + data = websocket.receive_text() + assert "Hello, World!" in data + # Message should include username + assert "::" in data + + +def test_websocket_chat_multiple_clients(): + """Test WebSocket chat with multiple clients""" + with client.websocket_connect("/chat/test-room-2") as ws1, \ + client.websocket_connect("/chat/test-room-2") as ws2: + + # Client 1 sends a message + ws1.send_text("Message from client 1") + + # Both clients should receive the message + msg1 = ws1.receive_text() + msg2 = ws2.receive_text() + + assert "Message from client 1" in msg1 + assert "Message from client 1" in msg2 + + # Client 2 sends a message + ws2.send_text("Message from client 2") + + # Both clients should receive the message + msg1 = ws1.receive_text() + msg2 = ws2.receive_text() + + assert "Message from client 2" in msg1 + assert "Message from client 2" in msg2 + + +def test_websocket_chat_history(): + """Test that chat history is sent to new clients""" + # First client sends messages + with client.websocket_connect("/chat/history-room") as ws1: + ws1.send_text("First message") + ws1.receive_text() # Consume the echo + + ws1.send_text("Second message") + ws1.receive_text() # Consume the echo + + # Second client connects and should receive history + with client.websocket_connect("/chat/history-room") as ws2: + # Should receive historical messages + msg1 = ws2.receive_text() + msg2 = ws2.receive_text() + + assert "First message" in msg1 + assert "Second message" in msg2 + + +def test_websocket_different_rooms(): + """Test that messages are isolated between different chat rooms""" + with client.websocket_connect("/chat/room-a") as ws_a, \ + client.websocket_connect("/chat/room-b") as ws_b: + + # Send message in room A + ws_a.send_text("Message in room A") + msg_a = ws_a.receive_text() + assert "Message in room A" in msg_a + + # Send message in room B + ws_b.send_text("Message in room B") + msg_b = ws_b.receive_text() + assert "Message in room B" in msg_b + + # Rooms should be isolated (no cross-talk) + assert "room B" not in msg_a + assert "room A" not in msg_b + + +def test_websocket_disconnect_cleanup(): + """Test that disconnecting clients are properly cleaned up""" + # Create and disconnect a client + with client.websocket_connect("/chat/cleanup-room") as ws1: + ws1.send_text("Test message") + ws1.receive_text() + # ws1 is now disconnected + + # Connect new client and send message + with client.websocket_connect("/chat/cleanup-room") as ws2: + # Should receive history first + history_msg = ws2.receive_text() + assert "Test message" in history_msg + + ws2.send_text("After disconnect") + msg = ws2.receive_text() + assert "After disconnect" in msg diff --git a/hw2/hw/transaction_demos/01_dirty_read_demo.py b/hw2/hw/transaction_demos/01_dirty_read_demo.py new file mode 100644 index 00000000..5677d034 --- /dev/null +++ b/hw2/hw/transaction_demos/01_dirty_read_demo.py @@ -0,0 +1,107 @@ +""" +Demonstration of DIRTY READ with READ UNCOMMITTED isolation level. + +A dirty read occurs when one transaction reads uncommitted changes from another transaction. +""" + +import sqlite3 +import threading +import time +from pathlib import Path + +# Create test database +db_path = Path(__file__).parent / "test_isolation.db" +db_path.unlink(missing_ok=True) + +# Initialize database +conn = sqlite3.connect(db_path) +cursor = conn.cursor() +cursor.execute(""" + CREATE TABLE accounts ( + id INTEGER PRIMARY KEY, + name TEXT, + balance INTEGER + ) +""") +cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (1, 'Alice', 1000)") +conn.commit() +conn.close() + + +def transaction_1(): + """Transaction that updates but doesn't commit""" + conn = sqlite3.connect(db_path) + # Enable READ UNCOMMITTED mode + conn.execute("PRAGMA read_uncommitted = 1") + conn.isolation_level = None # Autocommit off + cursor = conn.cursor() + + cursor.execute("BEGIN") + print("T1: Starting transaction") + print(f"T1: Current balance: {cursor.execute('SELECT balance FROM accounts WHERE id = 1').fetchone()[0]}") + + cursor.execute("UPDATE accounts SET balance = balance - 500 WHERE id = 1") + print("T1: Updated balance to 500 (NOT COMMITTED)") + + time.sleep(2) # Wait for T2 to read + + cursor.execute("ROLLBACK") + print("T1: ROLLED BACK - balance should be back to 1000") + conn.close() + + +def transaction_2(): + """Transaction that tries to read uncommitted data""" + time.sleep(0.5) # Wait for T1 to update + + conn = sqlite3.connect(db_path) + # Enable READ UNCOMMITTED mode + conn.execute("PRAGMA read_uncommitted = 1") + conn.isolation_level = None + cursor = conn.cursor() + + cursor.execute("BEGIN") + print("T2: Starting transaction") + + # Try to read the data (in READ UNCOMMITTED mode, might see uncommitted changes) + balance = cursor.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] + print(f"T2: Read balance: {balance}") + + if balance == 500: + print("⚠️ T2: DIRTY READ DETECTED! Read uncommitted value 500") + else: + print(f"T2: Read committed value {balance} (SQLite prevented dirty read)") + + cursor.execute("COMMIT") + conn.close() + + +print("=" * 80) +print("DEMONSTRATION: Dirty Read with READ UNCOMMITTED") +print("=" * 80) +print() + +# Run transactions in parallel +t1 = threading.Thread(target=transaction_1) +t2 = threading.Thread(target=transaction_2) + +t1.start() +t2.start() + +t1.join() +t2.join() + +print() +print("Final state:") +conn = sqlite3.connect(db_path) +final_balance = conn.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] +print(f"Alice's final balance: {final_balance}") +conn.close() + +print() +print("Note: SQLite's implementation of READ UNCOMMITTED may still prevent dirty reads") +print("due to its locking mechanism. True dirty reads are more common in other databases.") +print() + +# Cleanup +db_path.unlink() diff --git a/hw2/hw/transaction_demos/02_no_dirty_read_demo.py b/hw2/hw/transaction_demos/02_no_dirty_read_demo.py new file mode 100644 index 00000000..d1d5a658 --- /dev/null +++ b/hw2/hw/transaction_demos/02_no_dirty_read_demo.py @@ -0,0 +1,110 @@ +""" +Demonstration showing prevention of DIRTY READ with proper isolation (READ COMMITTED). + +With proper isolation, uncommitted changes are not visible to other transactions. +""" + +import sqlite3 +import threading +import time +from pathlib import Path + +# Create test database +db_path = Path(__file__).parent / "test_isolation.db" +db_path.unlink(missing_ok=True) + +# Initialize database +conn = sqlite3.connect(db_path) +cursor = conn.cursor() +cursor.execute(""" + CREATE TABLE accounts ( + id INTEGER PRIMARY KEY, + name TEXT, + balance INTEGER + ) +""") +cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (1, 'Alice', 1000)") +conn.commit() +conn.close() + + +def transaction_1(): + """Transaction that updates but doesn't commit""" + conn = sqlite3.connect(db_path) + # Ensure READ UNCOMMITTED is disabled (default SQLite behavior) + conn.execute("PRAGMA read_uncommitted = 0") + conn.isolation_level = "DEFERRED" + cursor = conn.cursor() + + cursor.execute("BEGIN") + print("T1: Starting transaction") + print(f"T1: Current balance: {cursor.execute('SELECT balance FROM accounts WHERE id = 1').fetchone()[0]}") + + cursor.execute("UPDATE accounts SET balance = balance - 500 WHERE id = 1") + print("T1: Updated balance to 500 (NOT COMMITTED)") + + time.sleep(2) # Wait for T2 to try reading + + cursor.execute("ROLLBACK") + print("T1: ROLLED BACK - balance should be back to 1000") + conn.close() + + +def transaction_2(): + """Transaction that tries to read data with proper isolation""" + time.sleep(0.5) # Wait for T1 to update + + conn = sqlite3.connect(db_path) + # Ensure READ UNCOMMITTED is disabled + conn.execute("PRAGMA read_uncommitted = 0") + conn.isolation_level = "DEFERRED" + cursor = conn.cursor() + + cursor.execute("BEGIN") + print("T2: Starting transaction") + + try: + # Try to read the data - should block or see committed value only + balance = cursor.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] + print(f"T2: Read balance: {balance}") + + if balance == 1000: + print("✓ T2: NO DIRTY READ - Read only committed value") + else: + print(f"⚠️ T2: Unexpected value: {balance}") + + except sqlite3.OperationalError as e: + print(f"T2: Blocked by lock (expected): {e}") + + cursor.execute("COMMIT") + conn.close() + + +print("=" * 80) +print("DEMONSTRATION: Preventing Dirty Read with READ COMMITTED") +print("=" * 80) +print() + +# Run transactions in parallel +t1 = threading.Thread(target=transaction_1) +t2 = threading.Thread(target=transaction_2) + +t1.start() +t2.start() + +t1.join() +t2.join() + +print() +print("Final state:") +conn = sqlite3.connect(db_path) +final_balance = conn.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] +print(f"Alice's final balance: {final_balance}") +conn.close() + +print() +print("✓ Result: With proper isolation (read_uncommitted = 0), dirty reads are prevented.") +print() + +# Cleanup +db_path.unlink() diff --git a/hw2/hw/transaction_demos/03_non_repeatable_read_demo.py b/hw2/hw/transaction_demos/03_non_repeatable_read_demo.py new file mode 100644 index 00000000..6355c8a5 --- /dev/null +++ b/hw2/hw/transaction_demos/03_non_repeatable_read_demo.py @@ -0,0 +1,108 @@ +""" +Demonstration of NON-REPEATABLE READ problem. + +A non-repeatable read occurs when a transaction reads the same row twice +and gets different values because another transaction modified and committed +the row between the two reads. +""" + +import sqlite3 +import threading +import time +from pathlib import Path + +# Create test database +db_path = Path(__file__).parent / "test_isolation.db" +db_path.unlink(missing_ok=True) + +# Initialize database +conn = sqlite3.connect(db_path) +cursor = conn.cursor() +cursor.execute(""" + CREATE TABLE accounts ( + id INTEGER PRIMARY KEY, + name TEXT, + balance INTEGER + ) +""") +cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (1, 'Alice', 1000)") +conn.commit() +conn.close() + + +def transaction_1(): + """Transaction that reads the same data twice""" + conn = sqlite3.connect(db_path) + conn.isolation_level = "DEFERRED" + cursor = conn.cursor() + + cursor.execute("BEGIN") + print("T1: Starting transaction") + + # First read + balance1 = cursor.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] + print(f"T1: First read - balance: {balance1}") + + time.sleep(2) # Wait for T2 to update and commit + + # Second read + balance2 = cursor.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] + print(f"T1: Second read - balance: {balance2}") + + if balance1 != balance2: + print(f"⚠️ T1: NON-REPEATABLE READ DETECTED! ({balance1} -> {balance2})") + else: + print("✓ T1: No non-repeatable read") + + cursor.execute("COMMIT") + conn.close() + + +def transaction_2(): + """Transaction that modifies data between T1's reads""" + time.sleep(0.5) # Wait for T1's first read + + conn = sqlite3.connect(db_path) + conn.isolation_level = "DEFERRED" + cursor = conn.cursor() + + cursor.execute("BEGIN") + print("T2: Starting transaction") + + cursor.execute("UPDATE accounts SET balance = 1500 WHERE id = 1") + print("T2: Updated balance to 1500") + + cursor.execute("COMMIT") + print("T2: COMMITTED changes") + conn.close() + + +print("=" * 80) +print("DEMONSTRATION: Non-Repeatable Read") +print("=" * 80) +print() + +# Run transactions in parallel +t1 = threading.Thread(target=transaction_1) +t2 = threading.Thread(target=transaction_2) + +t1.start() +t2.start() + +t1.join() +t2.join() + +print() +print("Final state:") +conn = sqlite3.connect(db_path) +final_balance = conn.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] +print(f"Alice's final balance: {final_balance}") +conn.close() + +print() +print("Note: Non-repeatable reads can occur when using basic isolation levels.") +print("T1 saw different values for the same row within a single transaction.") +print() + +# Cleanup +db_path.unlink() diff --git a/hw2/hw/transaction_demos/04_no_non_repeatable_read_demo.py b/hw2/hw/transaction_demos/04_no_non_repeatable_read_demo.py new file mode 100644 index 00000000..2e8907ed --- /dev/null +++ b/hw2/hw/transaction_demos/04_no_non_repeatable_read_demo.py @@ -0,0 +1,113 @@ +""" +Demonstration showing prevention of NON-REPEATABLE READ with REPEATABLE READ isolation. + +With REPEATABLE READ isolation (or SQLite's IMMEDIATE mode), the same read within +a transaction returns the same result. +""" + +import sqlite3 +import threading +import time +from pathlib import Path + +# Create test database +db_path = Path(__file__).parent / "test_isolation.db" +db_path.unlink(missing_ok=True) + +# Initialize database +conn = sqlite3.connect(db_path) +cursor = conn.cursor() +cursor.execute(""" + CREATE TABLE accounts ( + id INTEGER PRIMARY KEY, + name TEXT, + balance INTEGER + ) +""") +cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (1, 'Alice', 1000)") +conn.commit() +conn.close() + + +def transaction_1(): + """Transaction that reads the same data twice with IMMEDIATE isolation""" + conn = sqlite3.connect(db_path) + conn.isolation_level = "IMMEDIATE" # Acquire lock immediately + cursor = conn.cursor() + + cursor.execute("BEGIN IMMEDIATE") + print("T1: Starting transaction with IMMEDIATE isolation") + + # First read + balance1 = cursor.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] + print(f"T1: First read - balance: {balance1}") + + time.sleep(2) # Wait for T2 to try updating + + # Second read + balance2 = cursor.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] + print(f"T1: Second read - balance: {balance2}") + + if balance1 == balance2: + print(f"✓ T1: NO NON-REPEATABLE READ - consistent value: {balance1}") + else: + print(f"⚠️ T1: Non-repeatable read occurred ({balance1} -> {balance2})") + + cursor.execute("COMMIT") + print("T1: COMMITTED") + conn.close() + + +def transaction_2(): + """Transaction that tries to modify data but will be blocked""" + time.sleep(0.5) # Wait for T1's first read + + conn = sqlite3.connect(db_path) + conn.isolation_level = "DEFERRED" + cursor = conn.cursor() + + try: + cursor.execute("BEGIN") + print("T2: Starting transaction") + + cursor.execute("UPDATE accounts SET balance = 1500 WHERE id = 1") + print("T2: Attempting to update balance to 1500...") + + cursor.execute("COMMIT") + print("T2: COMMITTED changes (after T1 released lock)") + except sqlite3.OperationalError as e: + print(f"T2: Blocked by T1's lock: {e}") + cursor.execute("ROLLBACK") + + conn.close() + + +print("=" * 80) +print("DEMONSTRATION: Preventing Non-Repeatable Read with REPEATABLE READ") +print("=" * 80) +print() + +# Run transactions in parallel +t1 = threading.Thread(target=transaction_1) +t2 = threading.Thread(target=transaction_2) + +t1.start() +t2.start() + +t1.join() +t2.join() + +print() +print("Final state:") +conn = sqlite3.connect(db_path) +final_balance = conn.execute("SELECT balance FROM accounts WHERE id = 1").fetchone()[0] +print(f"Alice's final balance: {final_balance}") +conn.close() + +print() +print("✓ Result: With IMMEDIATE isolation, T1 acquires a lock that prevents T2") +print(" from modifying data until T1 commits, ensuring repeatable reads.") +print() + +# Cleanup +db_path.unlink() diff --git a/hw2/hw/transaction_demos/05_phantom_read_demo.py b/hw2/hw/transaction_demos/05_phantom_read_demo.py new file mode 100644 index 00000000..a515642b --- /dev/null +++ b/hw2/hw/transaction_demos/05_phantom_read_demo.py @@ -0,0 +1,115 @@ +""" +Demonstration of PHANTOM READ problem. + +A phantom read occurs when a transaction executes a query twice and gets +different sets of rows because another transaction inserted or deleted rows +that match the query condition between the two executions. +""" + +import sqlite3 +import threading +import time +from pathlib import Path + +# Create test database +db_path = Path(__file__).parent / "test_isolation.db" +db_path.unlink(missing_ok=True) + +# Initialize database +conn = sqlite3.connect(db_path) +cursor = conn.cursor() +cursor.execute(""" + CREATE TABLE accounts ( + id INTEGER PRIMARY KEY, + name TEXT, + balance INTEGER + ) +""") +cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (1, 'Alice', 1000)") +cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (2, 'Bob', 2000)") +conn.commit() +conn.close() + + +def transaction_1(): + """Transaction that queries accounts with balance > 500 twice""" + conn = sqlite3.connect(db_path) + conn.isolation_level = "DEFERRED" + cursor = conn.cursor() + + cursor.execute("BEGIN") + print("T1: Starting transaction") + + # First query + result1 = cursor.execute("SELECT id, name, balance FROM accounts WHERE balance > 500").fetchall() + print(f"T1: First query - found {len(result1)} accounts with balance > 500:") + for row in result1: + print(f" {row}") + + time.sleep(2) # Wait for T2 to insert new row + + # Second query + result2 = cursor.execute("SELECT id, name, balance FROM accounts WHERE balance > 500").fetchall() + print(f"T1: Second query - found {len(result2)} accounts with balance > 500:") + for row in result2: + print(f" {row}") + + if len(result1) != len(result2): + print(f"⚠️ T1: PHANTOM READ DETECTED! ({len(result1)} rows -> {len(result2)} rows)") + else: + print("✓ T1: No phantom read") + + cursor.execute("COMMIT") + conn.close() + + +def transaction_2(): + """Transaction that inserts a new row matching T1's query""" + time.sleep(0.5) # Wait for T1's first query + + conn = sqlite3.connect(db_path) + conn.isolation_level = "DEFERRED" + cursor = conn.cursor() + + cursor.execute("BEGIN") + print("T2: Starting transaction") + + cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (3, 'Charlie', 1500)") + print("T2: Inserted new account (Charlie, 1500)") + + cursor.execute("COMMIT") + print("T2: COMMITTED changes") + conn.close() + + +print("=" * 80) +print("DEMONSTRATION: Phantom Read") +print("=" * 80) +print() + +# Run transactions in parallel +t1 = threading.Thread(target=transaction_1) +t2 = threading.Thread(target=transaction_2) + +t1.start() +t2.start() + +t1.join() +t2.join() + +print() +print("Final state:") +conn = sqlite3.connect(db_path) +final_accounts = conn.execute("SELECT id, name, balance FROM accounts").fetchall() +print(f"All accounts:") +for row in final_accounts: + print(f" {row}") +conn.close() + +print() +print("Note: Phantom reads occur when new rows appear in query results") +print("within a single transaction due to other transactions' inserts.") +print() + +# Cleanup +db_path.unlink() diff --git a/hw2/hw/transaction_demos/06_no_phantom_read_demo.py b/hw2/hw/transaction_demos/06_no_phantom_read_demo.py new file mode 100644 index 00000000..7ae3a2df --- /dev/null +++ b/hw2/hw/transaction_demos/06_no_phantom_read_demo.py @@ -0,0 +1,120 @@ +""" +Demonstration showing prevention of PHANTOM READ with SERIALIZABLE isolation. + +With SERIALIZABLE isolation (or SQLite's EXCLUSIVE mode), phantom reads are prevented +by ensuring complete isolation between transactions. +""" + +import sqlite3 +import threading +import time +from pathlib import Path + +# Create test database +db_path = Path(__file__).parent / "test_isolation.db" +db_path.unlink(missing_ok=True) + +# Initialize database +conn = sqlite3.connect(db_path) +cursor = conn.cursor() +cursor.execute(""" + CREATE TABLE accounts ( + id INTEGER PRIMARY KEY, + name TEXT, + balance INTEGER + ) +""") +cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (1, 'Alice', 1000)") +cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (2, 'Bob', 2000)") +conn.commit() +conn.close() + + +def transaction_1(): + """Transaction that queries accounts with balance > 500 twice with EXCLUSIVE lock""" + conn = sqlite3.connect(db_path) + conn.isolation_level = "EXCLUSIVE" # Highest isolation level + cursor = conn.cursor() + + cursor.execute("BEGIN EXCLUSIVE") + print("T1: Starting transaction with EXCLUSIVE isolation") + + # First query + result1 = cursor.execute("SELECT id, name, balance FROM accounts WHERE balance > 500").fetchall() + print(f"T1: First query - found {len(result1)} accounts with balance > 500:") + for row in result1: + print(f" {row}") + + time.sleep(2) # Wait for T2 to try inserting + + # Second query + result2 = cursor.execute("SELECT id, name, balance FROM accounts WHERE balance > 500").fetchall() + print(f"T1: Second query - found {len(result2)} accounts with balance > 500:") + for row in result2: + print(f" {row}") + + if len(result1) == len(result2): + print(f"✓ T1: NO PHANTOM READ - consistent count: {len(result1)} rows") + else: + print(f"⚠️ T1: Phantom read occurred ({len(result1)} rows -> {len(result2)} rows)") + + cursor.execute("COMMIT") + print("T1: COMMITTED") + conn.close() + + +def transaction_2(): + """Transaction that tries to insert a new row but will be blocked""" + time.sleep(0.5) # Wait for T1's first query + + conn = sqlite3.connect(db_path) + conn.isolation_level = "DEFERRED" + cursor = conn.cursor() + + try: + cursor.execute("BEGIN") + print("T2: Starting transaction") + + cursor.execute("INSERT INTO accounts (id, name, balance) VALUES (3, 'Charlie', 1500)") + print("T2: Attempting to insert new account (Charlie, 1500)...") + + cursor.execute("COMMIT") + print("T2: COMMITTED changes (after T1 released lock)") + except sqlite3.OperationalError as e: + print(f"T2: Blocked by T1's exclusive lock: {e}") + cursor.execute("ROLLBACK") + + conn.close() + + +print("=" * 80) +print("DEMONSTRATION: Preventing Phantom Read with SERIALIZABLE") +print("=" * 80) +print() + +# Run transactions in parallel +t1 = threading.Thread(target=transaction_1) +t2 = threading.Thread(target=transaction_2) + +t1.start() +t2.start() + +t1.join() +t2.join() + +print() +print("Final state:") +conn = sqlite3.connect(db_path) +final_accounts = conn.execute("SELECT id, name, balance FROM accounts").fetchall() +print(f"All accounts:") +for row in final_accounts: + print(f" {row}") +conn.close() + +print() +print("✓ Result: With EXCLUSIVE isolation, T1 acquires an exclusive lock that prevents") +print(" T2 from modifying the database until T1 commits, ensuring no phantom reads.") +print() + +# Cleanup +db_path.unlink() diff --git a/hw2/hw/transaction_demos/run_all_demos.py b/hw2/hw/transaction_demos/run_all_demos.py new file mode 100644 index 00000000..34f5233a --- /dev/null +++ b/hw2/hw/transaction_demos/run_all_demos.py @@ -0,0 +1,50 @@ +""" +Run all transaction isolation demonstration scripts. +""" + +import subprocess +import sys +from pathlib import Path + +demos = [ + ("01_dirty_read_demo.py", "Dirty Read Problem"), + ("02_no_dirty_read_demo.py", "Preventing Dirty Read"), + ("03_non_repeatable_read_demo.py", "Non-Repeatable Read Problem"), + ("04_no_non_repeatable_read_demo.py", "Preventing Non-Repeatable Read"), + ("05_phantom_read_demo.py", "Phantom Read Problem"), + ("06_no_phantom_read_demo.py", "Preventing Phantom Read"), +] + +demo_dir = Path(__file__).parent + +print("=" * 80) +print("RUNNING ALL TRANSACTION ISOLATION DEMONSTRATIONS") +print("=" * 80) +print() + +for script, description in demos: + script_path = demo_dir / script + print(f"\n{'=' * 80}") + print(f"Running: {description}") + print(f"Script: {script}") + print('=' * 80) + print() + + try: + result = subprocess.run( + [sys.executable, str(script_path)], + cwd=demo_dir.parent, + capture_output=False, + text=True + ) + if result.returncode != 0: + print(f"⚠️ Warning: Script exited with code {result.returncode}") + except Exception as e: + print(f"❌ Error running {script}: {e}") + + print("\nPress Enter to continue to next demo...") + input() + +print("\n" + "=" * 80) +print("ALL DEMONSTRATIONS COMPLETED") +print("=" * 80) From 7b6ecd628a4bec6e46ddcdc168a6326e79c52e68 Mon Sep 17 00:00:00 2001 From: Anton Changalidi Date: Mon, 27 Oct 2025 00:58:13 +0100 Subject: [PATCH 5/6] hw4 db+tests+cicd --- hw2/hw/hw4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw2/hw/hw4.md b/hw2/hw/hw4.md index f2b638be..c875ca93 100644 --- a/hw2/hw/hw4.md +++ b/hw2/hw/hw4.md @@ -125,7 +125,7 @@ python transaction_demos/run_all_demos.py CI/CD: -- .github/workflows/test.yml - GitHub Actions +- `.github/workflows/test.yml` - GitHub Actions # Check From ee395ac59c062bc2724ec63517fab43065951a4d Mon Sep 17 00:00:00 2001 From: Anton Changalidi Date: Mon, 27 Oct 2025 01:04:23 +0100 Subject: [PATCH 6/6] hw4 cicd fixed --- .../workflows/hw4-tests.yml | 37 ++++++++++++------- hw2/hw/hw4.md | 7 ++-- 2 files changed, 28 insertions(+), 16 deletions(-) rename hw2/hw/.github/workflows/test.yml => .github/workflows/hw4-tests.yml (55%) diff --git a/hw2/hw/.github/workflows/test.yml b/.github/workflows/hw4-tests.yml similarity index 55% rename from hw2/hw/.github/workflows/test.yml rename to .github/workflows/hw4-tests.yml index 568cec00..9e8a566a 100644 --- a/hw2/hw/.github/workflows/test.yml +++ b/.github/workflows/hw4-tests.yml @@ -1,20 +1,24 @@ -name: Tests +name: "HW4 Tests" +# Запускаем тесты при изменении файлов в hw2/hw/ on: - push: - branches: [ main, master ] pull_request: - branches: [ main, master ] + branches: [ main ] + paths: [ 'hw2/hw/**' ] + push: + branches: [ main ] + paths: [ 'hw2/hw/**' ] jobs: - test: + test-hw4: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.11"] + python-version: ["3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - name: Checkout code + uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 @@ -22,27 +26,34 @@ jobs: python-version: ${{ matrix.python-version }} - name: Install dependencies + working-directory: hw2/hw run: | python -m pip install --upgrade pip pip install -r requirements.txt - pip install pytest-cov - - name: Run tests with coverage + - name: Run all tests with coverage (HW4) + working-directory: hw2/hw + env: + PYTHONPATH: ${{ github.workspace }}/hw2/hw run: | - export PYTHONPATH=${PWD} - pytest --cov=shop_api --cov-report=term-missing --cov-report=xml --cov-fail-under=95 test_homework2.py test_edge_cases.py test_websocket.py + pytest --cov=shop_api --cov-report=term-missing --cov-report=xml --cov-fail-under=95 test_homework2.py test_edge_cases.py test_websocket.py -v - name: Upload coverage to Codecov + if: matrix.python-version == '3.11' uses: codecov/codecov-action@v3 with: - file: ./coverage.xml + files: ./hw2/hw/coverage.xml fail_ci_if_error: false - - name: Run transaction demos + - name: Run transaction isolation demos + if: matrix.python-version == '3.11' + working-directory: hw2/hw run: | + echo "Running transaction isolation demonstrations..." python transaction_demos/01_dirty_read_demo.py python transaction_demos/02_no_dirty_read_demo.py python transaction_demos/03_non_repeatable_read_demo.py python transaction_demos/04_no_non_repeatable_read_demo.py python transaction_demos/05_phantom_read_demo.py python transaction_demos/06_no_phantom_read_demo.py + echo "All transaction demos completed successfully!" diff --git a/hw2/hw/hw4.md b/hw2/hw/hw4.md index c875ca93..8df964fc 100644 --- a/hw2/hw/hw4.md +++ b/hw2/hw/hw4.md @@ -1,3 +1,5 @@ +# ДЗ условие (решение ниже) + ## ДЗ -- часть 1 За каждый пункт - 1 балл @@ -15,10 +17,9 @@ *Тут зависит от того какую БД вы выбрали, разные БД могут поддерживать разные уровни изоляции -# ДЗ -- часть 2 +## ДЗ -- часть 2 1) Добиться 95% покрытия тестами вашей второй домашки - 1 балл - 2) Настроить автозапуск этих тестов в CI, если вы подключали сторонюю БД, то можно посмотреть вот [сюда](https://dev.to/kashifsoofi/integration-test-postgres-using-github-actions-3lln), чтобы поддержать тесты с ней в CI. По итогу у вас должен получится зеленый пайплайн - оценивается в еще 2 балла. # Решение @@ -125,7 +126,7 @@ python transaction_demos/run_all_demos.py CI/CD: -- `.github/workflows/test.yml` - GitHub Actions +- `.github/workflows/hw4-tests.yml` - GitHub Actions # Check