Add debug CLI decisions, POIs, and tasks subcommands
This commit is contained in:
parent
2196e256f4
commit
34f9e933c0
5 changed files with 551 additions and 0 deletions
120
cli/decisions.py
Normal file
120
cli/decisions.py
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
"""Debug CLI — decision commands (like/dislike)."""
|
||||
import click
|
||||
import httpx
|
||||
|
||||
from cli._context import CliContext, get_http_headers, output, error_output, resolve_user_id
|
||||
from database import engine
|
||||
from repositories.decision_repository import DecisionRepository
|
||||
from services import decision_service
|
||||
|
||||
|
||||
@click.group("decisions")
|
||||
def decisions_group() -> None:
|
||||
"""Like/dislike decision commands."""
|
||||
pass
|
||||
|
||||
|
||||
@decisions_group.command("set")
|
||||
@click.argument("listing_id", type=int)
|
||||
@click.argument("decision", type=click.Choice(["liked", "disliked"]))
|
||||
@click.option("--type", "-t", "listing_type", required=True, type=click.Choice(["RENT", "BUY"]))
|
||||
@click.pass_context
|
||||
def set_decision(ctx: click.Context, listing_id: int, decision: str, listing_type: str) -> None:
|
||||
"""Set a like/dislike decision for a listing."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.put(
|
||||
f"{cli_ctx.api_base_url}/api/decisions/{listing_id}",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
json={"decision": decision, "listing_type": listing_type},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
user_id = resolve_user_id(cli_ctx.user_email)
|
||||
repo = DecisionRepository(engine)
|
||||
result = decision_service.set_decision(repo, user_id, listing_id, listing_type, decision)
|
||||
data = {
|
||||
"listing_id": result.listing_id,
|
||||
"listing_type": result.listing_type,
|
||||
"decision": result.decision,
|
||||
"created_at": str(result.created_at),
|
||||
"updated_at": str(result.updated_at),
|
||||
}
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@decisions_group.command("list")
|
||||
@click.pass_context
|
||||
def list_decisions(ctx: click.Context) -> None:
|
||||
"""List all decisions for the user."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.get(
|
||||
f"{cli_ctx.api_base_url}/api/decisions",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
user_id = resolve_user_id(cli_ctx.user_email)
|
||||
repo = DecisionRepository(engine)
|
||||
decisions = decision_service.get_user_decisions(repo, user_id)
|
||||
data = [
|
||||
{
|
||||
"listing_id": d.listing_id,
|
||||
"listing_type": d.listing_type,
|
||||
"decision": d.decision,
|
||||
"created_at": str(d.created_at),
|
||||
"updated_at": str(d.updated_at),
|
||||
}
|
||||
for d in decisions
|
||||
]
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@decisions_group.command("remove")
|
||||
@click.argument("listing_id", type=int)
|
||||
@click.option("--type", "-t", "listing_type", required=True, type=click.Choice(["RENT", "BUY"]))
|
||||
@click.pass_context
|
||||
def remove_decision(ctx: click.Context, listing_id: int, listing_type: str) -> None:
|
||||
"""Remove a decision (un-like/un-dislike)."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.delete(
|
||||
f"{cli_ctx.api_base_url}/api/decisions/{listing_id}",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
params={"listing_type": listing_type},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
user_id = resolve_user_id(cli_ctx.user_email)
|
||||
repo = DecisionRepository(engine)
|
||||
deleted = decision_service.remove_decision(repo, user_id, listing_id, listing_type)
|
||||
if not deleted:
|
||||
error_output("Decision not found", cli_ctx.json_output)
|
||||
return
|
||||
data = {"success": True}
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
249
cli/pois.py
Normal file
249
cli/pois.py
Normal file
|
|
@ -0,0 +1,249 @@
|
|||
"""Debug CLI — POI commands."""
|
||||
import click
|
||||
import httpx
|
||||
|
||||
from cli._context import CliContext, get_http_headers, output, error_output, resolve_user_id
|
||||
from database import engine
|
||||
from models.listing import ListingType
|
||||
from repositories.poi_repository import POIRepository
|
||||
from services import poi_service, task_service
|
||||
|
||||
|
||||
@click.group("pois")
|
||||
def pois_group() -> None:
|
||||
"""Point of Interest management commands."""
|
||||
pass
|
||||
|
||||
|
||||
@pois_group.command("list")
|
||||
@click.pass_context
|
||||
def list_pois(ctx: click.Context) -> None:
|
||||
"""List all POIs for the user."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.get(
|
||||
f"{cli_ctx.api_base_url}/api/poi",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
user_id = resolve_user_id(cli_ctx.user_email)
|
||||
repo = POIRepository(engine)
|
||||
pois = poi_service.get_user_pois(repo, user_id)
|
||||
data = [
|
||||
{
|
||||
"id": p.id,
|
||||
"name": p.name,
|
||||
"address": p.address,
|
||||
"latitude": p.latitude,
|
||||
"longitude": p.longitude,
|
||||
"created_at": str(p.created_at),
|
||||
}
|
||||
for p in pois
|
||||
]
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@pois_group.command("create")
|
||||
@click.option("--name", required=True, help="POI name")
|
||||
@click.option("--address", required=True, help="Address")
|
||||
@click.option("--lat", required=True, type=float, help="Latitude")
|
||||
@click.option("--lon", required=True, type=float, help="Longitude")
|
||||
@click.pass_context
|
||||
def create_poi(ctx: click.Context, name: str, address: str, lat: float, lon: float) -> None:
|
||||
"""Create a new POI."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.post(
|
||||
f"{cli_ctx.api_base_url}/api/poi",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
json={"name": name, "address": address, "latitude": lat, "longitude": lon},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
user_id = resolve_user_id(cli_ctx.user_email)
|
||||
repo = POIRepository(engine)
|
||||
result = poi_service.create_poi(repo, user_id, name, address, lat, lon)
|
||||
data = {
|
||||
"id": result.poi.id,
|
||||
"name": result.poi.name,
|
||||
"address": result.poi.address,
|
||||
"latitude": result.poi.latitude,
|
||||
"longitude": result.poi.longitude,
|
||||
}
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@pois_group.command("update")
|
||||
@click.argument("poi_id", type=int)
|
||||
@click.option("--name", default=None, help="New name")
|
||||
@click.option("--address", default=None, help="New address")
|
||||
@click.option("--lat", default=None, type=float, help="New latitude")
|
||||
@click.option("--lon", default=None, type=float, help="New longitude")
|
||||
@click.pass_context
|
||||
def update_poi(ctx: click.Context, poi_id: int, name: str | None, address: str | None, lat: float | None, lon: float | None) -> None:
|
||||
"""Update an existing POI."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
body: dict[str, str | float] = {}
|
||||
if name is not None:
|
||||
body["name"] = name
|
||||
if address is not None:
|
||||
body["address"] = address
|
||||
if lat is not None:
|
||||
body["latitude"] = lat
|
||||
if lon is not None:
|
||||
body["longitude"] = lon
|
||||
resp = httpx.put(
|
||||
f"{cli_ctx.api_base_url}/api/poi/{poi_id}",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
json=body,
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
user_id = resolve_user_id(cli_ctx.user_email)
|
||||
repo = POIRepository(engine)
|
||||
result = poi_service.update_poi(repo, poi_id, user_id, name, address, lat, lon)
|
||||
if result is None:
|
||||
error_output("POI not found", cli_ctx.json_output)
|
||||
return
|
||||
data = {
|
||||
"id": result.poi.id,
|
||||
"name": result.poi.name,
|
||||
"address": result.poi.address,
|
||||
"latitude": result.poi.latitude,
|
||||
"longitude": result.poi.longitude,
|
||||
}
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@pois_group.command("delete")
|
||||
@click.argument("poi_id", type=int)
|
||||
@click.pass_context
|
||||
def delete_poi(ctx: click.Context, poi_id: int) -> None:
|
||||
"""Delete a POI."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.delete(
|
||||
f"{cli_ctx.api_base_url}/api/poi/{poi_id}",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
user_id = resolve_user_id(cli_ctx.user_email)
|
||||
repo = POIRepository(engine)
|
||||
deleted = poi_service.delete_poi(repo, poi_id, user_id)
|
||||
if not deleted:
|
||||
error_output("POI not found", cli_ctx.json_output)
|
||||
return
|
||||
data = {"success": True}
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@pois_group.command("calculate")
|
||||
@click.argument("poi_id", type=int)
|
||||
@click.option("--travel-modes", required=True, help="Comma-separated: WALK,BICYCLE,TRANSIT")
|
||||
@click.option("--type", "-t", "listing_type", required=True, type=click.Choice(["RENT", "BUY"]))
|
||||
@click.pass_context
|
||||
def calculate_distances(ctx: click.Context, poi_id: int, travel_modes: str, listing_type: str) -> None:
|
||||
"""Trigger distance calculation for a POI."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
modes = [m.strip().upper() for m in travel_modes.split(",")]
|
||||
lt = ListingType[listing_type]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.post(
|
||||
f"{cli_ctx.api_base_url}/api/poi/{poi_id}/calculate",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
json={"travel_modes": modes, "listing_type": listing_type},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
result = poi_service.trigger_calculation(
|
||||
poi_id=poi_id,
|
||||
travel_modes=modes,
|
||||
listing_type=lt,
|
||||
user_email=cli_ctx.user_email,
|
||||
)
|
||||
if result.task_id:
|
||||
task_service.add_task_for_user(cli_ctx.user_email, result.task_id)
|
||||
data = {"task_id": result.task_id or "", "message": result.message}
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@pois_group.command("distances")
|
||||
@click.argument("listing_id", type=int)
|
||||
@click.option("--type", "-t", "listing_type", default="RENT", type=click.Choice(["RENT", "BUY"]))
|
||||
@click.pass_context
|
||||
def get_distances(ctx: click.Context, listing_id: int, listing_type: str) -> None:
|
||||
"""Get POI distances for a specific listing."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
lt = ListingType[listing_type]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.get(
|
||||
f"{cli_ctx.api_base_url}/api/poi/distances",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
params={"listing_id": listing_id, "listing_type": listing_type},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
user_id = resolve_user_id(cli_ctx.user_email)
|
||||
repo = POIRepository(engine)
|
||||
distances = poi_service.get_distances_for_listing(repo, listing_id, lt, user_id)
|
||||
data = [
|
||||
{
|
||||
"poi_id": d.poi_id,
|
||||
"travel_mode": d.travel_mode,
|
||||
"duration_seconds": d.duration_seconds,
|
||||
"distance_meters": d.distance_meters,
|
||||
}
|
||||
for d in distances
|
||||
]
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
123
cli/tasks.py
Normal file
123
cli/tasks.py
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
"""Debug CLI — task management commands."""
|
||||
import click
|
||||
import httpx
|
||||
|
||||
from cli._context import CliContext, get_http_headers, output, error_output
|
||||
from services import task_service
|
||||
|
||||
|
||||
@click.group("tasks")
|
||||
def tasks_group() -> None:
|
||||
"""Background task management commands."""
|
||||
pass
|
||||
|
||||
|
||||
@tasks_group.command("status")
|
||||
@click.argument("task_id")
|
||||
@click.pass_context
|
||||
def task_status(ctx: click.Context, task_id: str) -> None:
|
||||
"""Get the status of a background task."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.get(
|
||||
f"{cli_ctx.api_base_url}/api/task_status",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
params={"task_id": task_id},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
status = task_service.get_task_status(task_id)
|
||||
data = {
|
||||
"task_id": status.task_id,
|
||||
"status": status.status,
|
||||
"progress": status.progress,
|
||||
"processed": status.processed,
|
||||
"total": status.total,
|
||||
"message": status.message,
|
||||
"error": status.error,
|
||||
}
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@tasks_group.command("list")
|
||||
@click.pass_context
|
||||
def list_tasks(ctx: click.Context) -> None:
|
||||
"""List all task IDs for the user."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.get(
|
||||
f"{cli_ctx.api_base_url}/api/tasks_for_user",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
data = task_service.get_user_tasks(cli_ctx.user_email)
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@tasks_group.command("cancel")
|
||||
@click.argument("task_id")
|
||||
@click.pass_context
|
||||
def cancel_task(ctx: click.Context, task_id: str) -> None:
|
||||
"""Cancel a running task."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.post(
|
||||
f"{cli_ctx.api_base_url}/api/cancel_task",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
params={"task_id": task_id},
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
task_service.cancel_task(task_id, user_email=cli_ctx.user_email)
|
||||
data = {"success": True, "message": "Task cancelled"}
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
|
||||
|
||||
@tasks_group.command("clear")
|
||||
@click.pass_context
|
||||
def clear_tasks(ctx: click.Context) -> None:
|
||||
"""Clear all tasks for the user."""
|
||||
cli_ctx: CliContext = ctx.obj["cli_ctx"]
|
||||
|
||||
try:
|
||||
if cli_ctx.use_http:
|
||||
resp = httpx.post(
|
||||
f"{cli_ctx.api_base_url}/api/clear_all_tasks",
|
||||
headers=get_http_headers(cli_ctx.user_email),
|
||||
)
|
||||
resp.raise_for_status()
|
||||
data = resp.json()
|
||||
else:
|
||||
count = task_service.clear_all_tasks(cli_ctx.user_email)
|
||||
data = {"success": True, "count": count, "message": f"Cleared {count} tasks"}
|
||||
|
||||
output(data, cli_ctx.json_output)
|
||||
except httpx.HTTPStatusError as e:
|
||||
error_output(f"HTTP {e.response.status_code}: {e.response.text}", cli_ctx.json_output)
|
||||
except Exception as e:
|
||||
error_output(str(e), cli_ctx.json_output)
|
||||
6
main.py
6
main.py
|
|
@ -472,6 +472,9 @@ def calculate_poi(poi_id: int, travel_modes: str, listing_type: str) -> None:
|
|||
|
||||
from cli._context import CliContext
|
||||
from cli.districts import districts_group
|
||||
from cli.decisions import decisions_group
|
||||
from cli.pois import pois_group
|
||||
from cli.tasks import tasks_group
|
||||
|
||||
|
||||
@cli.group("debug")
|
||||
|
|
@ -492,6 +495,9 @@ def debug(ctx: click.Context, user_email: str, use_http: bool, json_output: bool
|
|||
|
||||
|
||||
debug.add_command(districts_group)
|
||||
debug.add_command(decisions_group)
|
||||
debug.add_command(pois_group)
|
||||
debug.add_command(tasks_group)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
|||
|
|
@ -54,3 +54,56 @@ class TestDistrictsCommand:
|
|||
import json
|
||||
data = json.loads(result.output)
|
||||
assert "London" in data
|
||||
|
||||
|
||||
class TestDecisionsCommand:
|
||||
"""Tests for debug decisions subcommand."""
|
||||
|
||||
@patch("cli.decisions.decision_service.set_decision")
|
||||
@patch("cli.decisions.resolve_user_id", return_value=1)
|
||||
@patch("main.engine", new_callable=MagicMock)
|
||||
def test_set_decision_direct(
|
||||
self, mock_engine: MagicMock, mock_resolve: MagicMock, mock_set: MagicMock
|
||||
) -> None:
|
||||
from datetime import datetime
|
||||
mock_set.return_value = MagicMock(
|
||||
listing_id=123, listing_type="RENT", decision="liked",
|
||||
created_at=datetime(2025, 1, 1), updated_at=datetime(2025, 1, 1),
|
||||
)
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(
|
||||
cli, ["debug", "-u", "test@example.com", "decisions", "set", "123", "liked", "-t", "RENT"]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
mock_set.assert_called_once()
|
||||
|
||||
@patch("cli.decisions.decision_service.get_user_decisions")
|
||||
@patch("cli.decisions.resolve_user_id", return_value=1)
|
||||
@patch("main.engine", new_callable=MagicMock)
|
||||
def test_list_decisions_direct(
|
||||
self, mock_engine: MagicMock, mock_resolve: MagicMock, mock_list: MagicMock
|
||||
) -> None:
|
||||
mock_list.return_value = []
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(
|
||||
cli, ["debug", "-u", "test@example.com", "decisions", "list"]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
|
||||
|
||||
class TestPOIsCommand:
|
||||
"""Tests for debug pois subcommand."""
|
||||
|
||||
@patch("cli.pois.poi_service.get_user_pois")
|
||||
@patch("cli.pois.resolve_user_id", return_value=1)
|
||||
@patch("main.engine", new_callable=MagicMock)
|
||||
def test_list_pois_empty(
|
||||
self, mock_engine: MagicMock, mock_resolve: MagicMock, mock_pois: MagicMock
|
||||
) -> None:
|
||||
mock_pois.return_value = []
|
||||
runner = CliRunner()
|
||||
result = runner.invoke(
|
||||
cli, ["debug", "-u", "test@example.com", "pois", "list"]
|
||||
)
|
||||
assert result.exit_code == 0
|
||||
assert "No results" in result.output
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue