feat: add cornerstone
This commit is contained in:
@@ -2,6 +2,7 @@ import pytest
|
||||
import respx
|
||||
from httpx import Response
|
||||
|
||||
from traderai.cornerstone_client import CornerstoneClient, parse_cornerstone_item_page
|
||||
from traderai.tools import ToolRegistry
|
||||
from traderai.uex_client import UEXClient
|
||||
|
||||
@@ -213,6 +214,39 @@ class FakeSCMDB:
|
||||
}
|
||||
|
||||
|
||||
class FakeCornerstone:
|
||||
base_url = "https://finder.cstone.test"
|
||||
|
||||
async def list_items(self):
|
||||
return [
|
||||
{"id": "item-abrade", "name": "Abrade Scraper Module", "sold": True},
|
||||
{"id": "item-cinch", "name": "Cinch Scraper Module", "sold": True},
|
||||
{"id": "item-poster", "name": "Zeus 2955 Ship Showdown Poster", "sold": False},
|
||||
]
|
||||
|
||||
async def get_item_page(self, item_id):
|
||||
assert item_id == "item-abrade"
|
||||
return {
|
||||
"url": f"{self.base_url}/ShipSalvageMods1/{item_id}",
|
||||
"html": """
|
||||
<html>
|
||||
<head><title>Star Citizen - Salvage modifier - Abrade Scraper Module</title></head>
|
||||
<body>
|
||||
<table>
|
||||
<tr><td>NAME</td><td>Abrade Scraper Module</td></tr>
|
||||
<tr><td>MANUFACTURER</td><td>Greycat Industrial</td></tr>
|
||||
</table>
|
||||
<table>
|
||||
<tr><th>LOCATION</th><th>BASE PRICE</th><th>VERIFIED</th></tr>
|
||||
<tr><td>Stanton - ArcCorp - Area18 - Dumper's Depot</td><td>21 250</td><td>2956-01-29</td></tr>
|
||||
<tr><td>Stanton - microTech - Port Tressler - Platinum Bay</td><td>21 250</td><td>2956-01-04</td></tr>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
""",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_marketplace_listings_filters_locally():
|
||||
registry = ToolRegistry(FakeUEX())
|
||||
@@ -338,6 +372,15 @@ def test_schemas_expose_scmdb_mission_tools():
|
||||
assert "get_scmdb_mission_rewards" in names
|
||||
|
||||
|
||||
def test_schemas_expose_cornerstone_item_tools():
|
||||
registry = ToolRegistry(FakeUEX(), cornerstone=FakeCornerstone())
|
||||
|
||||
names = {schema["function"]["name"] for schema in registry.schemas}
|
||||
|
||||
assert "search_cornerstone_items" in names
|
||||
assert "get_cornerstone_item_locations" in names
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_scmdb_missions_returns_reward_summary():
|
||||
registry = ToolRegistry(FakeUEX(), scmdb=FakeSCMDB())
|
||||
@@ -368,6 +411,64 @@ async def test_get_scmdb_mission_rewards_enriches_items_blueprints_and_locations
|
||||
assert mission["rewards"]["blueprints"][0]["blueprints"] == ["Abrade Scraper Module"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_cornerstone_items_filters_sold_items():
|
||||
registry = ToolRegistry(FakeUEX(), cornerstone=FakeCornerstone())
|
||||
|
||||
result = await registry.search_cornerstone_items(query="scraper", sold_only=True)
|
||||
|
||||
assert result["matched"] == 2
|
||||
assert {item["name"] for item in result["items"]} == {"Abrade Scraper Module", "Cinch Scraper Module"}
|
||||
assert result["items"][0]["url"].startswith("https://finder.cstone.test/Search/item-")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_get_cornerstone_item_locations_parses_store_prices():
|
||||
registry = ToolRegistry(FakeUEX(), cornerstone=FakeCornerstone())
|
||||
|
||||
result = await registry.get_cornerstone_item_locations(query="abrade", location="Area18")
|
||||
|
||||
assert result["item"]["name"] == "Abrade Scraper Module"
|
||||
assert result["item"]["general"]["manufacturer"] == "Greycat Industrial"
|
||||
assert result["matched_locations"] == 1
|
||||
assert result["locations"] == [
|
||||
{
|
||||
"location": "Stanton - ArcCorp - Area18 - Dumper's Depot",
|
||||
"base_price": 21250,
|
||||
"base_price_display": "21 250",
|
||||
"verified": "2956-01-29",
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
def test_parse_cornerstone_item_page_extracts_locations():
|
||||
parsed = parse_cornerstone_item_page(
|
||||
"""
|
||||
<html><head><title>Star Citizen - Food - Whamburger</title></head>
|
||||
<body><table><tr><td>NAME</td><td>Whamburger</td></tr></table>
|
||||
<table><tr><th>LOCATION</th><th>BASE PRICE</th><th>VERIFIED</th></tr>
|
||||
<tr><td>Stanton - Area18 - Cubby Blast</td><td>9</td><td>2956-01-01</td></tr></table></body></html>
|
||||
"""
|
||||
)
|
||||
|
||||
assert parsed["name"] == "Whamburger"
|
||||
assert parsed["locations"][0]["base_price"] == 9
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@respx.mock
|
||||
async def test_cornerstone_client_accepts_json_encoded_string_payload():
|
||||
respx.get("https://finder.cstone.space/GetSearch").mock(
|
||||
return_value=Response(
|
||||
200,
|
||||
json='[{"id":"item-1","name":"Abrade Scraper Module","Sold":1}]',
|
||||
)
|
||||
)
|
||||
client = CornerstoneClient("https://finder.cstone.space")
|
||||
|
||||
assert await client.list_items() == [{"id": "item-1", "name": "Abrade Scraper Module", "sold": True}]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_uex_api_index_finds_history_tools():
|
||||
registry = ToolRegistry(FakeUEX())
|
||||
|
||||
Reference in New Issue
Block a user