Skip to content

Commit

Permalink
new: added tests and test case generating function for iputils
Browse files Browse the repository at this point in the history
  • Loading branch information
cryptaliagy committed Jul 6, 2020
1 parent b372939 commit cbbd3a7
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 8 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ python:
# command to install dependencies
install: "pip install -r requirements.txt . && pip install flake8"
# command to run tests
script:
- python -m unittest discover -s . -p '*_test.py'
script:
- pytest
- flake8 . --count --select=W291,W293,W391 --statistics
15 changes: 9 additions & 6 deletions capirca/utils/iputils.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import ipaddress

def exclude_address(
base_net: ipaddress._BaseNetwork,
exclude_net: ipaddress._BaseNetwork
base_net: ipaddress._BaseNetwork, # pylint disable=protected-access
exclude_net: ipaddress._BaseNetwork # pylint disable=protected-access
):
'''
Function to exclude a subnetwork from another, returning a generator that yields
Expand All @@ -29,14 +29,17 @@ def exclude_address(
A sequence of IP networks that do not encompass the exclude_net
'''

if not base_net._version == exclude_net._version:
if not isinstance(base_net, ipaddress._BaseNetwork): # pylint disable=protected-access
raise TypeError('%s is not a network object' % base_net)

if not isinstance(exclude_net, ipaddress._BaseNetwork): # pylint disable=protected-access
raise TypeError('%s is not a network object' % exclude_net)

if not base_net._version == exclude_net._version: # pylint disable=protected-access
raise TypeError(
'%s and %s are not of the same version' % (base_net, exclude_net)
)

if not isinstance(exclude_net, ipaddress._BaseNetwork):
raise TypeError('%s is not a network object' % exclude_net)

if not exclude_net.subnet_of(base_net):
raise ValueError()
if exclude_net == base_net:
Expand Down
4 changes: 4 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[tool:pytest]
markers =
unit: Marks a unit test
testpath = tests
Empty file added tests/utils/__init__.py
Empty file.
5 changes: 5 additions & 0 deletions tests/utils/address_exclude_test_cases.txt

Large diffs are not rendered by default.

32 changes: 32 additions & 0 deletions tests/utils/iputils_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pytest

import pathlib

from capirca.utils import iputils
from capirca.lib import nacaddr


file_directory = pathlib.Path(__file__).parent.absolute()
exclude_address_testcases = []
with open(str(file_directory)+"/address_exclude_test_cases.txt", 'r') as f:
for line in f:
ipstr, exstrs, restrs = line.strip().split(' ')
ip = nacaddr.IP(ipstr)
exclude_ips = list(map(nacaddr.IP, exstrs.split(',')))
expected_results = []
for i in restrs.split(';'):
result_strings = i.split(',')
ip_map = map(nacaddr.IP, result_strings)
ip_list = list(ip_map)
expected_results.append(ip_list)
for ex, res in zip(exclude_ips, expected_results):
exclude_address_testcases.append((ip, ex, res))

class TestIPUtils:
@pytest.mark.unit
@pytest.mark.parametrize("ip,exclude,expected", exclude_address_testcases)
def test_exclude_address(self, ip, exclude, expected):
result = iputils.exclude_address(ip, exclude)

assert list(result) == expected

50 changes: 50 additions & 0 deletions tools/iputilstools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import random
import ipaddress
import itertools as it


def write_excludes_testcase(ipstr, excludelist='', max_prefix_range=8, max_random_subnets=30):
"""
Writes a testcase to the tests/utils/address_exclude_test_cases.txt file.
Note that the number of prefixes to consider grows exponentially, so unless
you *do* want to consider a large pool to randomly select from, keep it at the default
Args:
ipstr: the ip network as a string (v4 or v6) to base the test on.
excludelist: optional comma-separated string of ip networks to exclude
max_prefix_range: the largest number of prefixes to consider.
max_random_subnets: the number of subnets to do exclusion tests for, if randomly generating
Returns:
None
"""
ip = ipaddress.ip_network(ipstr)
if len(excludelist) == 0: # empty excludelist, making a random one
prefixrange = min(max_prefix_range, ip.max_prefixlen - ip.prefixlen)
excludelist = it.chain.from_iterable(ip.subnets(i) for i in range(1, prefixrange+1))
total_ips = 2**prefixrange
ip_positions = set(
random.choices(
range(total_ips),
k=min(
max_random_subnets,
total_ips
)
)
)
compress_map = (1 if i in ip_positions else 0 for i in range(total_ips))
excludelist = list(it.compress(excludelist, compress_map))
else:
excludelist = list(map(ipaddress.ip_network, excludelist.split(',')))

result_list = []
for address in excludelist:
result_list.append(ip.address_exclude(address))

ipst = str(ip)
exst = ",".join(map(str, excludelist))
rest = ";".join(",".join(map(str, sorted(result))) for result in result_list)
with open('tests/utils/address_exclude_test_cases.txt', 'a') as f:
f.write("%s %s %s\n" % (ipst, exst, rest))



0 comments on commit cbbd3a7

Please sign in to comment.