ghpsolutions/quadro

Quadro: team boards with roles, history and an MCP endpoint for Claude and ChatGPT

A remix template · 0 remixes · Remix ghpsolutions/quadro

tests/conftest.py

import os
import sys
from datetime import date
from pathlib import Path

import pytest

sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "app"))

from boards.application.use_cases import Boards  # noqa: E402
from boards.domain.model import Person  # noqa: E402
from boards.infrastructure.memory import MemoryBoards  # noqa: E402

TODAY = date(2026, 11, 10)
OWNER, MEMBER, VIEWER, STRANGER = (Person(e) for e in (
    "owner@ghp.test", "member@ghp.test", "viewer@ghp.test", "stranger@ghp.test"))

TABLES = ("boards", "memberships", "board_lists", "cards", "comments", "activity",
          "card_embeddings")


class FakeAssistant:
    def __init__(self, fail=False):
        self.fail, self.calls = fail, []

    def checklist(self, title, description):
        self.calls.append(("checklist", title))
        if self.fail:
            raise RuntimeError("model down")
        return ["Draft it", "Review it", "Send it"]

    def summary(self, facts):
        self.calls.append(("summary", facts))
        if self.fail:
            raise RuntimeError("model down")
        return "Standup: " + facts.splitlines()[0]

    def embed(self, texts):
        if self.fail:
            raise RuntimeError("model down")
        # A tiny bag-of-topics vector: enough to make "similar" mean something in tests.
        topics = ("invoice", "certificate", "backup", "release")
        return [[1.0 if t in text.lower() else 0.0 for t in topics] + [0.01] for text in texts]


def _sql_repo():
    url = os.environ.get("TEST_DATABASE_URL")
    if not url:
        pytest.skip("set TEST_DATABASE_URL to run the SQL repository against Postgres")
    os.environ["DATABASE_URL"] = url
    from boards.infrastructure.repository import SqlBoards
    repo = SqlBoards(pool_size=4)
    for t in TABLES:
        repo._run(f"DROP TABLE IF EXISTS {t}")
    repo.ensure_schema()
    return repo


@pytest.fixture(params=["memory", "sql"])
def repo(request):
    return MemoryBoards() if request.param == "memory" else _sql_repo()


@pytest.fixture
def assistant():
    return FakeAssistant()


@pytest.fixture
def svc(repo, assistant):
    return Boards(repo, assistant, today=lambda: TODAY)


@pytest.fixture
def ops(svc):
    """An 'Ops' board: owner, a member and a viewer."""
    board = svc.create_board(OWNER, "Ops")
    svc.invite_member(OWNER, board["id"], MEMBER.email, "member")
    svc.invite_member(OWNER, board["id"], VIEWER.email, "viewer")
    return board["id"]