Skip to content

Commit

Permalink
feature: unittests (#57)
Browse files Browse the repository at this point in the history
* feature: unittests

* [fix+feature]: fix config file test and add codecoverage

- `test_config_file` unittest fixed for missing keys in config file
Now it tests against existing keys in config file and ignores the rest
(the rest of keys are default and previously are tested in `test_defaults`)

* [feature]: add unittest github action

a github action file for running unittest on PR and pushes with action
result badge in README.md

* [fix]: fix test dir name

* [fix]: fix GH action

for requirements

* [fix]: typo fix

* update new arguments from main updates

now supports port option
  • Loading branch information
RYNEQ authored Jun 18, 2022
1 parent 6f26700 commit 63bc2df
Showing 7 changed files with 151 additions and 5 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/unittest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: UnitTest

on:
pull_request:
push:

jobs:
unittest:
runs-on: ubuntu-latest
name: Run UnitTests
steps:
- uses: actions/checkout@v2
- name: Set up Python
id: setup-python
uses: actions/setup-python@v2
with:
python-version: 3
- name: Install requirements
run: pip install -r requirements.txt
- name: Launch tests
run: python -m unittest discover test

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -129,3 +129,4 @@ dmypy.json
.pyre/

tracevis_data/
.coverage
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -3,6 +3,8 @@ Traceroute with any packet. Visualize the routes. Discover Middleboxes and Firew

[![CodeQL](https://github.com/wikicensorship/tracevis/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/wikicensorship/tracevis/actions/workflows/codeql-analysis.yml)
[![Dockerise](https://github.com/wikicensorship/tracevis/actions/workflows/docker.yml/badge.svg)](https://github.com/wikicensorship/tracevis/actions/workflows/docker.yml)
[![unittest](https://github.com/wikicensorship/tracevis/actions/workflows/unittest.yml/badge.svg)](https://github.com/wikicensorship/tracevis/actions/workflows/unittest.yml)


TraceVis is a research project whose main goal is to find middleboxes. Where a packet is tampered with or blocked. This tool also has other features such as downloading and visualizing traceroute data from RIPE Atlas probes.

2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
scapy
pyvis
pyvis
Empty file added test/__init__.py
Empty file.
121 changes: 121 additions & 0 deletions test/test_operationality.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import unittest
import tracevis
import sys


class TestArguments(unittest.TestCase):
def test_help(self):
from io import StringIO
out,err = StringIO(), StringIO()
sys.stdout, sys.stderr = out, err
with self.assertRaises(SystemExit):
tracevis.get_args(['-h'], auto_exit=True)
self.assertIn(err.getvalue(), "usage:")
sys.stdout, sys.stderr = sys.__stdout__, sys.__stderr__

def test_no_args(self):
from io import StringIO
out,err = StringIO(), StringIO()
sys.stdout, sys.stderr = out, err
with self.assertRaises(SystemExit):
tracevis.get_args([], auto_exit=True)
self.assertIn(err.getvalue(), "usage:")
sys.stdout, sys.stderr = sys.__stdout__, sys.__stderr__


def test_defaults(self):
from io import StringIO
out,err = StringIO(), StringIO()
sys.stdout, sys.stderr = out, err
args = tracevis.get_args([], auto_exit=False)
expected = {'config_file': None, 'name': None, 'ips': None, 'packet': False, 'packet_input_method': 'hex',
'packet_data': None, 'dns': False, 'dnstcp': False, 'continue': False, 'maxttl': None,
'timeout': None, 'repeat': None, 'ripe': None, 'ripemids': None, 'file': None, 'csv': False,
'csvraw': False, 'attach': False, 'label': None, 'domain1': None, 'domain2': None, 'annot1': None,
'annot2': None, 'rexmit': False, 'paris': False, 'options': 'new', 'iface': None, 'show_ifaces': False, 'port': None}
self.assertEqual(args, expected)
sys.stdout, sys.stderr = sys.__stdout__, sys.__stderr__

def test_config_file(self):
from io import StringIO
import os, json
md = self.maxDiff
self.maxDiff = None
out,err = StringIO(), StringIO()
sys.stdout, sys.stderr = out, err
samples_dir = 'samples/'
for file in os.listdir(samples_dir):
args = tracevis.get_args(['--config-file', os.path.join(samples_dir, file)], auto_exit=False)
with open(os.path.join(samples_dir, file), 'r') as f:
expected = json.load(f)
del args['config_file']
for k,v in args.items():
if k in expected:
self.assertEqual(v, expected[k])

sys.stdout, sys.stderr = sys.__stdout__, sys.__stderr__
self.maxDiff = md

def test_dns_mode(self):
from io import StringIO
out,err = StringIO(), StringIO()
sys.stdout, sys.stderr = out, err
args = tracevis.get_args(['--dns'], auto_exit=False)
expected = {'config_file': None, 'name': None, 'ips': None, 'packet': False, 'packet_input_method': None,
'packet_data': None, 'dns': True, 'dnstcp': False, 'continue': False, 'maxttl': None,
'timeout': None, 'repeat': None, 'ripe': None, 'ripemids': None, 'file': None, 'csv': False,
'csvraw': False, 'attach': False, 'label': None, 'domain1': None, 'domain2': None, 'annot1': None,
'annot2': None, 'rexmit': False, 'paris': False, 'options': 'new', 'iface': None, 'show_ifaces': False, 'port': None}
self.assertEqual(args, expected)
sys.stdout, sys.stderr = sys.__stdout__, sys.__stderr__

def test_packet_mode(self):
from io import StringIO
out,err = StringIO(), StringIO()
sys.stdout, sys.stderr = out, err
args = tracevis.get_args(['--packet'], auto_exit=False)
expected = {'config_file': None, 'name': None, 'ips': None, 'packet': True, 'packet_input_method': 'hex',
'packet_data': None, 'dns': False, 'dnstcp': False, 'continue': False, 'maxttl': None,
'timeout': None, 'repeat': None, 'ripe': None, 'ripemids': None, 'file': None, 'csv': False,
'csvraw': False, 'attach': False, 'label': None, 'domain1': None, 'domain2': None, 'annot1': None,
'annot2': None, 'rexmit': False, 'paris': False, 'options': 'new', 'iface': None, 'show_ifaces': False, 'port': None}
self.assertEqual(args, expected)
sys.stdout, sys.stderr = sys.__stdout__, sys.__stderr__

def test_packet_input_types(self):
from io import StringIO
out,err = StringIO(), StringIO()
sys.stdout, sys.stderr = out, err
args = tracevis.get_args(['--packet', '--packet-input-method', 'hex'], auto_exit=False)
expected = {'config_file': None, 'name': None, 'ips': None, 'packet': True, 'packet_input_method': 'hex',
'packet_data': None, 'dns': False, 'dnstcp': False, 'continue': False, 'maxttl': None,
'timeout': None, 'repeat': None, 'ripe': None, 'ripemids': None, 'file': None, 'csv': False,
'csvraw': False, 'attach': False, 'label': None, 'domain1': None, 'domain2': None, 'annot1': None,
'annot2': None, 'rexmit': False, 'paris': False, 'options': 'new', 'iface': None, 'show_ifaces': False, 'port': None}
self.assertEqual(args, expected)

args = tracevis.get_args(['--packet', '--packet-input-method', 'json'], auto_exit=False)
expected = {'config_file': None, 'name': None, 'ips': None, 'packet': True, 'packet_input_method': 'json',
'packet_data': None, 'dns': False, 'dnstcp': False, 'continue': False, 'maxttl': None,
'timeout': None, 'repeat': None, 'ripe': None, 'ripemids': None, 'file': None, 'csv': False,
'csvraw': False, 'attach': False, 'label': None, 'domain1': None, 'domain2': None, 'annot1': None,
'annot2': None, 'rexmit': False, 'paris': False, 'options': 'new', 'iface': None, 'show_ifaces': False, 'port': None}
self.assertEqual(args, expected)

args = tracevis.get_args(['--packet', '--packet-input-method', 'interactive'], auto_exit=False)
expected = {'config_file': None, 'name': None, 'ips': None, 'packet': True, 'packet_input_method': 'interactive',
'packet_data': None, 'dns': False, 'dnstcp': False, 'continue': False, 'maxttl': None,
'timeout': None, 'repeat': None, 'ripe': None, 'ripemids': None, 'file': None, 'csv': False,
'csvraw': False, 'attach': False, 'label': None, 'domain1': None, 'domain2': None, 'annot1': None,
'annot2': None, 'rexmit': False, 'paris': False, 'options': 'new', 'iface': None, 'show_ifaces': False, 'port': None}
self.assertEqual(args, expected)

args = tracevis.get_args(['--packet', '--packet-input-method', 'json', '--packet-data', 'b64:e30='], auto_exit=False)
expected = {'config_file': None, 'name': None, 'ips': None, 'packet': True, 'packet_input_method': 'json',
'packet_data': 'b64:e30=', 'dns': False, 'dnstcp': False, 'continue': False, 'maxttl': None,
'timeout': None, 'repeat': None, 'ripe': None, 'ripemids': None, 'file': None, 'csv': False,
'csvraw': False, 'attach': False, 'label': None, 'domain1': None, 'domain2': None, 'annot1': None,
'annot2': None, 'rexmit': False, 'paris': False, 'options': 'new', 'iface': None, 'show_ifaces': False, 'port': None}
self.assertEqual(args, expected)
sys.stdout, sys.stderr = sys.__stdout__, sys.__stderr__

8 changes: 4 additions & 4 deletions tracevis.py
Original file line number Diff line number Diff line change
@@ -84,7 +84,7 @@ def process_input_args(args, parser):
return args_dict


def get_args():
def get_args(sys_args, auto_exit=True):
parser = argparse.ArgumentParser(
description='Traceroute with any packet. \
Visualize the routes. Discover Middleboxes and Firewalls', formatter_class=argparse.RawTextHelpFormatter)
@@ -155,10 +155,10 @@ def get_args():
help="set the target network interface")
parser.add_argument('--show-ifaces', action='store_true',
help="show the network interfaces (conf.route)")
if len(sys.argv) == 1:
if len(sys_args) == 0 and auto_exit:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
args = parser.parse_args(sys_args)
args_dict = process_input_args(args, parser)
return args_dict

@@ -339,4 +339,4 @@ def main(args):


if __name__ == "__main__":
main(get_args())
main(get_args(sys.argv[1:]))

0 comments on commit 63bc2df

Please sign in to comment.