From e0be339280fb18230017dcb91d72a6a1e8538549 Mon Sep 17 00:00:00 2001 From: Ken Celenza Date: Fri, 4 Aug 2023 19:13:40 -0400 Subject: [PATCH] Add int_to_asn function (#332) * Add int_to_asn function * add tests --- docs/user/include_jinja_list.md | 1 + netutils/asn.py | 28 ++++++++++++++++++++++++++++ netutils/utils.py | 1 + tests/unit/test_asn.py | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+) diff --git a/docs/user/include_jinja_list.md b/docs/user/include_jinja_list.md index 4be27d36..a2901448 100644 --- a/docs/user/include_jinja_list.md +++ b/docs/user/include_jinja_list.md @@ -1,6 +1,7 @@ | Filter name | Function | | ---------- | ------ | | asn_to_int | netutils.asn.asn_to_int | +| int_to_asn | netutils.asn.int_to_asn | | bits_to_name | netutils.bandwidth.bits_to_name | | bytes_to_name | netutils.bandwidth.bytes_to_name | | name_to_bits | netutils.bandwidth.name_to_bits | diff --git a/netutils/asn.py b/netutils/asn.py index 04323b4e..f3833908 100644 --- a/netutils/asn.py +++ b/netutils/asn.py @@ -24,3 +24,31 @@ def asn_to_int(asplain: str) -> int: asn = int(f"{int(asn_list[0]):016b}{int(asn_list[1]):016b}", 2) return asn return int(asplain) + + +def int_to_asn(asn_int: int) -> str: + """Convert integer to standardized asplain notation for BGP ASN. + + Args: + asn_int: Integer value of the BGP ASN. + + Returns: + `asplain` notated BGP ASN as a string. + + Examples: + >>> from netutils.asn import int_to_asn + >>> int_to_asn(65000) + '65000' + >>> int_to_asn(4259840111) + '65000.111' + >>> + """ + if isinstance(asn_int, str): + asn_int = int(asn_int) + if asn_int > 2**32 - 1 or asn_int < 1: + raise ValueError(f"`{str(asn_int)}` is not within range of 1 - 2^32-1") + if asn_int >= 2**16: + asn1 = asn_int >> 16 + asn2 = asn_int & ((1 << 16) - 1) + return f"{asn1}.{asn2}" + return str(asn_int) diff --git a/netutils/utils.py b/netutils/utils.py index 9580c278..9eefd912 100644 --- a/netutils/utils.py +++ b/netutils/utils.py @@ -5,6 +5,7 @@ _JINJA2_FUNCTION_MAPPINGS = { "asn_to_int": "asn.asn_to_int", + "int_to_asn": "asn.int_to_asn", "name_to_bits": "bandwidth.name_to_bits", "name_to_bytes": "bandwidth.name_to_bytes", "bits_to_name": "bandwidth.bits_to_name", diff --git a/tests/unit/test_asn.py b/tests/unit/test_asn.py index 045110c2..b73a8aa8 100644 --- a/tests/unit/test_asn.py +++ b/tests/unit/test_asn.py @@ -12,7 +12,39 @@ {"sent": {"asplain": "0.65526"}, "received": 65526}, ] +int_to_asn = [ + {"sent": {"asn_int": 6500}, "received": "6500"}, + {"sent": {"asn_int": 425985111}, "received": "6500.1111"}, + {"sent": {"asn_int": 425984001}, "received": "6500.1"}, + {"sent": {"asn_int": 65546}, "received": "1.10"}, + {"sent": {"asn_int": 65526}, "received": "65526"}, + {"sent": {"asn_int": "65526"}, "received": "65526"}, + {"sent": {"asn_int": "65535"}, "received": "65535"}, + {"sent": {"asn_int": "65536"}, "received": "1.0"}, + {"sent": {"asn_int": "425985111"}, "received": "6500.1111"}, + {"sent": {"asn_int": 4294967295}, "received": "65535.65535"}, +] + +int_to_asn_exceptions = [ + {"asn_int": "one22"}, + {"asn_int": "not_an_int"}, + {"asn_int": "4294967296"}, + {"asn_int": "0"}, + {"asn_int": -1}, +] + @pytest.mark.parametrize("data", asn_to_int) def test_asn_to_int(data): assert asn.asn_to_int(**data["sent"]) == data["received"] + + +@pytest.mark.parametrize("data", int_to_asn) +def test_int_to_asn(data): + assert asn.int_to_asn(**data["sent"]) == data["received"] + + +@pytest.mark.parametrize("data", int_to_asn_exceptions) +def test_int_to_asn_exceptions(data): + with pytest.raises(ValueError): + assert asn.int_to_asn(**data)