All checks were successful
CI/CD Pipeline / VM Test - security (push) Successful in 7s
CI/CD Pipeline / Backend Linting (push) Successful in 4s
CI/CD Pipeline / VM Test - backend-integration (push) Successful in 11s
CI/CD Pipeline / VM Test - full-stack (push) Successful in 8s
CI/CD Pipeline / VM Test - performance (push) Successful in 8s
CI/CD Pipeline / Nix Flake Check (push) Successful in 38s
CI/CD Pipeline / CI Summary (push) Successful in 0s
CI/CD Pipeline / Frontend Linting (push) Successful in 17s
290 lines
7.5 KiB
Python
290 lines
7.5 KiB
Python
"""Integration tests for group endpoints."""
|
|
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
from httpx import AsyncClient
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.database.models.board import Board
|
|
from app.database.models.board_image import BoardImage
|
|
from app.database.models.image import Image
|
|
from app.database.models.user import User
|
|
|
|
pytestmark = pytest.mark.asyncio
|
|
|
|
|
|
async def test_create_group(client: AsyncClient, test_user: User, db: Session):
|
|
"""Test creating a group with images."""
|
|
# Create board
|
|
board = Board(
|
|
id=uuid4(),
|
|
user_id=test_user.id,
|
|
title="Test Board",
|
|
viewport_state={"x": 0, "y": 0, "zoom": 1.0, "rotation": 0},
|
|
)
|
|
db.add(board)
|
|
|
|
# Create images
|
|
images = []
|
|
for i in range(3):
|
|
image = Image(
|
|
id=uuid4(),
|
|
user_id=test_user.id,
|
|
filename=f"test{i}.jpg",
|
|
storage_path=f"{test_user.id}/test{i}.jpg",
|
|
file_size=1024,
|
|
mime_type="image/jpeg",
|
|
width=800,
|
|
height=600,
|
|
metadata={"format": "jpeg", "checksum": f"abc{i}"},
|
|
)
|
|
db.add(image)
|
|
images.append(image)
|
|
|
|
board_image = BoardImage(
|
|
id=uuid4(),
|
|
board_id=board.id,
|
|
image_id=image.id,
|
|
position={"x": 100, "y": 100},
|
|
transformations={"scale": 1.0, "rotation": 0, "opacity": 1.0},
|
|
z_order=i,
|
|
)
|
|
db.add(board_image)
|
|
|
|
db.commit()
|
|
|
|
# Create group
|
|
response = await client.post(
|
|
f"/api/boards/{board.id}/groups",
|
|
json={
|
|
"name": "Test Group",
|
|
"color": "#FF5733",
|
|
"annotation": "Group annotation",
|
|
"image_ids": [str(img.id) for img in images[:2]],
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 201
|
|
data = response.json()
|
|
assert data["name"] == "Test Group"
|
|
assert data["color"] == "#FF5733"
|
|
assert data["annotation"] == "Group annotation"
|
|
assert data["member_count"] == 2
|
|
|
|
|
|
async def test_list_groups(client: AsyncClient, test_user: User, db: Session):
|
|
"""Test listing groups on a board."""
|
|
from app.database.models.group import Group
|
|
|
|
board = Board(
|
|
id=uuid4(),
|
|
user_id=test_user.id,
|
|
title="Test Board",
|
|
viewport_state={"x": 0, "y": 0, "zoom": 1.0, "rotation": 0},
|
|
)
|
|
db.add(board)
|
|
|
|
# Create groups
|
|
for i in range(3):
|
|
group = Group(
|
|
id=uuid4(),
|
|
board_id=board.id,
|
|
name=f"Group {i}",
|
|
color=f"#FF573{i}",
|
|
annotation=f"Annotation {i}",
|
|
)
|
|
db.add(group)
|
|
|
|
db.commit()
|
|
|
|
# List groups
|
|
response = await client.get(f"/api/boards/{board.id}/groups")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert len(data) == 3
|
|
assert data[0]["name"] == "Group 2" # Most recent first
|
|
|
|
|
|
async def test_get_group(client: AsyncClient, test_user: User, db: Session):
|
|
"""Test getting a specific group."""
|
|
from app.database.models.group import Group
|
|
|
|
board = Board(
|
|
id=uuid4(),
|
|
user_id=test_user.id,
|
|
title="Test Board",
|
|
viewport_state={"x": 0, "y": 0, "zoom": 1.0, "rotation": 0},
|
|
)
|
|
db.add(board)
|
|
|
|
group = Group(
|
|
id=uuid4(),
|
|
board_id=board.id,
|
|
name="Test Group",
|
|
color="#FF5733",
|
|
annotation="Test annotation",
|
|
)
|
|
db.add(group)
|
|
db.commit()
|
|
|
|
# Get group
|
|
response = await client.get(f"/api/boards/{board.id}/groups/{group.id}")
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["name"] == "Test Group"
|
|
assert data["color"] == "#FF5733"
|
|
|
|
|
|
async def test_update_group(client: AsyncClient, test_user: User, db: Session):
|
|
"""Test updating group metadata."""
|
|
from app.database.models.group import Group
|
|
|
|
board = Board(
|
|
id=uuid4(),
|
|
user_id=test_user.id,
|
|
title="Test Board",
|
|
viewport_state={"x": 0, "y": 0, "zoom": 1.0, "rotation": 0},
|
|
)
|
|
db.add(board)
|
|
|
|
group = Group(
|
|
id=uuid4(),
|
|
board_id=board.id,
|
|
name="Original Name",
|
|
color="#FF5733",
|
|
annotation="Original annotation",
|
|
)
|
|
db.add(group)
|
|
db.commit()
|
|
|
|
# Update group
|
|
response = await client.patch(
|
|
f"/api/boards/{board.id}/groups/{group.id}",
|
|
json={
|
|
"name": "Updated Name",
|
|
"color": "#00FF00",
|
|
"annotation": "Updated annotation",
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 200
|
|
data = response.json()
|
|
assert data["name"] == "Updated Name"
|
|
assert data["color"] == "#00FF00"
|
|
assert data["annotation"] == "Updated annotation"
|
|
|
|
|
|
async def test_delete_group(client: AsyncClient, test_user: User, db: Session):
|
|
"""Test deleting a group."""
|
|
from app.database.models.group import Group
|
|
|
|
board = Board(
|
|
id=uuid4(),
|
|
user_id=test_user.id,
|
|
title="Test Board",
|
|
viewport_state={"x": 0, "y": 0, "zoom": 1.0, "rotation": 0},
|
|
)
|
|
db.add(board)
|
|
|
|
# Create image
|
|
image = Image(
|
|
id=uuid4(),
|
|
user_id=test_user.id,
|
|
filename="test.jpg",
|
|
storage_path=f"{test_user.id}/test.jpg",
|
|
file_size=1024,
|
|
mime_type="image/jpeg",
|
|
width=800,
|
|
height=600,
|
|
metadata={"format": "jpeg", "checksum": "abc"},
|
|
)
|
|
db.add(image)
|
|
|
|
# Create group
|
|
group = Group(
|
|
id=uuid4(),
|
|
board_id=board.id,
|
|
name="Test Group",
|
|
color="#FF5733",
|
|
)
|
|
db.add(group)
|
|
|
|
# Add image to board and group
|
|
board_image = BoardImage(
|
|
id=uuid4(),
|
|
board_id=board.id,
|
|
image_id=image.id,
|
|
position={"x": 100, "y": 100},
|
|
transformations={"scale": 1.0, "rotation": 0, "opacity": 1.0},
|
|
z_order=0,
|
|
group_id=group.id,
|
|
)
|
|
db.add(board_image)
|
|
db.commit()
|
|
|
|
# Delete group
|
|
response = await client.delete(f"/api/boards/{board.id}/groups/{group.id}")
|
|
|
|
assert response.status_code == 204
|
|
|
|
# Verify image is ungrouped
|
|
db.refresh(board_image)
|
|
assert board_image.group_id is None
|
|
|
|
|
|
async def test_group_unauthorized_board(client: AsyncClient, test_user: User, db: Session):
|
|
"""Test that users can't create groups on boards they don't own."""
|
|
# Create another user
|
|
other_user = User(id=uuid4(), email="other@example.com", password_hash="hashed")
|
|
db.add(other_user)
|
|
|
|
# Create board owned by other user
|
|
board = Board(
|
|
id=uuid4(),
|
|
user_id=other_user.id,
|
|
title="Other Board",
|
|
viewport_state={"x": 0, "y": 0, "zoom": 1.0, "rotation": 0},
|
|
)
|
|
db.add(board)
|
|
db.commit()
|
|
|
|
# Try to create group
|
|
response = await client.post(
|
|
f"/api/boards/{board.id}/groups",
|
|
json={
|
|
"name": "Test Group",
|
|
"color": "#FF5733",
|
|
"image_ids": [str(uuid4())],
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 404 # Board not found (for security)
|
|
|
|
|
|
async def test_invalid_color_format(client: AsyncClient, test_user: User, db: Session):
|
|
"""Test that invalid color formats are rejected."""
|
|
board = Board(
|
|
id=uuid4(),
|
|
user_id=test_user.id,
|
|
title="Test Board",
|
|
viewport_state={"x": 0, "y": 0, "zoom": 1.0, "rotation": 0},
|
|
)
|
|
db.add(board)
|
|
db.commit()
|
|
|
|
# Try with invalid color
|
|
response = await client.post(
|
|
f"/api/boards/{board.id}/groups",
|
|
json={
|
|
"name": "Test Group",
|
|
"color": "red", # Invalid: not hex
|
|
"image_ids": [str(uuid4())],
|
|
},
|
|
)
|
|
|
|
assert response.status_code == 422
|
|
|