更新
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from sqlalchemy import create_engine, inspect, text
|
||||
|
||||
|
||||
BACKEND_DIR = Path(__file__).resolve().parents[1]
|
||||
if str(BACKEND_DIR) not in sys.path:
|
||||
sys.path.insert(0, str(BACKEND_DIR))
|
||||
|
||||
from rpa_engine.egress_channels import (
|
||||
EgressChannel,
|
||||
EgressChannelUnavailable,
|
||||
EgressSnapshot,
|
||||
LocalAddress,
|
||||
discover_egress_channels,
|
||||
reset_egress_cache_for_tests,
|
||||
resolve_send_channels,
|
||||
)
|
||||
from models.db_migrate import migrate_accounts_table
|
||||
|
||||
|
||||
class EgressChannelTests(unittest.IsolatedAsyncioTestCase):
|
||||
def setUp(self):
|
||||
reset_egress_cache_for_tests()
|
||||
|
||||
async def test_discovery_deduplicates_public_ip_and_keeps_bindable_source(self):
|
||||
candidates = [
|
||||
LocalAddress(None, "default", True),
|
||||
LocalAddress("10.0.0.5", "eth0"),
|
||||
LocalAddress("10.0.0.6", "eth0:1"),
|
||||
]
|
||||
|
||||
async def probe(candidate):
|
||||
public_ip = "203.0.113.10" if candidate.source_ip != "10.0.0.6" else "203.0.113.11"
|
||||
return (
|
||||
EgressChannel(
|
||||
public_ip=public_ip,
|
||||
source_ip=candidate.source_ip,
|
||||
interface=candidate.interface,
|
||||
is_default=candidate.is_default,
|
||||
),
|
||||
"",
|
||||
)
|
||||
|
||||
with (
|
||||
patch(
|
||||
"rpa_engine.egress_channels.local_address_candidates",
|
||||
return_value=candidates,
|
||||
),
|
||||
patch(
|
||||
"rpa_engine.egress_channels._probe_local_address",
|
||||
AsyncMock(side_effect=probe),
|
||||
),
|
||||
):
|
||||
snapshot = await discover_egress_channels(force=True)
|
||||
|
||||
self.assertEqual([item.public_ip for item in snapshot.channels], ["203.0.113.10", "203.0.113.11"])
|
||||
self.assertEqual(snapshot.channels[0].source_ip, "10.0.0.5")
|
||||
self.assertTrue(snapshot.channels[0].is_default)
|
||||
|
||||
async def test_selected_channel_is_first_and_attempt_count_is_bounded(self):
|
||||
snapshot = EgressSnapshot(
|
||||
channels=(
|
||||
EgressChannel("198.51.100.1", "10.0.0.1", "eth0", True),
|
||||
EgressChannel("198.51.100.2", "10.0.0.2", "eth0:1"),
|
||||
EgressChannel("198.51.100.3", "10.0.0.3", "eth0:2"),
|
||||
),
|
||||
errors=(),
|
||||
detected_at=time.time(),
|
||||
)
|
||||
with patch(
|
||||
"rpa_engine.egress_channels.discover_egress_channels",
|
||||
AsyncMock(return_value=snapshot),
|
||||
):
|
||||
routes = await resolve_send_channels("198.51.100.2", 2)
|
||||
|
||||
self.assertEqual([item.public_ip for item in routes], ["198.51.100.2", "198.51.100.1"])
|
||||
|
||||
async def test_missing_selected_channel_fails_closed(self):
|
||||
snapshot = EgressSnapshot(
|
||||
channels=(EgressChannel("198.51.100.1", None, "default", True),),
|
||||
errors=(),
|
||||
detected_at=time.time(),
|
||||
)
|
||||
with patch(
|
||||
"rpa_engine.egress_channels.discover_egress_channels",
|
||||
AsyncMock(return_value=snapshot),
|
||||
):
|
||||
with self.assertRaises(EgressChannelUnavailable):
|
||||
await resolve_send_channels("198.51.100.99", 2)
|
||||
|
||||
|
||||
class EgressMigrationTests(unittest.TestCase):
|
||||
def test_old_accounts_table_receives_egress_columns(self):
|
||||
engine = create_engine("sqlite:///:memory:")
|
||||
with engine.begin() as connection:
|
||||
connection.execute(text("CREATE TABLE accounts (id INTEGER PRIMARY KEY)"))
|
||||
migrate_accounts_table(connection)
|
||||
columns = {item["name"] for item in inspect(connection).get_columns("accounts")}
|
||||
|
||||
self.assertIn("egress_public_ip", columns)
|
||||
self.assertIn("egress_auto_attempts", columns)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user