feat: new settings, CLI skeleton and interface skeletons
Adds the pydantic-settings Settings with validated GITEA_URL, OAuth scopes and toolsets, the argparse CLI skeleton, catalog.model, identity and GiteaAPIError. Test fixtures now isolate env, cwd and state paths in tmp.
This commit is contained in:
1 parent
4ac9626eb5
commit
b82e2866cb
24 files changed
+1512
-605
No files matched your search
@@ -0,0 +1,117 @@
|
||||
"""Tests for the catalog data model."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from aegis_gitea_mcp.catalog import Operation, Parameter
|
||||
|
||||
|
||||
def sample_dict() -> dict[str, Any]:
|
||||
return {
|
||||
"tool_name": "gitea_issue_create",
|
||||
"domain": "issue",
|
||||
"operation_id": "issueCreateIssue",
|
||||
"method": "POST",
|
||||
"path": "/repos/{owner}/{repo}/issues",
|
||||
"summary": "Create an issue",
|
||||
"description": "",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "owner",
|
||||
"arg_name": "owner",
|
||||
"location": "path",
|
||||
"required": True,
|
||||
"schema": {"type": "string"},
|
||||
"is_file": False,
|
||||
},
|
||||
{
|
||||
"name": "body",
|
||||
"arg_name": "body",
|
||||
"location": "body",
|
||||
"required": False,
|
||||
"schema": {"type": "object"},
|
||||
},
|
||||
],
|
||||
"input_schema": {"type": "object", "additionalProperties": False},
|
||||
"consumes": ["application/json"],
|
||||
"produces": ["application/json"],
|
||||
"read_only": False,
|
||||
"destructive": False,
|
||||
"idempotent": False,
|
||||
"paginated": False,
|
||||
}
|
||||
|
||||
|
||||
def test_operation_round_trip_through_json() -> None:
|
||||
data = sample_dict()
|
||||
operation = Operation.from_dict(data)
|
||||
|
||||
assert operation.method == "POST"
|
||||
assert isinstance(operation.parameters, tuple)
|
||||
assert isinstance(operation.consumes, tuple)
|
||||
assert operation.parameters[0].location == "path"
|
||||
assert operation.parameters[1].is_file is False
|
||||
|
||||
rebuilt = Operation.from_dict(json.loads(json.dumps(operation.to_dict())))
|
||||
assert rebuilt == operation
|
||||
|
||||
|
||||
def test_to_dict_uses_lists_and_is_json_serializable() -> None:
|
||||
dumped = Operation.from_dict(sample_dict()).to_dict()
|
||||
assert isinstance(dumped["parameters"], list)
|
||||
assert isinstance(dumped["consumes"], list)
|
||||
json.dumps(dumped)
|
||||
|
||||
|
||||
def test_method_is_upper_cased() -> None:
|
||||
data = sample_dict()
|
||||
data["method"] = "post"
|
||||
assert Operation.from_dict(data).method == "POST"
|
||||
|
||||
|
||||
def test_optional_fields_default() -> None:
|
||||
data = sample_dict()
|
||||
del data["summary"], data["description"], data["consumes"], data["produces"]
|
||||
operation = Operation.from_dict(data)
|
||||
assert operation.summary == ""
|
||||
assert operation.consumes == ()
|
||||
assert operation.produces == ()
|
||||
|
||||
|
||||
def test_invalid_location_rejected() -> None:
|
||||
with pytest.raises(ValueError, match="location"):
|
||||
Parameter.from_dict(
|
||||
{"name": "x", "arg_name": "x", "location": "header", "required": True, "schema": {}}
|
||||
)
|
||||
|
||||
|
||||
def test_missing_required_key_raises() -> None:
|
||||
data = sample_dict()
|
||||
del data["tool_name"]
|
||||
with pytest.raises(KeyError):
|
||||
Operation.from_dict(data)
|
||||
|
||||
|
||||
def test_operation_is_frozen() -> None:
|
||||
operation = Operation.from_dict(sample_dict())
|
||||
with pytest.raises(AttributeError):
|
||||
operation.method = "GET" # type: ignore[misc]
|
||||
|
||||
|
||||
def test_file_parameter() -> None:
|
||||
parameter = Parameter.from_dict(
|
||||
{
|
||||
"name": "attachment",
|
||||
"arg_name": "attachment",
|
||||
"location": "formData",
|
||||
"required": True,
|
||||
"schema": {"type": "string", "contentEncoding": "base64"},
|
||||
"is_file": True,
|
||||
}
|
||||
)
|
||||
assert parameter.is_file is True
|
||||
assert parameter.to_dict()["location"] == "formData"
|
||||
Reference in new issue
Block a user