Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,46 @@ jobs:
echo "=== Container logs ==="
docker logs lampyrid-test 2>&1
exit 1

integration-tests:
name: Integration Tests
runs-on: ubuntu-latest
needs: [lint-and-format, build-test]
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
version: "latest"

- name: Set up Python
run: uv python install 3.14

- name: Install dependencies
run: uv sync

- name: Setup Firefly III test environment
run: |
set -euo pipefail
chmod +x tests/setup_test_env.sh
./tests/setup_test_env.sh

- name: Run integration tests
run: |
uv run pytest tests/ -v --cov=src/lampyrid --cov-report=xml --cov-report=term

- name: Upload coverage report
uses: codecov/codecov-action@v4
if: always()
with:
files: ./coverage.xml
flags: integration
name: integration-tests
token: ${{ secrets.CODECOV_TOKEN }}

- name: Stop Firefly III
if: always()
run: |
docker compose -f docker-compose.test.yml down -v
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ celerybeat.pid

# Environments
.env
.env.test
.envrc
.venv
env/
Expand Down
55 changes: 55 additions & 0 deletions docker-compose.test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Docker Compose configuration for running Firefly III test instance
# This is used for integration testing of LamPyrid

services:
# Firefly III application
firefly-app:
image: fireflyiii/core:latest
container_name: firefly_iii_test_app
restart: unless-stopped
environment:
# Application environment
- APP_ENV=testing
# Database configuration
- DB_CONNECTION=sqlite

# Application configuration
- APP_KEY=SomeRandomStringOf32CharsExactly
- APP_URL=http://localhost:8080
- TRUSTED_PROXIES=**

# Disable unnecessary features for testing
- SEND_REGISTRATION_MAIL=false
- SEND_ERROR_MESSAGE=false
- SEND_REPORT_JOURNALS=false
- ENABLE_EXTERNAL_MAP=false
- ENABLE_EXTERNAL_RATES=false

# Logging
- APP_LOG_LEVEL=debug
- LOG_CHANNEL=stack

# Demo mode disabled
- IS_DEMO_SITE=false

# Cache and session
- CACHE_DRIVER=file
- SESSION_DRIVER=file

# Mail (disabled for testing)
- MAIL_MAILER=log

ports:
- "8080:8080"
networks:
- firefly_test
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s

networks:
firefly_test:
driver: bridge
19 changes: 19 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ lampyrid = "lampyrid.__main__:main"
[dependency-groups]
dev = [
"datamodel-code-generator>=0.52.0",
"dirty-equals>=0.11",
"inline-snapshot>=0.31.1",
"pytest>=9.0.2",
"pytest-asyncio>=1.3.0",
"pytest-cov>=7.0.0",
"python-dotenv>=1.2.1",
"ruff>=0.14.11",
]

Expand All @@ -35,6 +41,19 @@ docstring-code-format = true
[tool.ruff.lint]
extend-select = ["I"]

[tool.pytest.ini_options]
asyncio_mode = "auto"
testpaths = ["tests"]
python_files = ["test_*.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
markers = [
"integration: marks tests as integration tests",
"accounts: account-related tests",
"transactions: transaction-related tests",
"budgets: budget-related tests",
]

[tool.datamodel-codegen]
input = "firefly-iii-6.4.14-v1.yaml"
output = "src/lampyrid/models/firefly_models.py"
Expand Down
18 changes: 18 additions & 0 deletions src/lampyrid/clients/firefly.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
from ..models.firefly_models import (
AccountArray,
AccountSingle,
AccountStore,
AccountTypeFilter,
AvailableBudgetArray,
BudgetArray,
BudgetLimitArray,
BudgetSingle,
BudgetStore,
TransactionArray,
TransactionSingle,
TransactionSplitStore,
Expand Down Expand Up @@ -118,6 +120,13 @@ async def search_accounts(self, req: SearchAccountRequest) -> AccountArray:
r.raise_for_status()
return AccountArray.model_validate(r.json())

async def create_account(self, account_store: AccountStore) -> Account:
r = await self._client.post('/api/v1/accounts', json=self._serialize_model(account_store))
self._handle_api_error(r)
r.raise_for_status()
account_single = AccountSingle.model_validate(r.json())
return Account.from_account_read(account_single.data)

@staticmethod
def _sanitize_value(value: str) -> str:
"""Escape and optionally quote a search value for Firefly III query syntax.
Expand Down Expand Up @@ -490,6 +499,15 @@ async def get_budget_summary(self, req: GetBudgetSummaryRequest) -> BudgetSummar
available_budget=None, # Would need additional API call to get available budget
)

async def create_budget(self, budget_store: BudgetStore) -> Budget:
"""Create a new budget."""
payload = self._serialize_model(budget_store)
r = await self._client.post('/api/v1/budgets', json=payload)
self._handle_api_error(r, payload)
r.raise_for_status()
budget_single = BudgetSingle.model_validate(r.json())
return Budget.from_budget_read(budget_single.data)

async def get_available_budget(self, req: GetAvailableBudgetRequest) -> AvailableBudget:
"""Get available budget for a period."""
params: Dict[str, Any] = {}
Expand Down
1 change: 1 addition & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Test suite for LamPyrid MCP server
Loading