"""Real PostgreSQL integrity and routing tests for Agent Zones v1.""" import unittest from uuid import UUID from unittest.mock import patch import psycopg from psycopg.errors import ForeignKeyViolation, UniqueViolation from app.agent_zones.repository import AgentZoneRepository from app.config import settings from app.miner_control.repository import MinerControlRepository from app.miner_control.service import MinerControlService from app.miner_control.exceptions import MinerControlUnavailable from app.agent_commands.policy import PHYSICAL_CONTROL_DISABLED SITE_A = UUID("00000000-0000-4000-8000-000000001630") SITE_B = UUID("00000000-0000-4000-8000-000000001631") ZONE_A = UUID("00000000-0000-4000-8000-000000001632") ZONE_B = UUID("00000000-0000-4000-8000-000000001633") ZONE_C = UUID("00000000-0000-4000-8000-000000001636") MINER_UNASSIGNED = UUID("00000000-0000-4000-8000-000000001634") MINER_OTHER = UUID("00000000-0000-4000-8000-000000001635") AGENT_A = "agent-zone-postgres-a" def connect(): return psycopg.connect( host=settings.postgres_host, port=settings.postgres_port, dbname=settings.postgres_db, user=settings.postgres_user, password=settings.postgres_password, connect_timeout=5, ) class AgentZonePostgresTests(unittest.TestCase): def assert_stage_a_unavailable(self, expected_zone, expected_agent): repository = MinerControlRepository(connect) context = repository.get_control_context(MINER_UNASSIGNED) # Check actual routing facts independently of the unconditional Stage A # reason. A changed assertion must not hide a Site fallback regression. self.assertEqual(context["agent_zone_id"], expected_zone) self.assertEqual(context["agent_id"], expected_agent) projection = MinerControlService(repository).get_controls(MINER_UNASSIGNED) for capability in (projection.service_control, projection.performance_mode_control): self.assertEqual(capability.state, "unavailable") self.assertEqual(capability.reason, PHYSICAL_CONTROL_DISABLED) self.assertIsNone(projection.available_service_action) with patch.object(repository, "enqueue_with_audit") as enqueue: for action, value in (("suspend", None), ("resume", None), ("performance_mode", "high")): with self.assertRaisesRegex(MinerControlUnavailable, PHYSICAL_CONTROL_DISABLED): MinerControlService(repository).queue_control( MINER_UNASSIGNED, action, requested_value=value, actor_user_id=UUID("00000000-0000-4000-8000-000000001639"), actor_username="zone-containment-test", ) enqueue.assert_not_called() return context @classmethod def setUpClass(cls): connection = connect() try: with connection.cursor() as cur: cur.execute( "INSERT INTO sites (id, name) VALUES (%s, 'Zone Test A'), " "(%s, 'Zone Test B') ON CONFLICT (id) DO NOTHING", (SITE_A, SITE_B), ) cur.execute( "INSERT INTO agent_zones (id, site_id, name) VALUES " "(%s, %s, 'Main Room'), (%s, %s, 'Remote Room'), " "(%s, %s, 'Unstaffed Zone') " "ON CONFLICT (id) DO UPDATE SET is_enabled = true", (ZONE_A, SITE_A, ZONE_B, SITE_B, ZONE_C, SITE_A), ) cur.execute( "INSERT INTO miners (id, site_id, asset_tag, current_ip, status, " "api3_supported, first_seen_at, last_seen_at) VALUES " "(%s, %s, 'ZONE-UNASSIGNED', '192.0.2.31', 'online', true, NULL, NULL), " "(%s, %s, 'ZONE-OTHER', '192.0.2.32', 'online', true, NULL, NULL) " "ON CONFLICT (id) DO UPDATE SET agent_zone_id = NULL", (MINER_UNASSIGNED, SITE_A, MINER_OTHER, SITE_B), ) cur.execute( "UPDATE miners SET agent_zone_id = %s WHERE id = %s", (ZONE_B, MINER_OTHER), ) cur.execute( "INSERT INTO minerops_site_agents (" "agent_id, site_id, agent_zone_id, site_name, last_payload) " "VALUES (%s, %s, %s, 'Zone Test A', '{\"control_available\":true}') " "ON CONFLICT (agent_id) DO UPDATE SET site_id = EXCLUDED.site_id, " "agent_zone_id = EXCLUDED.agent_zone_id, last_payload = EXCLUDED.last_payload", (AGENT_A, SITE_A, ZONE_A), ) connection.commit() finally: connection.close() @classmethod def tearDownClass(cls): connection = connect() try: with connection.cursor() as cur: cur.execute("DELETE FROM minerops_site_agents WHERE agent_id LIKE 'agent-zone-postgres-%'") cur.execute("DELETE FROM miners WHERE id IN (%s, %s)", (MINER_UNASSIGNED, MINER_OTHER)) cur.execute("DELETE FROM agent_zone_network_ranges WHERE agent_zone_id IN (%s, %s, %s)", (ZONE_A, ZONE_B, ZONE_C)) cur.execute("DELETE FROM agent_zones WHERE id IN (%s, %s, %s)", (ZONE_A, ZONE_B, ZONE_C)) cur.execute("DELETE FROM sites WHERE id IN (%s, %s)", (SITE_A, SITE_B)) connection.commit() finally: connection.close() def setUp(self): connection = connect() try: with connection.cursor() as cur: cur.execute( "UPDATE agent_zones SET is_enabled = true " "WHERE id IN (%s, %s, %s)", (ZONE_A, ZONE_B, ZONE_C), ) cur.execute( "UPDATE miners SET agent_zone_id = NULL WHERE id = %s", (MINER_UNASSIGNED,), ) cur.execute( "UPDATE miners SET site_id = %s, agent_zone_id = %s WHERE id = %s", (SITE_B, ZONE_B, MINER_OTHER), ) cur.execute( "UPDATE minerops_site_agents SET site_id = %s, agent_zone_id = %s " "WHERE agent_id = %s", (SITE_A, ZONE_A, AGENT_A), ) connection.commit() finally: connection.close() def test_repository_lists_multiple_canonical_networks(self): connection = connect() try: with connection.cursor() as cur: cur.execute( "INSERT INTO agent_zone_network_ranges (agent_zone_id, network) " "VALUES (%s, '10.30.0.0/24'), (%s, '10.31.0.0/24') " "ON CONFLICT DO NOTHING", (ZONE_A, ZONE_A), ) connection.commit() finally: connection.close() listed = AgentZoneRepository(connect).list_zones(SITE_A) self.assertEqual([item["network"] for item in listed[0]["networks"]], ["10.30.0.0/24", "10.31.0.0/24"]) def test_active_names_are_case_insensitively_unique_per_site(self): connection = connect() try: with self.assertRaises(UniqueViolation), connection.cursor() as cur: cur.execute( "INSERT INTO agent_zones (site_id, name) VALUES (%s, 'main room')", (SITE_A,), ) finally: connection.rollback() connection.close() def test_one_agent_per_zone_but_multiple_zones_per_site(self): connection = connect() try: with self.assertRaises(UniqueViolation), connection.cursor() as cur: cur.execute( "INSERT INTO minerops_site_agents " "(agent_id, site_id, agent_zone_id, site_name) " "VALUES ('agent-zone-postgres-duplicate', %s, %s, 'Duplicate')", (SITE_A, ZONE_A), ) finally: connection.rollback() connection.close() def test_composite_foreign_keys_reject_cross_site_assignment(self): connection = connect() try: with self.assertRaises(ForeignKeyViolation), connection.cursor() as cur: cur.execute( "UPDATE miners SET agent_zone_id = %s WHERE id = %s", (ZONE_A, MINER_OTHER), ) finally: connection.rollback() connection.close() def test_unassigned_miner_inherits_zone_and_existing_other_zone_wins(self): repository = AgentZoneRepository(connect) outcomes = repository.assign_miners_to_zone( [MINER_UNASSIGNED, MINER_OTHER], ZONE_A ) self.assertEqual(outcomes[MINER_UNASSIGNED], "assigned") self.assertEqual(outcomes[MINER_OTHER], "agent_zone_conflict") connection = connect() try: with connection.cursor() as cur: cur.execute( "SELECT id, agent_zone_id FROM miners WHERE id IN (%s, %s)", (MINER_UNASSIGNED, MINER_OTHER), ) assignments = dict(cur.fetchall()) finally: connection.close() self.assertEqual(assignments[MINER_UNASSIGNED], ZONE_A) self.assertEqual(assignments[MINER_OTHER], ZONE_B) def test_disabled_zone_blocks_control_without_site_fallback(self): connection = connect() try: with connection.cursor() as cur: cur.execute( "UPDATE miners SET agent_zone_id = %s WHERE id = %s", (ZONE_A, MINER_UNASSIGNED), ) cur.execute("UPDATE agent_zones SET is_enabled = false WHERE id = %s", (ZONE_A,)) connection.commit() finally: connection.close() try: context = self.assert_stage_a_unavailable(ZONE_A, AGENT_A) self.assertFalse(context["agent_zone_enabled"]) finally: connection = connect() try: with connection.cursor() as cur: cur.execute("UPDATE agent_zones SET is_enabled = true WHERE id = %s", (ZONE_A,)) connection.commit() finally: connection.close() def test_enabled_zone_without_agent_does_not_fall_back_within_site(self): connection = connect() try: with connection.cursor() as cur: cur.execute( "UPDATE miners SET agent_zone_id = %s WHERE id = %s", (ZONE_C, MINER_UNASSIGNED), ) connection.commit() finally: connection.close() self.assert_stage_a_unavailable(ZONE_C, None) def test_null_zone_does_not_fall_back_to_site_agent(self): self.assert_stage_a_unavailable(None, None) if __name__ == "__main__": unittest.main()