release: update version to 0.2.0 and add schema to models
Build and Push Docker Image / build-and-push (push) Successful in 3m24s
Details
Build and Push Docker Image / build-and-push (push) Successful in 3m24s
Details
This commit is contained in:
parent
0cc81356a7
commit
ae119ec5e1
|
|
@ -10,20 +10,28 @@ jobs:
|
|||
build-and-push:
|
||||
if: contains(github.event.head_commit.message, 'release')
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
- name: Set release version manually
|
||||
id: version
|
||||
run: echo "version=0.2.0" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Compute short SHA
|
||||
id: gitvars
|
||||
run: echo "short_sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
|
|
@ -32,6 +40,12 @@ jobs:
|
|||
push: true
|
||||
tags: |
|
||||
itqop/hubgw:latest
|
||||
itqop/hubgw:${{ gitea.sha }}
|
||||
itqop/hubgw:${{ steps.version.outputs.version }}
|
||||
itqop/hubgw:${{ steps.version.outputs.version }}-${{ steps.gitvars.outputs.short_sha }}
|
||||
labels: |
|
||||
org.opencontainers.image.title=hubgw
|
||||
org.opencontainers.image.version=${{ steps.version.outputs.version }}
|
||||
org.opencontainers.image.revision=${{ github.sha }}
|
||||
org.opencontainers.image.source=${{ github.repository }}
|
||||
cache-from: type=registry,ref=itqop/hubgw:buildcache
|
||||
cache-to: type=registry,ref=itqop/hubgw:buildcache,mode=max
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|||
|
||||
[tool.poetry]
|
||||
name = "hubgw"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
description = "FastAPI Gateway for HubMC"
|
||||
authors = ["itqop <leonkl32@gmail.com>"]
|
||||
packages = [
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
|
||||
from sqlalchemy import Column, DateTime, func
|
||||
from sqlalchemy.orm import DeclarativeBase
|
||||
from sqlalchemy.orm import DeclarativeBase, declared_attr
|
||||
|
||||
|
||||
class Base(DeclarativeBase):
|
||||
|
|
@ -12,3 +12,8 @@ class Base(DeclarativeBase):
|
|||
updated_at = Column(
|
||||
DateTime(timezone=True), server_default=func.now(), onupdate=func.now()
|
||||
)
|
||||
|
||||
@declared_attr.directive
|
||||
def __table_args__(cls):
|
||||
"""Set default schema for all tables."""
|
||||
return {"schema": "hubmc"}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class Cooldown(Base):
|
|||
UniqueConstraint(
|
||||
"player_uuid", "cooldown_type", name="idx_hub_cooldowns_player_type"
|
||||
),
|
||||
{"schema": "hubmc"},
|
||||
)
|
||||
|
||||
id = Column(
|
||||
|
|
@ -22,7 +23,7 @@ class Cooldown(Base):
|
|||
)
|
||||
player_uuid = Column(
|
||||
String(36),
|
||||
ForeignKey("luckperms_players.uuid", ondelete="CASCADE"),
|
||||
ForeignKey("hubmc.luckperms_players.uuid", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class Home(Base):
|
|||
__tablename__ = "hub_homes"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("player_uuid", "name", name="idx_hub_homes_player_name"),
|
||||
{"schema": "hubmc"},
|
||||
)
|
||||
|
||||
id = Column(
|
||||
|
|
@ -20,7 +21,7 @@ class Home(Base):
|
|||
)
|
||||
player_uuid = Column(
|
||||
String(36),
|
||||
ForeignKey("luckperms_players.uuid", ondelete="CASCADE"),
|
||||
ForeignKey("hubmc.luckperms_players.uuid", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -41,12 +41,13 @@ class LuckPermsUserPermission(Base):
|
|||
"server",
|
||||
"world",
|
||||
),
|
||||
{"schema": "hubmc"},
|
||||
)
|
||||
|
||||
id = Column(Integer, primary_key=True, autoincrement=True)
|
||||
uuid = Column(
|
||||
String(36),
|
||||
ForeignKey("luckperms_players.uuid", ondelete="CASCADE"),
|
||||
ForeignKey("hubmc.luckperms_players.uuid", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ class Punishment(Base):
|
|||
"player_ip",
|
||||
postgresql_where=Column("player_ip") != None,
|
||||
),
|
||||
{"schema": "hubmc"},
|
||||
)
|
||||
|
||||
id = Column(
|
||||
|
|
@ -40,7 +41,7 @@ class Punishment(Base):
|
|||
)
|
||||
player_uuid = Column(
|
||||
String(36),
|
||||
ForeignKey("luckperms_players.uuid", ondelete="CASCADE"),
|
||||
ForeignKey("hubmc.luckperms_players.uuid", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
|
@ -50,7 +51,7 @@ class Punishment(Base):
|
|||
reason = Column(Text, nullable=False)
|
||||
staff_uuid = Column(
|
||||
String(36),
|
||||
ForeignKey("luckperms_players.uuid", ondelete="SET NULL"),
|
||||
ForeignKey("hubmc.luckperms_players.uuid", ondelete="SET NULL"),
|
||||
nullable=False,
|
||||
)
|
||||
staff_name = Column(String(255), nullable=False)
|
||||
|
|
@ -58,7 +59,7 @@ class Punishment(Base):
|
|||
is_active = Column(Boolean, default=True)
|
||||
revoked_at = Column(DateTime(timezone=True))
|
||||
revoked_by = Column(
|
||||
String(36), ForeignKey("luckperms_players.uuid", ondelete="SET NULL")
|
||||
String(36), ForeignKey("hubmc.luckperms_players.uuid", ondelete="SET NULL")
|
||||
)
|
||||
revoked_reason = Column(Text)
|
||||
evidence_url = Column(Text)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ class TeleportHistory(Base):
|
|||
)
|
||||
player_uuid = Column(
|
||||
String(36),
|
||||
ForeignKey("luckperms_players.uuid", ondelete="CASCADE"),
|
||||
ForeignKey("hubmc.luckperms_players.uuid", ondelete="CASCADE"),
|
||||
nullable=False,
|
||||
index=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -32,4 +32,7 @@ class User(Base):
|
|||
deleted_at = Column(DateTime(timezone=True), nullable=True)
|
||||
password_changed_at = Column(DateTime(timezone=True), nullable=True)
|
||||
|
||||
__table_args__ = (Index("idx_users_email", "email", unique=True),)
|
||||
__table_args__ = (
|
||||
Index("idx_users_email", "email", unique=True),
|
||||
{"schema": "public"},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class Warp(Base):
|
|||
Index(
|
||||
"idx_hub_warps_public", "is_public", postgresql_where=Column("is_public")
|
||||
),
|
||||
{"schema": "hubmc"},
|
||||
)
|
||||
|
||||
id = Column(
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ class WhitelistEntry(Base):
|
|||
"expires_at",
|
||||
postgresql_where=Column("expires_at") != None,
|
||||
),
|
||||
{"schema": "hubmc"},
|
||||
)
|
||||
|
||||
id = Column(
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@ class WhitelistService:
|
|||
logger.error(
|
||||
f"Failed to create LuckPerms player '{request.player_name}': {type(e).__name__}: {e}"
|
||||
)
|
||||
await self.repo.session.rollback()
|
||||
raise
|
||||
|
||||
existing = await self.repo.get_by_player_name(request.player_name)
|
||||
if existing:
|
||||
|
|
|
|||
|
|
@ -1,92 +1,48 @@
|
|||
"""Integration tests for whitelist endpoints."""
|
||||
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from unittest.mock import AsyncMock, patch
|
||||
from uuid import uuid4
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import pytest
|
||||
import pytest_asyncio
|
||||
from httpx import AsyncClient, ASGITransport
|
||||
from sqlalchemy import Column, String, Boolean, DateTime, event
|
||||
from sqlalchemy.dialects.postgresql import UUID as PG_UUID
|
||||
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
|
||||
from sqlalchemy import delete
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from hubgw.context import APP_CTX
|
||||
from hubgw.main import create_app
|
||||
from hubgw.models.base import Base
|
||||
from hubgw.models.whitelist import WhitelistEntry
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(scope="function")
|
||||
async def test_engine():
|
||||
"""Create test database engine and setup tables."""
|
||||
from sqlalchemy import Table, MetaData, Index
|
||||
from uuid import uuid4 as _uuid4
|
||||
|
||||
engine = create_async_engine(
|
||||
"sqlite+aiosqlite:///:memory:",
|
||||
echo=False,
|
||||
connect_args={"check_same_thread": False},
|
||||
)
|
||||
|
||||
metadata = MetaData()
|
||||
|
||||
whitelist_table = Table(
|
||||
"hub_whitelist",
|
||||
metadata,
|
||||
Column("id", String(36), primary_key=True),
|
||||
Column("player_name", String(255), nullable=False, unique=True, index=True),
|
||||
Column("added_by", String(255), nullable=False),
|
||||
Column("added_at", DateTime(timezone=True), nullable=False),
|
||||
Column("expires_at", DateTime(timezone=True)),
|
||||
Column("is_active", Boolean, default=True),
|
||||
Column("reason", String(500)),
|
||||
Column("created_at", DateTime(timezone=True)),
|
||||
Column("updated_at", DateTime(timezone=True)),
|
||||
)
|
||||
|
||||
async with engine.begin() as conn:
|
||||
await conn.run_sync(metadata.create_all)
|
||||
|
||||
yield engine
|
||||
|
||||
await engine.dispose()
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(scope="function")
|
||||
async def test_session(test_engine):
|
||||
"""Create test database session."""
|
||||
session_factory = async_sessionmaker(
|
||||
bind=test_engine,
|
||||
class_=AsyncSession,
|
||||
expire_on_commit=False,
|
||||
)
|
||||
|
||||
async with session_factory() as session:
|
||||
yield session
|
||||
|
||||
|
||||
@pytest_asyncio.fixture(scope="function")
|
||||
async def client(test_engine):
|
||||
async def client():
|
||||
"""Create async test client."""
|
||||
from hubgw.services.luckperms_service import LuckPermsService
|
||||
from hubgw.services.users_service import UserService
|
||||
|
||||
app = create_app()
|
||||
|
||||
original_engine = APP_CTX._engine
|
||||
original_factory = APP_CTX._session_factory
|
||||
mock_luckperms = AsyncMock(spec=LuckPermsService)
|
||||
mock_luckperms.create_player = AsyncMock()
|
||||
|
||||
APP_CTX._engine = test_engine
|
||||
APP_CTX._session_factory = async_sessionmaker(
|
||||
bind=test_engine,
|
||||
class_=AsyncSession,
|
||||
expire_on_commit=False,
|
||||
)
|
||||
mock_user = AsyncMock(spec=UserService)
|
||||
|
||||
async def get_mock_luckperms():
|
||||
return mock_luckperms
|
||||
|
||||
async def get_mock_user():
|
||||
return mock_user
|
||||
|
||||
from hubgw.api import deps
|
||||
app.dependency_overrides[deps.get_luckperms_service] = get_mock_luckperms
|
||||
app.dependency_overrides[deps.get_user_service] = get_mock_user
|
||||
|
||||
async with AsyncClient(
|
||||
transport=ASGITransport(app=app), base_url="http://test"
|
||||
) as ac:
|
||||
yield ac
|
||||
|
||||
APP_CTX._engine = original_engine
|
||||
APP_CTX._session_factory = original_factory
|
||||
app.dependency_overrides.clear()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
|
@ -101,36 +57,29 @@ class TestWhitelistAdd:
|
|||
@pytest.mark.asyncio
|
||||
async def test_add_player_success(self, client, api_key):
|
||||
"""Test successfully adding a new player to whitelist."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "TestPlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"expires_at": (now + timedelta(days=30)).isoformat(),
|
||||
"is_active": True,
|
||||
"reason": "Testing",
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_lp.return_value.create_player = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "TestPlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"expires_at": (now + timedelta(days=30)).isoformat(),
|
||||
"is_active": True,
|
||||
"reason": "Testing",
|
||||
}
|
||||
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
data = response.json()
|
||||
assert data["player_name"] == "TestPlayer"
|
||||
assert data["added_by"] == "admin"
|
||||
assert data["is_active"] is True
|
||||
assert data["reason"] == "Testing"
|
||||
assert "id" in data
|
||||
assert response.status_code == 201
|
||||
data = response.json()
|
||||
assert data["player_name"] == "TestPlayer"
|
||||
assert data["added_by"] == "admin"
|
||||
assert data["is_active"] is True
|
||||
assert data["reason"] == "Testing"
|
||||
assert "id" in data
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_player_invalid_username(self, client, api_key):
|
||||
|
|
@ -172,103 +121,85 @@ class TestWhitelistAdd:
|
|||
@pytest.mark.asyncio
|
||||
async def test_add_player_expires_before_added(self, client, api_key):
|
||||
"""Test adding player with expires_at before added_at."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "TestPlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"expires_at": (now - timedelta(minutes=1)).isoformat(),
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "TestPlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"expires_at": (now - timedelta(minutes=1)).isoformat(),
|
||||
}
|
||||
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 422
|
||||
assert "expires_at" in response.text and ("cannot be in the past" in response.text or "must be after added_at" in response.text)
|
||||
assert response.status_code == 422
|
||||
assert "expires_at" in response.text and ("cannot be in the past" in response.text or "must be after added_at" in response.text)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_player_duplicate_active(self, client, api_key):
|
||||
"""Test adding duplicate player when already active."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "DuplicatePlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
response1 = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
assert response1.status_code == 201
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "DuplicatePlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
|
||||
response1 = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
assert response1.status_code == 201
|
||||
|
||||
response2 = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
assert response2.status_code == 409
|
||||
assert "already whitelisted" in response2.text
|
||||
response2 = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
assert response2.status_code == 409
|
||||
assert "already whitelisted" in response2.text
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_player_reactivate_inactive(self, client, api_key, test_session):
|
||||
async def test_add_player_reactivate_inactive(self, client, api_key):
|
||||
"""Test reactivating an inactive player."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
payload1 = {
|
||||
"player_name": "InactivePlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": False,
|
||||
}
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
response1 = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload1,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
assert response1.status_code == 201
|
||||
|
||||
payload1 = {
|
||||
"player_name": "InactivePlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": False,
|
||||
}
|
||||
payload2 = {
|
||||
"player_name": "InactivePlayer",
|
||||
"added_by": "moderator",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": True,
|
||||
"reason": "Reactivated",
|
||||
}
|
||||
|
||||
response1 = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload1,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
assert response1.status_code == 201
|
||||
|
||||
payload2 = {
|
||||
"player_name": "InactivePlayer",
|
||||
"added_by": "moderator",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": True,
|
||||
"reason": "Reactivated",
|
||||
}
|
||||
|
||||
response2 = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload2,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
assert response2.status_code == 201
|
||||
data = response2.json()
|
||||
assert data["added_by"] == "moderator"
|
||||
assert data["is_active"] is True
|
||||
assert data["reason"] == "Reactivated"
|
||||
response2 = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload2,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
assert response2.status_code == 201
|
||||
data = response2.json()
|
||||
assert data["added_by"] == "moderator"
|
||||
assert data["is_active"] is True
|
||||
assert data["reason"] == "Reactivated"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_player_unauthorized(self, client):
|
||||
|
|
@ -307,33 +238,27 @@ class TestWhitelistRemove:
|
|||
@pytest.mark.asyncio
|
||||
async def test_remove_player_success(self, client, api_key):
|
||||
"""Test successfully removing a player."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
add_payload = {
|
||||
"player_name": "PlayerToRemove",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=add_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
add_payload = {
|
||||
"player_name": "PlayerToRemove",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
remove_payload = {"player_name": "PlayerToRemove"}
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/remove",
|
||||
json=remove_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=add_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
remove_payload = {"player_name": "PlayerToRemove"}
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/remove",
|
||||
json=remove_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 204
|
||||
assert response.status_code == 204
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_remove_player_not_found(self, client, api_key):
|
||||
|
|
@ -367,70 +292,58 @@ class TestWhitelistCheck:
|
|||
@pytest.mark.asyncio
|
||||
async def test_check_player_active(self, client, api_key):
|
||||
"""Test checking active whitelisted player."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
add_payload = {
|
||||
"player_name": "ActivePlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": True,
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=add_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
add_payload = {
|
||||
"player_name": "ActivePlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": True,
|
||||
}
|
||||
check_payload = {"player_name": "ActivePlayer"}
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/check",
|
||||
json=check_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=add_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
check_payload = {"player_name": "ActivePlayer"}
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/check",
|
||||
json=check_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_whitelisted"] is True
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_whitelisted"] is True
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_check_player_inactive(self, client, api_key):
|
||||
"""Test checking inactive player."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
add_payload = {
|
||||
"player_name": "InactivePlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": False,
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=add_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
add_payload = {
|
||||
"player_name": "InactivePlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": False,
|
||||
}
|
||||
check_payload = {"player_name": "InactivePlayer"}
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/check",
|
||||
json=check_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=add_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
check_payload = {"player_name": "InactivePlayer"}
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/check",
|
||||
json=check_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_whitelisted"] is False
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_whitelisted"] is False
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_check_player_not_found(self, client, api_key):
|
||||
|
|
@ -466,40 +379,34 @@ class TestWhitelistList:
|
|||
@pytest.mark.asyncio
|
||||
async def test_list_multiple_players(self, client, api_key):
|
||||
"""Test listing multiple players."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
for i, name in enumerate(["Player1", "Player2", "Player3"]):
|
||||
payload = {
|
||||
"player_name": name,
|
||||
"added_by": "admin",
|
||||
"added_at": (now + timedelta(seconds=i)).isoformat(),
|
||||
"is_active": i % 2 == 0,
|
||||
}
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
response = await client.get(
|
||||
"/api/v1/whitelist/",
|
||||
for i, name in enumerate(["Player1", "Player2", "Player3"]):
|
||||
payload = {
|
||||
"player_name": name,
|
||||
"added_by": "admin",
|
||||
"added_at": (now + timedelta(seconds=i)).isoformat(),
|
||||
"is_active": i % 2 == 0,
|
||||
}
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data["entries"]) == 3
|
||||
assert data["total"] == 3
|
||||
response = await client.get(
|
||||
"/api/v1/whitelist/",
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert data["entries"][0]["player_name"] == "Player3"
|
||||
assert data["entries"][1]["player_name"] == "Player2"
|
||||
assert data["entries"][2]["player_name"] == "Player1"
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data["entries"]) == 3
|
||||
assert data["total"] == 3
|
||||
|
||||
assert data["entries"][0]["player_name"] == "Player3"
|
||||
assert data["entries"][1]["player_name"] == "Player2"
|
||||
assert data["entries"][2]["player_name"] == "Player1"
|
||||
|
||||
|
||||
class TestWhitelistCount:
|
||||
|
|
@ -520,67 +427,55 @@ class TestWhitelistCount:
|
|||
@pytest.mark.asyncio
|
||||
async def test_count_multiple(self, client, api_key):
|
||||
"""Test count with multiple entries."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
for i in range(5):
|
||||
payload = {
|
||||
"player_name": f"Player{i}",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
response = await client.get(
|
||||
"/api/v1/whitelist/count",
|
||||
for i in range(5):
|
||||
payload = {
|
||||
"player_name": f"Player{i}",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 5
|
||||
response = await client.get(
|
||||
"/api/v1/whitelist/count",
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 5
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_count_includes_inactive(self, client, api_key):
|
||||
"""Test that count includes both active and inactive entries."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
|
||||
for i in range(3):
|
||||
payload = {
|
||||
"player_name": f"Player{i}",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": i % 2 == 0,
|
||||
}
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
response = await client.get(
|
||||
"/api/v1/whitelist/count",
|
||||
for i in range(3):
|
||||
payload = {
|
||||
"player_name": f"Player{i}",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"is_active": i % 2 == 0,
|
||||
}
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 3
|
||||
response = await client.get(
|
||||
"/api/v1/whitelist/count",
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["total"] == 3
|
||||
|
||||
|
||||
class TestWhitelistEdgeCases:
|
||||
|
|
@ -589,107 +484,83 @@ class TestWhitelistEdgeCases:
|
|||
@pytest.mark.asyncio
|
||||
async def test_add_player_with_whitespace_reason(self, client, api_key):
|
||||
"""Test adding player with whitespace-only reason."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "TestPlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"reason": " ",
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "TestPlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
"reason": " ",
|
||||
}
|
||||
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
data = response.json()
|
||||
assert data["reason"] is None
|
||||
assert response.status_code == 201
|
||||
data = response.json()
|
||||
assert data["reason"] is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_player_max_length_username(self, client, api_key):
|
||||
"""Test adding player with maximum length username."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "A" * 16,
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "A" * 16,
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
assert response.status_code == 201
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_add_player_min_length_username(self, client, api_key):
|
||||
"""Test adding player with minimum length username."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "ABC",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
payload = {
|
||||
"player_name": "ABC",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
assert response.status_code == 201
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_check_player_case_sensitive(self, client, api_key):
|
||||
"""Test that player name check is case-sensitive."""
|
||||
with patch("hubgw.api.deps.get_luckperms_service") as mock_lp, \
|
||||
patch("hubgw.api.deps.get_user_service") as mock_us:
|
||||
now = datetime.now(timezone.utc)
|
||||
add_payload = {
|
||||
"player_name": "TestPlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
|
||||
mock_lp.return_value = AsyncMock()
|
||||
mock_us.return_value = AsyncMock()
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=add_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
add_payload = {
|
||||
"player_name": "TestPlayer",
|
||||
"added_by": "admin",
|
||||
"added_at": now.isoformat(),
|
||||
}
|
||||
check_payload = {"player_name": "testplayer"}
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/check",
|
||||
json=check_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
await client.post(
|
||||
"/api/v1/whitelist/add",
|
||||
json=add_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
check_payload = {"player_name": "testplayer"}
|
||||
response = await client.post(
|
||||
"/api/v1/whitelist/check",
|
||||
json=check_payload,
|
||||
headers={"X-API-Key": api_key},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_whitelisted"] is False
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["is_whitelisted"] is False
|
||||
|
|
|
|||
Loading…
Reference in New Issue