Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test updates #33

Merged
merged 5 commits into from
Aug 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
Docs [here](https://github.com/jfuruness/bgpy/wiki)
Docs [here](https://github.com/jfuruness/bgpy/wiki)
6 changes: 6 additions & 0 deletions bgpy/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,9 @@ class SpecialPercentAdoptions(Enum):

def __float__(self) -> float:
return float(self.value)

def __lt__(self, other):
if isinstance(other, (SpecialPercentAdoptions, float)):
return float(self) == float(other)
else:
return NotImplemented
17 changes: 14 additions & 3 deletions bgpy/simulation_framework/graph_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from itertools import product
from pathlib import Path
import pickle
from typing import Union

import matplotlib # type: ignore
import matplotlib.pyplot as plt # type: ignore
Expand All @@ -10,6 +11,8 @@
from .metric_tracker.metric_key import MetricKey
from .utils import get_all_metric_keys

from bgpy.enums import SpecialPercentAdoptions


class GraphFactory:
"""Automates graphing of default graphs"""
Expand Down Expand Up @@ -84,11 +87,19 @@ def _generate_graph(self, metric_key: MetricKey, relevant_rows, adopting) -> Non
plt.xlim(0, 100)
plt.ylim(0, 100)

def get_percent_adopt(graph_row) -> Union[float, SpecialPercentAdoptions]:
"""Extractions percent adoption for sort comparison

Need separate function for mypy puposes
"""

percent_adopt = graph_row["data_key"].percent_adopt
assert isinstance(percent_adopt, (float, SpecialPercentAdoptions))
return percent_adopt

# Add the data from the lines
for as_cls, graph_rows in as_cls_rows_dict.items():
graph_rows_sorted = list(
sorted(graph_rows, key=lambda x: x["data_key"].percent_adopt)
)
graph_rows_sorted = list(sorted(graph_rows, key=get_percent_adopt))
ax.errorbar(
[x["data_key"].percent_adopt * 100 for x in graph_rows_sorted],
[x["value"] for x in graph_rows_sorted],
Expand Down
2 changes: 1 addition & 1 deletion bgpy/simulation_framework/metric_tracker/metric.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class Metric:
def __init__(
self,
metric_key: MetricKey,
percents: Optional[defaultdict[str, list[float]]] = None,
percents: Optional[defaultdict[MetricKey, list[float]]] = None,
) -> None:
self.metric_key: MetricKey = metric_key
self._numerators: defaultdict[type[AS], float] = defaultdict(float)
Expand Down
34 changes: 21 additions & 13 deletions bgpy/simulation_framework/scenarios/scenario.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from ipaddress import IPv6Network
from typing import Any, Optional, Union

from frozendict import frozendict

from bgpy.caida_collector import AS

from .scenario_config import ScenarioConfig
Expand Down Expand Up @@ -40,11 +42,11 @@ def __init__(
self.scenario_config: ScenarioConfig = scenario_config
self.percent_adoption: Union[float, SpecialPercentAdoptions] = percent_adoption

self.attacker_asns: set[int] = self._get_attacker_asns(
self.attacker_asns: frozenset[int] = self._get_attacker_asns(
scenario_config.override_attacker_asns, engine, prev_scenario
)

self.victim_asns: set[int] = self._get_victim_asns(
self.victim_asns: frozenset[int] = self._get_victim_asns(
scenario_config.override_victim_asns, engine, prev_scenario
)

Expand Down Expand Up @@ -72,10 +74,10 @@ def __init__(

def _get_attacker_asns(
self,
override_attacker_asns: Optional[set[int]],
override_attacker_asns: Optional[frozenset[int]],
engine: Optional[SimulationEngine],
prev_scenario: Optional["Scenario"],
) -> set[int]:
) -> frozenset[int]:
"""Returns attacker ASN at random"""

# This is coming from YAML, do not recalculate
Expand All @@ -91,7 +93,7 @@ def _get_attacker_asns(
engine, self.percent_adoption, prev_scenario
)
# https://stackoverflow.com/a/15837796/8903959
attacker_asns = set(
attacker_asns = frozenset(
random.sample(
tuple(possible_attacker_asns), self.scenario_config.num_attackers
)
Expand Down Expand Up @@ -125,10 +127,10 @@ def _get_possible_attacker_asns(

def _get_victim_asns(
self,
override_victim_asns: Optional[set[int]],
override_victim_asns: Optional[frozenset[int]],
engine: Optional[SimulationEngine],
prev_scenario: Optional["Scenario"],
) -> set[int]:
) -> frozenset[int]:
"""Returns victim ASN at random"""

# This is coming from YAML, do not recalculate
Expand All @@ -144,7 +146,7 @@ def _get_victim_asns(
engine, self.percent_adoption, prev_scenario
)
# https://stackoverflow.com/a/15837796/8903959
victim_asns = set(
victim_asns = frozenset(
random.sample(
tuple(possible_victim_asns), self.scenario_config.num_victims
)
Expand Down Expand Up @@ -177,7 +179,12 @@ def _get_possible_victim_asns(

def _get_non_default_asn_cls_dict(
self,
override_non_default_asn_cls_dict: Optional[dict[int, type[AS]]],
override_non_default_asn_cls_dict: Union[
Optional[frozendict[int, type[AS]]],
# Must include due to mypy weirdness
# about empty frozendicts
frozendict[str, None],
],
engine: Optional[SimulationEngine],
prev_scenario: Optional["Scenario"],
) -> dict[int, type[AS]]:
Expand All @@ -192,7 +199,8 @@ def _get_non_default_asn_cls_dict(
"""

if override_non_default_asn_cls_dict is not None:
return override_non_default_asn_cls_dict
# Must ignore type here since mypy doesn't understand frozendict
return override_non_default_asn_cls_dict # type: ignore
# By default, use the last engine input to maintain static
# adoption across the graph
elif prev_scenario:
Expand Down Expand Up @@ -272,19 +280,19 @@ def _get_randomized_non_default_asn_cls_dict(
return asn_cls_dict

@property
def _default_adopters(self) -> set[int]:
def _default_adopters(self) -> frozenset[int]:
"""By default, victim always adopts"""

return self.victim_asns

@property
def _default_non_adopters(self) -> set[int]:
def _default_non_adopters(self) -> frozenset[int]:
"""By default, attacker always does not adopt"""

return self.attacker_asns

@property
def _preset_asns(self) -> set[int]:
def _preset_asns(self) -> frozenset[int]:
"""ASNs that have a preset adoption policy"""

# Returns the union of default adopters and non adopters
Expand Down
12 changes: 9 additions & 3 deletions bgpy/simulation_framework/scenarios/scenario_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import abc
from dataclasses import asdict, dataclass, field
from typing import Any, Optional, TYPE_CHECKING
from typing import Any, Optional, Union, TYPE_CHECKING

from frozendict import frozendict

Expand Down Expand Up @@ -49,12 +49,18 @@ class ScenarioConfig:
victim_subcategory_attr: str = ASGroups.STUBS_OR_MH.value
# ASes that are hardcoded to specific values
hardcoded_asn_cls_dict: frozendict[int, type[AS]] = field(
default_factory=frozendict
# Mypy doesn't understand frozendict typing, just ignore it
default_factory=frozendict # type: ignore
)
# Only necessary if coming from YAML or the test suite
override_attacker_asns: Optional[frozenset[int]] = None
override_victim_asns: Optional[frozenset[int]] = None
override_non_default_asn_cls_dict: Optional[frozendict[int, type[AS]]] = None
# For some reason mypy has trouble with empty frozendicts
# So I've included that as a second option for typing purposes
# (specifically with the tests)
override_non_default_asn_cls_dict: Union[
Optional[frozendict[int, type[AS]]], frozendict[str, None]
] = None
override_announcements: tuple[Announcement, ...] = ()
# If you'd like to add an extra CSV label you do so here
csv_label: str = ""
Expand Down
6 changes: 4 additions & 2 deletions bgpy/simulation_framework/utils.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import Iterable

from frozendict import frozendict

from bgpy.caida_collector import CaidaCollector
Expand Down Expand Up @@ -37,10 +39,10 @@ def get_real_world_rov_asn_cls_dict(
else:
raise NotImplementedError("ROV filtering case not accoutned for")

return frozendict(**asn_as_cls_dict)
return frozendict({int(k): v for k, v in asn_as_cls_dict.items()})


def get_all_metric_keys() -> MetricKey:
def get_all_metric_keys() -> Iterable[MetricKey]:
"""Returns all possible metric key combos"""

for plane in Plane:
Expand Down
5 changes: 1 addition & 4 deletions bgpy/tests/caida_collector_tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,7 @@ def mock_caida_collector():
Clears cache and tsv before yielding"""

with patch(
(
"bgpy.caida_collector.caida_collector."
"html_funcs.requests.get"
),
("bgpy.caida_collector.caida_collector." "html_funcs.requests.get"),
mocked_requests_get,
):
with patch(
Expand Down
6 changes: 2 additions & 4 deletions bgpy/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def pytest_sessionfinish(session, exitstatus):
# Only run in master thread after all other threads/tests have finished
# Also runs when xdist isn't running
if not hasattr(session.config, "workerinput"):
# DiagramAggregator(DIAGRAM_PATH).aggregate_diagrams()
DiagramAggregator(DIAGRAM_PATH).aggregate_diagrams()
# Teardown stuff (open PDF for viewing)
if session.config.getoption("view"):
# https://stackoverflow.com/q/19453338/8903959
Expand All @@ -46,8 +46,6 @@ def overwrite(pytestconfig):
# https://stackoverflow.com/a/66597438/8903959
def pytest_addoption(parser):
# View test PDF when complete
# NOTE: This is temporarily down after v 1.0.0, will be fixed the
# week of July 17
# parser.addoption("--view", action="store_true", default=False)
parser.addoption("--view", action="store_true", default=False)
# Overwrite ground truth
parser.addoption("--overwrite", action="store_true", default=False)
4 changes: 2 additions & 2 deletions bgpy/tests/engine_tests/engine_test_configs/config_032.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ def post_propagation_hook(self, engine=None, propagation_round=0, *args, **kwarg
object.__setattr__(ann, "seed_asn", 3)
object.__setattr__(ann, "as_path", (3,))
engine.as_dict[3]._local_rib.add_ann(ann)
Custom32ValidPrefix.victim_asns = {2, 3}
self.victim_asns = {2, 3}
Custom32ValidPrefix.victim_asns = frozenset({2, 3})
self.victim_asns = frozenset({2, 3})


config_032 = EngineTestConfig(
Expand Down
4 changes: 2 additions & 2 deletions bgpy/tests/engine_tests/engine_test_configs/config_033.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ def post_propagation_hook(self, engine=None, propagation_round=0, *args, **kwarg
object.__setattr__(ann, "seed_asn", 3)
object.__setattr__(ann, "as_path", (3,))
engine.as_dict[3]._local_rib.add_ann(ann)
Custom33ValidPrefix.victim_asns = {2, 3}
self.victim_asns = {2, 3}
Custom33ValidPrefix.victim_asns = frozenset({2, 3})
self.victim_asns = frozenset({2, 3})


config_033 = EngineTestConfig(
Expand Down
4 changes: 2 additions & 2 deletions bgpy/tests/engine_tests/engine_test_configs/config_034.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def post_propagation_hook(self, engine=None, propagation_round=0, *args, **kwarg
object.__setattr__(ann, "seed_asn", 3)
object.__setattr__(ann, "as_path", (3,))
engine.as_dict[3]._local_rib.add_ann(ann)
Custom34ValidPrefix.victim_asns = {2, 3}
Custom34ValidPrefix.victim_asns = frozenset({2, 3})

if propagation_round == 2: # third round
ann = deepcopy(engine.as_dict[3]._local_rib.get_ann(Prefixes.PREFIX.value))
Expand All @@ -34,7 +34,7 @@ def post_propagation_hook(self, engine=None, propagation_round=0, *args, **kwarg
engine.as_dict[3]._local_rib.remove_ann(Prefixes.PREFIX.value)
engine.as_dict[3]._ribs_out.remove_entry(1, Prefixes.PREFIX.value)
engine.as_dict[3]._send_q.add_ann(1, ann)
Custom34ValidPrefix.victim_asns = {2}
Custom34ValidPrefix.victim_asns = frozenset({2})


config_034 = EngineTestConfig(
Expand Down
2 changes: 1 addition & 1 deletion bgpy/tests/engine_tests/utils/engine_tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def _compare_data(self):
with self.metrics_ground_truth_path_csv.open() as ground_truth_f:
guess_lines = set([tuple(x) for x in csv.reader(guess_f)])
gt_lines = set([tuple(x) for x in csv.reader(ground_truth_f)])
assert gt_lines == guess_lines, self.metrics_guess_path
assert gt_lines == guess_lines, self.metrics_guess_path_csv

# Compare metrics YAML
with self.metrics_guess_path_pickle.open("rb") as f:
Expand Down
Loading
Loading