shopmanager-train-code / test_env_smoke.py
hard007ik's picture
shop manage eng phase 2 first
048f186
Raw
History Blame Contribute Delete
4.3 kB
"""Standalone, no-LLM, no-server smoke tests for the JewelryShop env.
Run from inside the ShopManagerEng folder so `models` / `server` import.
Usage:
cd ShopManagerEng
SHOPMANAGER_MARKET_MODE=synthetic python test_env_smoke.py # default: A+B
SHOPMANAGER_MARKET_MODE=real python test_env_smoke.py live # C only
python test_env_smoke.py all # all three
Why a script: putting `f'gold_price=${o.gold_price}/oz'` inside `bash -c "..."`
makes bash try to expand `${o.gold_price}` as a shell variable and crash with
`bad substitution`. Running it from a .py file removes that whole class of bugs.
"""
from __future__ import annotations
import os
import sys
from server.ShopManagerEng_environment import JewelryShopEnvironment
from models import JewelryAction
def test_reward_path() -> None:
"""A. Synthetic episode end-to-end, prints per-step partial + cumulative."""
print("\n=== A. reward path (synthetic) ===")
os.environ["SHOPMANAGER_MARKET_MODE"] = "synthetic"
e = JewelryShopEnvironment()
o = e.reset(seed=42, task_id="market_timing", starting_cash=10000.0)
print(
f" reset: phase={o.phase} cash=${o.cash} gold={o.gold_oz}oz "
f"price=${o.gold_price} weights={o.weights}"
)
actions = [
JewelryAction(market_action="buy", gold_qty=1.0),
JewelryAction(product_choice="ring"),
JewelryAction(message="I accept"),
]
for i, a in enumerate(actions, 1):
o = e.step(a)
print(
f" step {i}: phase={o.phase} reward={o.reward:.4f} "
f"cum={o.cumulative_reward:.4f} done={o.done}"
)
print(f" FINAL cum={o.cumulative_reward:.4f} (must be in [0, 1])")
def test_bounce_loop() -> None:
"""B. Warehouse cannot craft -> agent is bounced back to MARKET."""
print("\n=== B. bounce loop (warehouse -> market) ===")
os.environ["SHOPMANAGER_MARKET_MODE"] = "synthetic"
e = JewelryShopEnvironment()
o = e.reset(seed=42, task_id="profit_negotiator", starting_cash=10000.0)
o = e.step(JewelryAction(market_action="buy", gold_qty=0.2))
print(f" bought 0.2oz: phase={o.phase}, gold={o.gold_oz}oz")
o = e.step(JewelryAction(product_choice="ring"))
print(
f" tried ring: phase={o.phase} reentries={o.market_reentries}"
f"/{o.max_market_reentries} urgent={o.inventory_urgent} "
f"cannot_wait={o.cannot_wait}"
)
assert o.phase == "market", "expected bounce back to market"
assert o.inventory_urgent is True, "expected urgent flag"
o = e.step(JewelryAction(market_action="wait"))
print(f" tried wait while urgent: phase={o.phase} (should still be market)")
assert o.phase == "market", "wait should be blocked when urgent"
o = e.step(JewelryAction(market_action="buy", gold_qty=1.0))
print(f" bought 1.0oz more: phase={o.phase} gold={o.gold_oz}oz")
o = e.step(JewelryAction(product_choice="ring"))
print(f" craft ring: phase={o.phase} cum={o.cumulative_reward:.4f}")
o = e.step(JewelryAction(message="I accept"))
print(f" FINAL cum={o.cumulative_reward:.4f}")
def test_live_quote() -> None:
"""C. Real mode: live yfinance gold price (needs network)."""
print("\n=== C. live yfinance quote (real mode) ===")
os.environ["SHOPMANAGER_MARKET_MODE"] = "real"
e = JewelryShopEnvironment()
o = e.reset(seed=0, task_id="market_timing", starting_cash=10000.0)
print(f" gold_price=${o.gold_price}/oz source={o.gold_price_source}")
print(f" market_mode={o.market_mode}")
print(f" history(last 5)={o.gold_price_history[-5:]}")
def main(argv: list[str]) -> None:
arg = (argv[1] if len(argv) > 1 else "default").lower()
if arg in ("default", "ab"):
test_reward_path()
test_bounce_loop()
elif arg == "live":
test_live_quote()
elif arg == "all":
test_reward_path()
test_bounce_loop()
test_live_quote()
elif arg == "a":
test_reward_path()
elif arg == "b":
test_bounce_loop()
elif arg == "c":
test_live_quote()
else:
print(f"unknown arg: {arg}. use one of: a / b / c / ab / live / all")
sys.exit(2)
if __name__ == "__main__":
main(sys.argv)