dissertation-3-evaluation/structure/environments.py
2020-12-12 17:15:09 +00:00

115 lines
4.0 KiB
Python

import threading
from typing import Tuple, Optional
from structure import Bridge, StandardTest, SpeedTestServer, Node, IperfResult, RemotePortal, Interface, \
IpMethod, LocalPortal
from structure.tests import repeat_until_satisfied
class BaseEnvironment:
def __init__(self, runner, top_level_bridge: Bridge):
self.top_level_bridge = top_level_bridge
self._runner = runner
def __enter__(self):
try:
self._runner.build(self.top_level_bridge)
except Exception as e:
self._runner.teardown()
raise e
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self._runner.teardown()
def _test(
self,
test: StandardTest,
inbound_server: SpeedTestServer,
inbound_client: SpeedTestServer,
rated_node: Node,
expected_interfaces: int,
) -> Tuple[IperfResult, IperfResult]:
if len(test.rates) != expected_interfaces:
raise RuntimeError('mismatched number of interfaces')
results = []
for server, client in [(inbound_server, inbound_client), (inbound_client, inbound_server)]:
def test_reducer(old: Optional[IperfResult]) -> IperfResult:
for i, r in enumerate(test.rates):
rated_node.get_interfaces()[i].set_rate(r)
server.server()
for delay, (index, rate) in test.events.items():
iface = rated_node.get_interfaces()[index]
threading.Timer(6 + delay, iface.set_rate, args=[rate]).start()
iperf = client.client(server, time=test.duration)
if old is None:
return IperfResult(test, iperf)
else:
old.add_results(iperf)
return old
def test_satisfier(val: IperfResult) -> bool:
if val.num_tests < 3:
return False
return val.bandwidth_coefficient_variance() < test.bandwidth_variation_target and False not in \
[x < test.interval_variation_target for x in val.interval_coefficient_variances().values()]
result = repeat_until_satisfied(
test_reducer,
test_satisfier,
max_failures=test.max_failures,
max_attempts=test.max_attempts,
)
results.append(result)
# Return a tuple of (inbound, outbound)
return results[0], results[1]
def test(self, test: StandardTest) -> Tuple[IperfResult, IperfResult]:
raise RuntimeError('not implemented')
class StandardEnvironment(BaseEnvironment):
def __init__(self, interfaces: int, runner, setup_params: dict):
self._interfaces = interfaces
self.rp = RemotePortal([Interface(IpMethod.Auto4)], setup_params=setup_params)
self.st = SpeedTestServer()
self.cl = SpeedTestServer(clone_interface=self.rp.get_interfaces()[0])
self.lp = LocalPortal(
[Interface(IpMethod.Auto4) for _ in range(interfaces)],
self.cl,
setup_params=setup_params,
)
self.rp.set_local_portal(self.lp)
self.lp.set_remote_portal(self.rp)
super().__init__(runner, Bridge(
self.st.get_interfaces()[0],
self.rp.get_interfaces()[0],
*self.lp.get_interfaces()[0:interfaces],
))
def test(self, test: StandardTest) -> Tuple[IperfResult, IperfResult]:
return self._test(test, self.st, self.cl, self.lp, self._interfaces)
class DirectEnvironment(BaseEnvironment):
def __init__(self, runner):
self.st1 = SpeedTestServer()
self.st2 = SpeedTestServer()
super().__init__(runner, Bridge(
self.st1.get_interfaces()[0],
self.st2.get_interfaces()[0],
))
def test(self, test: StandardTest) -> Tuple[IperfResult, IperfResult]:
return self._test(test, self.st2, self.st1, self.st2, 1)