Skip to content

Commit

Permalink
rpki parsing tests: test validations, set up test context
Browse files Browse the repository at this point in the history
set up a test context to use with pytest's tmp_path
refactor epoch dir setup in order to handle mocking it.
Add a rpki_raw.json fixture, and a tests/util.py module.
  • Loading branch information
jurraca committed Feb 7, 2025
1 parent ba9b24e commit ffa208a
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 22 deletions.
44 changes: 22 additions & 22 deletions kartograf/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ class Context:
def __init__(self, args):
self.args = args

# The epoch is used to keep artifacts seperated for each run. This
# The epoch is used to keep artifacts separated for each run. This
# makes cleanup and debugging easier.
if args.wait:
utc_time_now = args.wait
if self.args.wait:
self.epoch = self.args.wait
elif self.args.epoch:
self.epoch = self.args.epoch
else:
utc_time_now = time.time()
# Uncomment this random fixed date for testing purposes
# time_now = datetime(2008, 10, 31)
self.epoch = str(int(time.time()))

self.reproduce = self.args.reproduce is not None
if self.reproduce:
Expand All @@ -31,18 +31,7 @@ def __init__(self, args):
self.args.irr = 'irr' in source_folders
self.args.routeviews = 'collectors' in source_folders

repro_epoch = datetime.utcfromtimestamp(int(self.args.epoch))

# When we reproduce we are not really using the data from that
# epoch, so better to signal that data is coming from a
# reproduction run.
self.epoch = self.args.epoch
self.epoch_dir = "r" + self.args.epoch
self.epoch_datetime = repro_epoch
else:
self.epoch = str(int(utc_time_now))
self.epoch_dir = str(int(utc_time_now))
self.epoch_datetime = datetime.utcfromtimestamp(int(utc_time_now))
self._set_epoch_dirs()

cwd = Path.cwd()
# Data dir
Expand All @@ -67,10 +56,6 @@ def __init__(self, args):
self.out_dir_rpki = str(Path(self.out_dir) / "rpki")
self.out_dir_collectors = str(Path(self.out_dir) / "collectors")

if Path(self.data_dir).exists() and not self.reproduce:
print("Not so fast, a folder with that epoch already exists.")
sys.exit()

# We skip creating the folders if we are reproducing a run.
if not self.reproduce:
Path(self.data_dir_rpki_cache).mkdir(parents=True)
Expand All @@ -93,3 +78,18 @@ def __init__(self, args):
self.debug_log = str(Path(self.out_dir) / "debug.log")
else:
self.debug_log = ""


def _set_epoch_dirs(self):
'''
If doing a reproduction run, we will prepend the directory name with a "r"
to separate it from the original run directory.
'''
if self.reproduce and self.epoch:
# both reproduce and epoch args are set: this is a reproduction run
repro_epoch = datetime.utcfromtimestamp(int(self.args.epoch))
self.epoch_dir = "r" + self.epoch
self.epoch_datetime = repro_epoch
else:
self.epoch_dir = self.epoch
self.epoch_datetime = datetime.utcfromtimestamp(int(self.epoch))
12 changes: 12 additions & 0 deletions tests/data/rpki_raw.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
aia,aki,cert_issuer,cert_serial,error,file,hash_id,sia,signing_time,ski,type,valid_since,valid_until,validation,prefix,asid,maxlen,test_case
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,2A789934ED3D1853C03BA192AFF9CBBE2A44E891,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a31313a3a2f34382d3438203d3e203439313334.roa,jJJsAMYzGpr8h9jrBTHvkZWOWQcbQsY6KFav/8MwBC4=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a31313a3a2f34382d3438203d3e203439313334.roa,1721069362,C4:F5:41:EE:72:30:C9:A4:9E:76:FD:FB:C7:85:FE:C7:2B:EE:E6:CA,roa,1721069062,1752518962,OK,2602:fd60:11::/48,49134,48,valid
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,618746799E365F8F63A3CAB2A372ABE6816EC3F6,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a3a2f34342d3434203d3e20333936353033.roa,JrIkZRssmOONk/CBI9A9neb6L4O1efvsso1ar/lUbHQ=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a3a2f34342d3434203d3e20333936353033.roa,1721069361,5A:89:FE:EA:7D:A9:81:96:46:49:C5:25:07:37:B5:F4:AA:A5:96:91,roa,1721069061,1752518961,OK,2602:fd60::/44,396503,44,valid
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,4973C3937B8453A08847D3B995C1CA41BA28D153,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/3135382e35312e3131332e302f32342d3234203d3e203233343730.roa,18oKgF1Or7jXF1G/gggLM4BHgRLPSPi64hFZ2Z8UHk8=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/3135382e35312e3131332e302f32342d3234203d3e203233343730.roa,1706756675,88:21:48:93:4E:7A:2C:6C:6F:F0:D2:0B:7B:3D:D2:BC:DA:80:84:4D,roa,1706756375,1738206275,OK,158.51.113.0/24,23470,24,valid
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,6BE1ADC656C88D467CBF06BB2E890B95BCA0B24E,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a6666303a3a2f34382d3438203d3e20313337393038.roa,EhQRnwfEIqL4rpYQmSzoByvQElLITMmNQmilR4MYPc4=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a6666303a3a2f34382d3438203d3e20313337393038.roa,1721069361,DB:B0:C0:44:5D:A4:86:C2:55:E2:07:55:EE:30:85:E6:CB:59:31:84,roa,1721069061,1752518961,OK,2602:fd60:ff0::/48,137908,48,valid
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,45D9858BC753770DD894B50587AF74A5D61E238C,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a653a3a2f34382d3438203d3e20333936353033.roa,9BdIkUhCxm4K663U7LFp/tM71Hq0nDVSFP6NvT0pngQ=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a653a3a2f34382d3438203d3e20333936353033.roa,1702699880,CF:BC:73:EE:A3:DB:A2:5E:7A:2B:AE:DF:2D:AE:0E:6E:89:70:1D:69,roa,1702699580,1734149480,OK,2602:fd60:e::/48,396503,48,valid
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,2AEA9B91583807D0CBBA0C4F0998FC56E89AAE7F,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a373a3a2f34382d3438203d3e20333936353033.roa,TAHubY+7GFPqIJIlhlmcQzM/eqNRhS0m4z1pEbe1cmQ=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a373a3a2f34382d3438203d3e20333936353033.roa,1725124096,C0:F1:6A:8D:95:BE:AB:A0:96:A3:9C:04:02:65:8A:7D:9E:DE:EE:C4,roa,1725123796,1756573696,OK,2602:fd60:7::/48,396503,48,valid
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,2AEA9B91583807D0CBBA0C4F0998FC56E89AAE7F,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a373a3a2f34382d3438203d3e20333936353033.roa,TAHubY+7GFPqIJIlhlmcQzM/eqNRhS0m4z1pEbe1cmQ=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/323630323a666436303a373a3a2f34382d3438203d3e20333936353033.roa,1725124096,C0:F1:6A:8D:95:BE:AB:A0:96:A3:9C:04:02:65:8A:7D:9E:DE:EE:C4,roa,1725123796,1756573696,OK,2602:fd60:7::/48,396503,48,duplicate of row above
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,775EA3FF97551B8DAB1870EE20B90C6D38AFE3F3,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/32332e3135342e38312e302f32342d3234203d3e203533333536.roa,7pPxkgwX/p8qZcZ4U4B6r43qRmLaDzJ9eipWTWYXVgQ=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/32332e3135342e38312e302f32342d3234203d3e203533333536.roa,1702699880,98:23:C0:CD:73:C0:73:4B:88:4C:8E:A2:FE:FC:94:59:27:54:FC:CF,roa,1702699580,1734149480,OK,23.154.81.0/24,53356,24,valid
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,66D4203E6D324EDF7DB13F151CE102BE0DBE1200,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/32332e3135342e38312e302f32342d3234203d3e20333936353033.roa,Wfz/lTUfLoaYSWzIWHHqfxFY68pwclupNoh7qMD/dy4=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/32332e3135342e38312e302f32342d3234203d3e20333936353033.roa,1721069363,EF:A6:FD:C7:47:52:EA:52:97:81:CB:E6:BC:08:E1:89:74:01:CE:54,roa,1721069063,1752518963,OK,23.154.81.0/24,396503,24,duplicate of row above
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,35802871A8C539AD5A498BEDDDEF0D3F70E27D85,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/32332e3135342e38302e302f32342d3234203d3e20323133313836.roa,5DOfCcd4V1zI0oWAJNiXnZVa/zwdfo+24eD0OBlrFy4=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/32332e3135342e38302e302f32342d3234203d3e20323133313836.roa,1721921309,BA:47:CE:B1:56:FB:2F:78:B5:37:B4:63:10:F4:17:1F:BB:2C:6A:FB,err,1721921009,1753370909,OK,23.154.80.0/24,213186,24,type is not “roa”
rsync://rpki.arin.net/repository/arin-rpki-ta/5e4a23ea-e80a-403e-b08c-2171da2157d3/f60c9f32-a87c-4339-a2f3-6299a3b02e29/1146938c-c605-4779-bf60-820a16fa701c/8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b.cer,86:A9:90:76:61:0E:7C:08:AE:DD:CE:87:67:AA:5D:C4:52:8C:49:08,/CN=8f6916d463bfc5c35e4659c12889a337f3cc6f6b7fe978372b,77C98DB3245AF48F037FF77D087EB06EC63AAC8D,unable to get local issuer certificate,/home/kartograf/data/1730210400/rpki/cache/rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/3135382e35312e3131322e302f32342d3234203d3e20333936353033.roa,/pHsoAr4Krm+kx64aCsYjFRuk+JnfbiC6JA9UWV27TQ=,rsync://rpki.tools.westconnect.ca/repo/WestConnect-Pub/0/3135382e35312e3131322e302f32342d3234203d3e20333936353033.roa,1721069362,C5:65:B7:B3:AA:F9:59:32:0B:F5:50:24:70:01:09:71:4D:FC:20:24,roa,1721069062,1752518962,Failed,158.51.112.0/24,396503,24,failed validation
97 changes: 97 additions & 0 deletions tests/rpki_parse_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import json
import os

from kartograf.rpki.parse import parse_rpki
from .context import create_test_context
from .util import flatten


def prefixes_from_vrps(vrps):
pfxs = []
for items in vrps:
if 'prefix' in items.keys():
pfxs.append(items['prefix'])
return pfxs


def test_roa_validations(tmp_path, capsys):
'''
The ROA validation informs the user of invalids, incompletes, not-ROAs etc
but not data is returned to that effect, so we test stdout's messages.
We assert on the length of the output file, and assert on duplicates.
The fixtures file should output 7 entries, with 2 duplicates, 1 not-ROA, and
1 invalid entry.
'''
epoch = "111111111"
context = create_test_context(tmp_path, epoch)
parse_rpki(context)

# Check that rpki_final.txt was created
final_path = os.path.join(context.out_dir_rpki, "rpki_final.txt")
assert os.path.exists(final_path), "rpki_final.txt should exist"

# Read the raw JSON to compare counts
with open(os.path.join(context.out_dir_rpki, "rpki_raw.json"), "r") as f:
raw_data = json.load(f)

# Count entries in final output
with open(final_path, "r") as f:
final_lines = f.readlines()

# Count of duplicates should be the count of final output minus the count
# of unique prefixes in the raw data
prefixes = [prefixes_from_vrps(roa['vrps']) for roa in raw_data]
duplicates = len(set(flatten(prefixes))) - len(final_lines)

captured = capsys.readouterr()
assert len(final_lines) == 7, "Should have found 7 valid ROAs"
assert duplicates == 2, "Should have found 2 duplicates"
assert "Result entries written: 7" in captured.out
assert "Duplicates found: 2" in captured.out
assert "Invalids found: 1" in captured.out
assert "Incompletes: 0" in captured.out
assert "Non-ROA files: 1" in captured.out

def test_roa_incompletes(tmp_path, capsys):
'''
Test that the ROA file has missing entries.
The data is mocked here and written to a json file.
'''
epoch = "111111112"
context = create_test_context(tmp_path, epoch)
test_data = [
{
"type": "roa",
"validation": "OK",
"ski": "some-ski",
"vrps": [{"prefix": "192.0.2.0/24", "asid": "64496", "maxlen": "24"}],
"valid_until": "1234567890",
"valid_since": "1234567880"
},
{
"type": "roa",
"validation": "OK",
"ski": "some-ski",
"vrps": [{"prefix": "198.51.100.0/24", "asid": "64497", "maxlen": "24"}],
"valid_until": "1234567890",
"valid_since": "1234567880"
}
]

# Write test data to rpki_raw.json
with open(os.path.join(context.out_dir_rpki, "rpki_raw.json"), "w") as f:
json.dump(test_data, f)

parse_rpki(context)

# Check that rpki_final.txt was created
final_path = os.path.join(context.out_dir_rpki, "rpki_final.txt")
assert os.path.exists(final_path), "rpki_final.txt should exist"

# Count entries in final output
with open(final_path, "r") as f:
final_lines = f.readlines()

assert len(final_lines) == 0, "No rows should be written"
captured = capsys.readouterr()
assert "Incompletes: 2" in captured.out
9 changes: 9 additions & 0 deletions tests/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'''
Utilities for testing purposes only.
'''

def flatten(nested_list):
'''
Flatten a 2D array without importing a dependency or using numpy arrays.
'''
return [item for sublist in nested_list for item in sublist]

0 comments on commit ffa208a

Please sign in to comment.