155 lines
5.1 KiB
Python
155 lines
5.1 KiB
Python
|
|
"""Pytest fixtures for integration tests."""
|
||
|
|
import pytest
|
||
|
|
import uuid
|
||
|
|
from datetime import datetime, timezone
|
||
|
|
|
||
|
|
from gatehouse_app import create_app, db
|
||
|
|
from gatehouse_app.extensions import limiter
|
||
|
|
from gatehouse_app.models.user.user import User
|
||
|
|
from gatehouse_app.models.organization.organization import Organization
|
||
|
|
from gatehouse_app.models.organization.organization_member import OrganizationMember
|
||
|
|
from gatehouse_app.models.ssh_ca.ca import CA, CaType, KeyType
|
||
|
|
from gatehouse_app.utils.constants import OrganizationRole
|
||
|
|
from tests.integration.client.base import SecuirdClient
|
||
|
|
|
||
|
|
|
||
|
|
# Disable the global rate limiter for integration tests.
|
||
|
|
# The default app created at module level in gatehouse_app/__init__.py
|
||
|
|
# initializes the limiter with production settings; we turn it off here
|
||
|
|
# so tests don't hit rate limits.
|
||
|
|
limiter.enabled = False
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture(scope="module")
|
||
|
|
def integration_app():
|
||
|
|
"""Create a test Flask app with in-memory SQLite.
|
||
|
|
|
||
|
|
Yields the configured application; tears down the DB after the
|
||
|
|
module finishes.
|
||
|
|
"""
|
||
|
|
app = create_app(config_name="testing")
|
||
|
|
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///:memory:"
|
||
|
|
app.config["TESTING"] = True
|
||
|
|
app.config["WTF_CSRF_ENABLED"] = False
|
||
|
|
app.config["RATELIMIT_ENABLED"] = False
|
||
|
|
|
||
|
|
with app.app_context():
|
||
|
|
db.create_all()
|
||
|
|
yield app
|
||
|
|
db.session.remove()
|
||
|
|
db.drop_all()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def integration_client(integration_app):
|
||
|
|
"""Yield a fresh SecuirdClient for every test function."""
|
||
|
|
with integration_app.test_client() as flask_client:
|
||
|
|
client = SecuirdClient(flask_client)
|
||
|
|
yield client
|
||
|
|
client.clear_token()
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def create_test_user(integration_app):
|
||
|
|
"""Return a factory that creates a user inside the app context."""
|
||
|
|
from gatehouse_app.models.auth.authentication_method import AuthenticationMethod
|
||
|
|
from gatehouse_app.utils.constants import AuthMethodType
|
||
|
|
|
||
|
|
def _factory(
|
||
|
|
*,
|
||
|
|
email: str | None = None,
|
||
|
|
password: str = "password123",
|
||
|
|
full_name: str = "Test User",
|
||
|
|
email_verified: bool = True,
|
||
|
|
) -> dict:
|
||
|
|
email = email or f"test_{uuid.uuid4().hex[:8]}@example.com"
|
||
|
|
with integration_app.app_context():
|
||
|
|
user = User(
|
||
|
|
email=email,
|
||
|
|
full_name=full_name,
|
||
|
|
email_verified=email_verified,
|
||
|
|
)
|
||
|
|
db.session.add(user)
|
||
|
|
db.session.commit()
|
||
|
|
|
||
|
|
from gatehouse_app.extensions import bcrypt
|
||
|
|
password_hash = bcrypt.generate_password_hash(password).decode("utf-8")
|
||
|
|
auth_method = AuthenticationMethod(
|
||
|
|
user_id=user.id,
|
||
|
|
method_type=AuthMethodType.PASSWORD,
|
||
|
|
password_hash=password_hash,
|
||
|
|
is_primary=True,
|
||
|
|
verified=True,
|
||
|
|
)
|
||
|
|
db.session.add(auth_method)
|
||
|
|
db.session.commit()
|
||
|
|
|
||
|
|
return {
|
||
|
|
"id": str(user.id),
|
||
|
|
"email": user.email,
|
||
|
|
"password": password,
|
||
|
|
"full_name": user.full_name,
|
||
|
|
}
|
||
|
|
|
||
|
|
return _factory
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def create_test_org(integration_app):
|
||
|
|
"""Return a factory that creates an organization inside the app context."""
|
||
|
|
def _factory(*, name: str | None = None, slug: str | None = None) -> dict:
|
||
|
|
name = name or f"Test Org {uuid.uuid4().hex[:8]}"
|
||
|
|
slug = slug or name.lower().replace(" ", "-")
|
||
|
|
with integration_app.app_context():
|
||
|
|
org = Organization(name=name, slug=slug)
|
||
|
|
db.session.add(org)
|
||
|
|
db.session.commit()
|
||
|
|
return {"id": str(org.id), "name": org.name, "slug": org.slug}
|
||
|
|
|
||
|
|
return _factory
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def create_test_membership(integration_app):
|
||
|
|
"""Return a factory that creates an org membership."""
|
||
|
|
def _factory(user_id: str, org_id: str, role: OrganizationRole = OrganizationRole.MEMBER) -> dict:
|
||
|
|
with integration_app.app_context():
|
||
|
|
membership = OrganizationMember(
|
||
|
|
user_id=user_id,
|
||
|
|
organization_id=org_id,
|
||
|
|
role=role,
|
||
|
|
)
|
||
|
|
db.session.add(membership)
|
||
|
|
db.session.commit()
|
||
|
|
return {"id": str(membership.id), "role": role.value}
|
||
|
|
|
||
|
|
return _factory
|
||
|
|
|
||
|
|
|
||
|
|
@pytest.fixture
|
||
|
|
def create_test_ca(integration_app):
|
||
|
|
"""Return a factory that creates a Certificate Authority."""
|
||
|
|
def _factory(
|
||
|
|
*,
|
||
|
|
org_id: str,
|
||
|
|
name: str = "Test CA",
|
||
|
|
ca_type: CaType = CaType.USER,
|
||
|
|
key_type: KeyType = KeyType.ED25519,
|
||
|
|
) -> dict:
|
||
|
|
with integration_app.app_context():
|
||
|
|
ca = CA(
|
||
|
|
organization_id=org_id,
|
||
|
|
name=name,
|
||
|
|
ca_type=ca_type,
|
||
|
|
key_type=key_type,
|
||
|
|
private_key="encrypted_private_key_placeholder",
|
||
|
|
public_key="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...",
|
||
|
|
fingerprint="sha256:ABC123...",
|
||
|
|
is_active=True,
|
||
|
|
)
|
||
|
|
db.session.add(ca)
|
||
|
|
db.session.commit()
|
||
|
|
return {"id": str(ca.id), "name": ca.name, "ca_type": ca.ca_type.value}
|
||
|
|
|
||
|
|
return _factory
|