Skip to content

Commit 7250387

Browse files
test(cli): add failing tests for env list servers
1 parent 851c866 commit 7250387

File tree

1 file changed

+331
-0
lines changed

1 file changed

+331
-0
lines changed

tests/integration/cli/test_cli_reporter_integration.py

Lines changed: 331 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1222,3 +1222,334 @@ def test_env_list_hosts_combined_filters(self):
12221222

12231223
# dev environment should NOT appear (doesn't match env filter)
12241224
assert "0.9.0" not in output, "Version 0.9.0 from dev should NOT appear"
1225+
1226+
1227+
class TestEnvListServersCommand:
1228+
"""Integration tests for env list servers command.
1229+
1230+
Reference: R10 §3.4 (10-namespace_consistency_specification_v2.md)
1231+
1232+
These tests verify that handle_env_list_servers:
1233+
1. Reads from environment data (Hatch-managed packages only)
1234+
2. Shows environment/server/host deployments with columns: Environment → Server → Host → Version
1235+
3. Shows '-' for undeployed packages
1236+
4. Supports --env and --host filters (regex patterns)
1237+
5. Supports --host - to show only undeployed packages
1238+
6. First column (Environment) sorted alphabetically
1239+
"""
1240+
1241+
def test_env_list_servers_uniform_output(self):
1242+
"""Command should produce uniform table output with Environment → Server → Host → Version columns.
1243+
1244+
Reference: R10 §3.4 - Column order matches command structure
1245+
"""
1246+
from hatch.cli.cli_env import handle_env_list_servers
1247+
1248+
mock_env_manager = MagicMock()
1249+
mock_env_manager.list_environments.return_value = [
1250+
{"name": "default"},
1251+
{"name": "dev"},
1252+
]
1253+
mock_env_manager.get_environment_data.side_effect = lambda env_name: {
1254+
"default": {
1255+
"packages": [
1256+
{
1257+
"name": "weather-server",
1258+
"version": "1.0.0",
1259+
"configured_hosts": {"claude-desktop": {}}
1260+
},
1261+
{
1262+
"name": "util-lib",
1263+
"version": "0.5.0",
1264+
"configured_hosts": {} # Undeployed
1265+
}
1266+
]
1267+
},
1268+
"dev": {
1269+
"packages": [
1270+
{
1271+
"name": "test-server",
1272+
"version": "0.1.0",
1273+
"configured_hosts": {"cursor": {}}
1274+
}
1275+
]
1276+
},
1277+
}.get(env_name, {"packages": []})
1278+
1279+
args = Namespace(
1280+
env_manager=mock_env_manager,
1281+
env=None,
1282+
host=None,
1283+
json=False,
1284+
)
1285+
1286+
captured_output = io.StringIO()
1287+
with patch('sys.stdout', captured_output):
1288+
result = handle_env_list_servers(args)
1289+
1290+
output = captured_output.getvalue()
1291+
1292+
# Verify column headers present
1293+
assert "Environment" in output, "Environment column should be present"
1294+
assert "Server" in output, "Server column should be present"
1295+
assert "Host" in output, "Host column should be present"
1296+
assert "Version" in output, "Version column should be present"
1297+
1298+
# Verify data appears
1299+
assert "default" in output, "default environment should appear"
1300+
assert "dev" in output, "dev environment should appear"
1301+
assert "weather-server" in output, "weather-server should appear"
1302+
assert "util-lib" in output, "util-lib should appear"
1303+
assert "test-server" in output, "test-server should appear"
1304+
1305+
def test_env_list_servers_env_filter_exact(self):
1306+
"""--env flag with exact name should filter to matching environment only.
1307+
1308+
Reference: R10 §3.4 - --env <pattern> filter
1309+
"""
1310+
from hatch.cli.cli_env import handle_env_list_servers
1311+
1312+
mock_env_manager = MagicMock()
1313+
mock_env_manager.list_environments.return_value = [
1314+
{"name": "default"},
1315+
{"name": "dev"},
1316+
]
1317+
mock_env_manager.get_environment_data.side_effect = lambda env_name: {
1318+
"default": {
1319+
"packages": [
1320+
{"name": "server-a", "version": "1.0.0", "configured_hosts": {"claude-desktop": {}}}
1321+
]
1322+
},
1323+
"dev": {
1324+
"packages": [
1325+
{"name": "server-b", "version": "0.1.0", "configured_hosts": {"claude-desktop": {}}}
1326+
]
1327+
},
1328+
}.get(env_name, {"packages": []})
1329+
1330+
args = Namespace(
1331+
env_manager=mock_env_manager,
1332+
env="default",
1333+
host=None,
1334+
json=False,
1335+
)
1336+
1337+
captured_output = io.StringIO()
1338+
with patch('sys.stdout', captured_output):
1339+
result = handle_env_list_servers(args)
1340+
1341+
output = captured_output.getvalue()
1342+
1343+
# Matching environment should appear
1344+
assert "server-a" in output, "server-a from default should appear"
1345+
1346+
# Non-matching environment should NOT appear
1347+
assert "server-b" not in output, "server-b from dev should NOT appear"
1348+
1349+
def test_env_list_servers_env_filter_pattern(self):
1350+
"""--env flag with regex pattern should filter matching environments.
1351+
1352+
Reference: R10 §3.4 - --env accepts regex patterns
1353+
"""
1354+
from hatch.cli.cli_env import handle_env_list_servers
1355+
1356+
mock_env_manager = MagicMock()
1357+
mock_env_manager.list_environments.return_value = [
1358+
{"name": "default"},
1359+
{"name": "dev"},
1360+
{"name": "dev-staging"},
1361+
]
1362+
mock_env_manager.get_environment_data.side_effect = lambda env_name: {
1363+
"default": {
1364+
"packages": [
1365+
{"name": "server-a", "version": "1.0.0", "configured_hosts": {"claude-desktop": {}}}
1366+
]
1367+
},
1368+
"dev": {
1369+
"packages": [
1370+
{"name": "server-b", "version": "0.1.0", "configured_hosts": {"claude-desktop": {}}}
1371+
]
1372+
},
1373+
"dev-staging": {
1374+
"packages": [
1375+
{"name": "server-c", "version": "0.2.0", "configured_hosts": {"claude-desktop": {}}}
1376+
]
1377+
},
1378+
}.get(env_name, {"packages": []})
1379+
1380+
args = Namespace(
1381+
env_manager=mock_env_manager,
1382+
env="dev.*",
1383+
host=None,
1384+
json=False,
1385+
)
1386+
1387+
captured_output = io.StringIO()
1388+
with patch('sys.stdout', captured_output):
1389+
result = handle_env_list_servers(args)
1390+
1391+
output = captured_output.getvalue()
1392+
1393+
# Matching environments should appear
1394+
assert "server-b" in output, "server-b from dev should appear"
1395+
assert "server-c" in output, "server-c from dev-staging should appear"
1396+
1397+
# Non-matching environment should NOT appear
1398+
assert "server-a" not in output, "server-a from default should NOT appear"
1399+
1400+
def test_env_list_servers_host_filter_exact(self):
1401+
"""--host flag with exact name should filter to matching host only.
1402+
1403+
Reference: R10 §3.4 - --host <pattern> filter
1404+
"""
1405+
from hatch.cli.cli_env import handle_env_list_servers
1406+
1407+
mock_env_manager = MagicMock()
1408+
mock_env_manager.list_environments.return_value = [{"name": "default"}]
1409+
mock_env_manager.get_environment_data.return_value = {
1410+
"packages": [
1411+
{"name": "server-a", "version": "1.0.0", "configured_hosts": {"claude-desktop": {}}},
1412+
{"name": "server-b", "version": "2.0.0", "configured_hosts": {"cursor": {}}},
1413+
]
1414+
}
1415+
1416+
args = Namespace(
1417+
env_manager=mock_env_manager,
1418+
env=None,
1419+
host="claude-desktop",
1420+
json=False,
1421+
)
1422+
1423+
captured_output = io.StringIO()
1424+
with patch('sys.stdout', captured_output):
1425+
result = handle_env_list_servers(args)
1426+
1427+
output = captured_output.getvalue()
1428+
1429+
# Matching host should appear
1430+
assert "server-a" in output, "server-a on claude-desktop should appear"
1431+
1432+
# Non-matching host should NOT appear
1433+
assert "server-b" not in output, "server-b on cursor should NOT appear"
1434+
1435+
def test_env_list_servers_host_filter_pattern(self):
1436+
"""--host flag with regex pattern should filter matching hosts.
1437+
1438+
Reference: R10 §3.4 - --host accepts regex patterns
1439+
"""
1440+
from hatch.cli.cli_env import handle_env_list_servers
1441+
1442+
mock_env_manager = MagicMock()
1443+
mock_env_manager.list_environments.return_value = [{"name": "default"}]
1444+
mock_env_manager.get_environment_data.return_value = {
1445+
"packages": [
1446+
{"name": "server-a", "version": "1.0.0", "configured_hosts": {"claude-desktop": {}}},
1447+
{"name": "server-b", "version": "2.0.0", "configured_hosts": {"cursor": {}}},
1448+
{"name": "server-c", "version": "3.0.0", "configured_hosts": {"claude-code": {}}},
1449+
]
1450+
}
1451+
1452+
args = Namespace(
1453+
env_manager=mock_env_manager,
1454+
env=None,
1455+
host="claude.*", # Regex pattern
1456+
json=False,
1457+
)
1458+
1459+
captured_output = io.StringIO()
1460+
with patch('sys.stdout', captured_output):
1461+
result = handle_env_list_servers(args)
1462+
1463+
output = captured_output.getvalue()
1464+
1465+
# Matching hosts should appear
1466+
assert "server-a" in output, "server-a on claude-desktop should appear"
1467+
assert "server-c" in output, "server-c on claude-code should appear"
1468+
1469+
# Non-matching host should NOT appear
1470+
assert "server-b" not in output, "server-b on cursor should NOT appear"
1471+
1472+
def test_env_list_servers_host_filter_undeployed(self):
1473+
"""--host - should show only undeployed packages.
1474+
1475+
Reference: R10 §3.4 - Special filter for undeployed packages
1476+
"""
1477+
from hatch.cli.cli_env import handle_env_list_servers
1478+
1479+
mock_env_manager = MagicMock()
1480+
mock_env_manager.list_environments.return_value = [{"name": "default"}]
1481+
mock_env_manager.get_environment_data.return_value = {
1482+
"packages": [
1483+
{"name": "deployed-server", "version": "1.0.0", "configured_hosts": {"claude-desktop": {}}},
1484+
{"name": "util-lib", "version": "0.5.0", "configured_hosts": {}}, # Undeployed
1485+
{"name": "debug-lib", "version": "0.3.0", "configured_hosts": {}}, # Undeployed
1486+
]
1487+
}
1488+
1489+
args = Namespace(
1490+
env_manager=mock_env_manager,
1491+
env=None,
1492+
host="-", # Special filter for undeployed
1493+
json=False,
1494+
)
1495+
1496+
captured_output = io.StringIO()
1497+
with patch('sys.stdout', captured_output):
1498+
result = handle_env_list_servers(args)
1499+
1500+
output = captured_output.getvalue()
1501+
1502+
# Undeployed packages should appear
1503+
assert "util-lib" in output, "util-lib (undeployed) should appear"
1504+
assert "debug-lib" in output, "debug-lib (undeployed) should appear"
1505+
1506+
# Deployed package should NOT appear
1507+
assert "deployed-server" not in output, "deployed-server should NOT appear"
1508+
1509+
def test_env_list_servers_combined_filters(self):
1510+
"""Combined --env and --host filters should work with AND logic.
1511+
1512+
Reference: R10 §1.5 - Combined filters
1513+
"""
1514+
from hatch.cli.cli_env import handle_env_list_servers
1515+
1516+
mock_env_manager = MagicMock()
1517+
mock_env_manager.list_environments.return_value = [
1518+
{"name": "default"},
1519+
{"name": "dev"},
1520+
]
1521+
mock_env_manager.get_environment_data.side_effect = lambda env_name: {
1522+
"default": {
1523+
"packages": [
1524+
{"name": "server-a", "version": "1.0.0", "configured_hosts": {"claude-desktop": {}}},
1525+
{"name": "server-b", "version": "2.0.0", "configured_hosts": {"cursor": {}}},
1526+
]
1527+
},
1528+
"dev": {
1529+
"packages": [
1530+
{"name": "server-c", "version": "0.1.0", "configured_hosts": {"claude-desktop": {}}},
1531+
]
1532+
},
1533+
}.get(env_name, {"packages": []})
1534+
1535+
args = Namespace(
1536+
env_manager=mock_env_manager,
1537+
env="default",
1538+
host="claude-desktop",
1539+
json=False,
1540+
)
1541+
1542+
captured_output = io.StringIO()
1543+
with patch('sys.stdout', captured_output):
1544+
result = handle_env_list_servers(args)
1545+
1546+
output = captured_output.getvalue()
1547+
1548+
# Only server-a from default on claude-desktop should appear
1549+
assert "server-a" in output, "server-a should appear"
1550+
1551+
# server-b should NOT appear (wrong host)
1552+
assert "server-b" not in output, "server-b should NOT appear"
1553+
1554+
# server-c should NOT appear (wrong env)
1555+
assert "server-c" not in output, "server-c should NOT appear"

0 commit comments

Comments
 (0)