Commit 6ff9fc56 authored by Nigel Kukard's avatar Nigel Kukard
Browse files

Merge branch 'nkupdates' into 'master'

Added tests

See merge request allworldit/python/birdclient!1
parents 3d5c6631 6707b24b
Pipeline #4503 passed with stage
in 27 seconds
...@@ -11,7 +11,6 @@ test_job: ...@@ -11,7 +11,6 @@ test_job:
- pacman -Syu --noconfirm - pacman -Syu --noconfirm
- pacman -S --noconfirm grep python - pacman -S --noconfirm grep python
- pacman -S --noconfirm python-pytest python-pytest-runner python-pytest-cov python-pylint python-isort mypy pylama python-mccabe - pacman -S --noconfirm python-pytest python-pytest-runner python-pytest-cov python-pylint python-isort mypy pylama python-mccabe
- pacman -S --noconfirm iproute2 bird exabgp
# Run tests # Run tests
- python setup.py test - python setup.py test
# Artifacts # Artifacts
......
...@@ -25,8 +25,10 @@ import socket ...@@ -25,8 +25,10 @@ import socket
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
__version__ = '0.0.1'
class Birdc:
class BirdClient:
"""BIRD client class.""" """BIRD client class."""
# Socket file # Socket file
...@@ -34,7 +36,7 @@ class Birdc: ...@@ -34,7 +36,7 @@ class Birdc:
# Ending lines for bird control channel # Ending lines for bird control channel
_ending_lines: List[bytes] _ending_lines: List[bytes]
def __init__(self, socket_file: str): def __init__(self, socket_file: Optional[str] = None):
"""Initialize the object.""" """Initialize the object."""
# Set socket file # Set socket file
...@@ -44,13 +46,6 @@ class Birdc: ...@@ -44,13 +46,6 @@ class Birdc:
def show_status(self, data: Optional[List[str]] = None) -> Dict[str, str]: def show_status(self, data: Optional[List[str]] = None) -> Dict[str, str]:
"""Return parsed BIRD status.""" """Return parsed BIRD status."""
# 0001 BIRD 2.0.4 ready.
# 1000-BIRD 2.0.4
# 1011-Router ID is 172.16.10.1
# Current server time is 2019-08-15 12:42:51.638
# Last reboot on 2019-08-15 12:42:47.592
# Last reconfiguration on 2019-08-15 12:42:47.592
# 0013 Daemon is up and running
# Grab status # Grab status
if not data: if not data:
...@@ -92,22 +87,6 @@ class Birdc: ...@@ -92,22 +87,6 @@ class Birdc:
def show_protocols(self, data: Optional[List[str]] = None) -> Dict[str, Any]: def show_protocols(self, data: Optional[List[str]] = None) -> Dict[str, Any]:
"""Return parsed BIRD protocols.""" """Return parsed BIRD protocols."""
# 0001 BIRD 2.0.4 ready.
# 2002-Name Proto Table State Since Info
# 1002-device1 Device --- up 13:13:28.641
# kernel4 Kernel t_kernel4 up 13:13:28.641
# kernel6 Kernel t_kernel6 up 13:13:28.641
# static4 Static t_static4 up 13:13:28.641
# static6 Static t_static6 up 13:13:28.641
# p_static4_to_kernel4 Pipe --- up 13:13:28.641 t_static4 <=> t_kernel4
# p_static6_to_kernel6 Pipe --- up 13:13:28.641 t_static6 <=> t_kernel6
# ospf4 OSPF t_ospf4 up 13:13:28.641 Alone
# ospf6 OSPF t_ospf6 up 13:13:28.641 Running
# p_ospf4_to_kernel4 Pipe --- up 13:13:28.641 t_ospf4 <=> t_kernel4
# p_ospf6_to_kernel6 Pipe --- up 13:13:28.641 t_ospf6 <=> t_kernel6
# p_ospf4_to_static4 Pipe --- up 13:13:28.641 t_ospf4 <=> t_static4
# p_ospf6_to_static6 Pipe --- up 13:13:28.641 t_ospf6 <=> t_static6
# 0000
# Grab protocols # Grab protocols
if not data: if not data:
...@@ -142,92 +121,6 @@ class Birdc: ...@@ -142,92 +121,6 @@ class Birdc:
# pylama: ignore=R0915,C901 # pylama: ignore=R0915,C901
def show_route_table(self, table: str, data: Optional[List[str]] = None) -> List: def show_route_table(self, table: str, data: Optional[List[str]] = None) -> List:
"""Return parsed BIRD routing table.""" """Return parsed BIRD routing table."""
# 0001 BIRD 2.0.4 ready.
# 1007-Table t_static4:
# 10.0.1.0/24 unicast [static4 13:36:14.198] * (200)
# via 192.168.0.4 on eth0
# 1008- Type: static univ
# 1007-10.0.2.0/24 unicast [static4 13:36:14.198] * (200)
# via 192.168.0.5 on eth0
# 1008- Type: static univ
# 0000
# 0001 BIRD 2.0.4 ready.
# 1007-Table t_kernel4:
# 172.16.100.0/24 unicast [kernel4 13:36:14.199] (10)
# via 172.16.10.10 on eth9
# 1008- Type: inherit univ
# 1007-10.0.1.0/24 unicast [static4 13:36:14.199] * (200)
# via 192.168.0.4 on eth0
# 1008- Type: static univ
# 1007-10.0.2.0/24 unicast [static4 13:36:14.199] * (200)
# via 192.168.0.5 on eth0
# 1008- Type: static univ
# 0000
# 0001 BIRD 2.0.4 ready.
# 1007-Table t_ospf4:
# 172.16.100.0/24 unicast [kernel4 13:36:14.199] (10)
# via 172.16.10.10 on eth9
# 1008- Type: inherit univ
# 1007-10.0.1.0/24 unicast [static4 13:36:14.199] * (200)
# via 192.168.0.4 on eth0
# 1008- Type: static univ
# 1007-10.0.2.0/24 unicast [static4 13:36:14.199] * (200)
# via 192.168.0.5 on eth0
# 1008- Type: static univ
# 0000
# 0001 BIRD 2.0.4 ready.
# 1007-Table t_static6:
# fec0:20::/64 unicast [static6 13:36:14.708] * (200)
# via fec0::5 on eth0
# 1008- Type: static univ
# 1007-fec0:10::/64 unicast [static6 13:36:14.708] * (200)
# via fec0::4 on eth0
# 1008- Type: static univ
# 0000
# 0001 BIRD 2.0.4 ready.
# 1007-Table t_kernel6:
# fec0:20::/64 unicast [static6 13:36:14.708] * (200)
# via fec0::5 on eth0
# 1008- Type: static univ
# 1007-fec0:10::/64 unicast [static6 13:36:14.708] * (200)
# via fec0::4 on eth0
# 1008- Type: static univ
# 0000
# 0001 BIRD 2.0.4 ready.
# 1007-Table t_ospf6:
# fec0:20::/64 unicast [static6 13:36:14.708] * (200)
# via fec0::5 on eth0
# 1008- Type: static univ
# 1007-fec0:10::/64 unicast [static6 13:36:14.708] * (200)
# via fec0::4 on eth0
# 1008- Type: static univ
# 0000
# 0001 BIRD 2.0.4 ready.
# 1007-Table t_ospf6:
# fec0:20::/64 unicast [ospf6 14:20:00.666] E2 (150/20/10000) [172.16.10.1]
# via fe80::8c84:28ff:fe6c:40ae on eth0
# 1008- Type: OSPF-E2 univ
# 1007-fec0:10::/64 unicast [ospf6 14:20:00.666] E2 (150/20/10000) [172.16.10.1]
# via fe80::8c84:28ff:fe6c:40ae on eth0
# 1008- Type: OSPF-E2 univ
# 1007-fec0::/64 unicast [ospf6 14:19:58.660] I (150/20) [172.16.10.1]
# via fe80::8c84:28ff:fe6c:40ae on eth0
# 1008- Type: OSPF univ
# 1007-fefe::/64 unicast [ospf6 14:20:00.666] I (150/30) [172.16.10.1]
# via fe80::8c84:28ff:fe6c:40ae on eth0
# 1008- Type: OSPF univ
# 1007-fec0:1::/64 unicast [ospf6 14:19:58.660] I (150/10) [0.0.0.3]
# dev eth0
# 1008- Type: OSPF univ
# 1007-fefe:1::/64 unicast [ospf6 14:20:00.666] E2 (150/30/10000) [172.16.10.1]
# via fe80::8c84:28ff:fe6c:40ae on eth0
# 1008- Type: OSPF-E2 univ
# Grab routes # Grab routes
if not data: if not data:
......
"""Tests for the Python BirdClient class."""
from typing import List
from birdclient import BirdClient
class TestBirdClient():
"""Test the BirdClient class."""
def _load_file(self, filename: str) -> List[str]:
"""Read in a file and return the lines."""
with open(f'tests/{filename}', 'r') as datafile:
data = datafile.read()
return data.splitlines()
def test_show_status(self):
"""Test show_status."""
birdclient = BirdClient()
result = birdclient.show_status(self._load_file('test_show_status.txt'))
correct_result = {
'last_reboot': '2019-08-15 12:42:47.592',
'last_reconfiguration': '2019-08-15 12:42:47.592',
'router_id': '172.16.10.1',
'server_time': '2019-08-15 12:42:51.638',
'version': '2.0.4'
}
assert result == correct_result, 'The show_status() result does not match what it should be'
def test_show_protocols(self):
"""Test show_protocols."""
birdclient = BirdClient()
result = birdclient.show_protocols(self._load_file('test_show_protocols.txt'))
correct_result = {
'ospf4': {
'info': 'Alone',
'name': 'ospf4',
'proto': 'OSPF',
'since': '13:13:28.641',
'state': 'up',
'table': 't_ospf4'
},
'ospf6': {
'info': 'Running',
'name': 'ospf6',
'proto': 'OSPF',
'since': '13:13:28.641',
'state': 'up',
'table': 't_ospf6'
},
'p_ospf4_to_kernel4': {
'info': 't_ospf4 <=> t_kernel4',
'name': 'p_ospf4_to_kernel4',
'proto': 'Pipe',
'since': '13:13:28.641',
'state': 'up',
'table': '---'
},
'p_ospf4_to_static4': {
'info': 't_ospf4 <=> t_static4',
'name': 'p_ospf4_to_static4',
'proto': 'Pipe',
'since': '13:13:28.641',
'state': 'up',
'table': '---'
},
'p_ospf6_to_kernel6': {
'info': 't_ospf6 <=> t_kernel6',
'name': 'p_ospf6_to_kernel6',
'proto': 'Pipe',
'since': '13:13:28.641',
'state': 'up',
'table': '---'
},
'p_ospf6_to_static6': {
'info': 't_ospf6 <=> t_static6',
'name': 'p_ospf6_to_static6',
'proto': 'Pipe',
'since': '13:13:28.641',
'state': 'up',
'table': '---'
},
'p_static4_to_kernel4': {
'info': 't_static4 <=> t_kernel4',
'name': 'p_static4_to_kernel4',
'proto': 'Pipe',
'since': '13:13:28.641',
'state': 'up',
'table': '---'
},
'p_static6_to_kernel6': {
'info': 't_static6 <=> t_kernel6',
'name': 'p_static6_to_kernel6',
'proto': 'Pipe',
'since': '13:13:28.641',
'state': 'up',
'table': '---'
}
}
assert result == correct_result, 'The show_protocols() result does not match what it should be'
def test_show_route_table_t_static4(self):
"""Test show_route_table."""
birdclient = BirdClient()
result = birdclient.show_route_table('t_static4', self._load_file('test_show_route_table_t_static4.txt'))
correct_result = [
{
'prefix': '10.0.1.0/24',
'primary': '*',
'proto': 'static4',
'since': '13:36:14.198',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': '192.168.0.4',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'prefix': '10.0.2.0/24',
'primary': '*',
'proto': 'static4',
'since': '13:36:14.198',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': '192.168.0.5',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
}
]
assert result == correct_result, 'The show_route_table() result does not match what it should be'
def test_show_route_table_t_static6(self):
"""Test show_route_table."""
birdclient = BirdClient()
result = birdclient.show_route_table('t_static6', self._load_file('test_show_route_table_t_static6.txt'))
correct_result = [
{
'prefix': 'fec0:20::/64',
'primary': '*',
'proto': 'static6',
'since': '13:36:14.708',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': 'fec0::5',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'prefix': 'fec0:10::/64',
'primary': '*',
'proto': 'static6',
'since': '13:36:14.708',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': 'fec0::4',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
}
]
assert result == correct_result, 'The show_route_table() result does not match what it should be'
def test_show_route_table_t_kernel4(self):
"""Test show_route_table."""
birdclient = BirdClient()
result = birdclient.show_route_table('t_kernel4', self._load_file('test_show_route_table_t_kernel4.txt'))
correct_result = [
{
'prefix': '172.16.100.0/24',
'primary': None,
'proto': 'kernel4',
'since': '13:36:14.199',
'type': ['inherit', 'univ'],
'weight': '10',
'nexthops': [{
'gateway': '172.16.10.10',
'interface': 'eth9',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'prefix': '10.0.1.0/24',
'primary': '*',
'proto': 'static4',
'since': '13:36:14.199',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': '192.168.0.4',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'prefix': '10.0.2.0/24',
'primary': '*',
'proto': 'static4',
'since': '13:36:14.199',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': '192.168.0.5',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
}
]
assert result == correct_result, 'The show_route_table() result does not match what it should be'
def test_show_route_table_t_kernel6(self):
"""Test show_route_table."""
birdclient = BirdClient()
result = birdclient.show_route_table('t_kernel6', self._load_file('test_show_route_table_t_kernel6.txt'))
correct_result = [
{
'prefix': 'fec0:20::/64',
'primary': '*',
'proto': 'static6',
'since': '13:36:14.708',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': 'fec0::5',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'prefix': 'fec0:10::/64',
'primary': '*',
'proto': 'static6',
'since': '13:36:14.708',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': 'fec0::4',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
}
]
assert result == correct_result, 'The show_route_table() result does not match what it should be'
def test_show_route_table_t_ospf4(self):
"""Test show_route_table."""
birdclient = BirdClient()
result = birdclient.show_route_table('t_ospf4', self._load_file('test_show_route_table_t_ospf4.txt'))
correct_result = [
{
'prefix': '172.16.100.0/24',
'primary': None,
'proto': 'kernel4',
'since': '13:36:14.199',
'type': ['inherit', 'univ'],
'weight': '10',
'nexthops': [{
'gateway': '172.16.10.10',
'interface': 'eth9',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'prefix': '10.0.1.0/24',
'primary': '*',
'proto': 'static4',
'since': '13:36:14.199',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': '192.168.0.4',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'prefix': '10.0.2.0/24',
'primary': '*',
'proto': 'static4',
'since': '13:36:14.199',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': '192.168.0.5',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
}
]
assert result == correct_result, 'The show_route_table() result does not match what it should be'
def test_show_route_table_t_ospf6_1(self):
"""Test show_route_table."""
birdclient = BirdClient()
result = birdclient.show_route_table('t_ospf6', self._load_file('test_show_route_table_t_ospf6-1.txt'))
correct_result = [
{
'prefix': 'fec0:20::/64',
'primary': '*',
'proto': 'static6',
'since': '13:36:14.708',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': 'fec0::5',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'prefix': 'fec0:10::/64',
'primary': '*',
'proto': 'static6',
'since': '13:36:14.708',
'type': ['static', 'univ'],
'weight': '200',
'nexthops': [{
'gateway': 'fec0::4',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
}
]
assert result == correct_result, 'The show_route_table() result does not match what it should be'
def test_show_route_table_t_ospf6_2(self):
"""Test show_route_table."""
birdclient = BirdClient()
result = birdclient.show_route_table('t_ospf6', self._load_file('test_show_route_table_t_ospf6-2.txt'))
correct_result = [
{
'metric1': '20',
'metric2': '10000',
'ospf_type': 'E2',
'pref': '150',
'prefix': 'fec0:20::/64',
'proto': 'ospf6',
'router_id': '172.16.10.1',
'since': '14:20:00.666',
'tag': None,
'type': ['OSPF-E2', 'univ'],
'nexthops': [{
'gateway': 'fe80::8c84:28ff:fe6c:40ae',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'metric1': '20',
'metric2': '10000',
'ospf_type': 'E2',
'pref': '150',
'prefix': 'fec0:10::/64',
'proto': 'ospf6',
'router_id': '172.16.10.1',
'since': '14:20:00.666',
'tag': None,
'type': ['OSPF-E2', 'univ'],
'nexthops': [{
'gateway': 'fe80::8c84:28ff:fe6c:40ae',
'interface': 'eth0',
'mpls': None,
'onlink': None,
'weight': None
}]
},
{
'metric1': '20',
'metric2': None,
'ospf_type': 'I',
'pref': '150',
'prefix': 'fec0::/64',
'proto': 'ospf6',
'router_id': '172.16.10.1',
'since': '14:19:58.660',
'tag': None,
'type': ['OSPF', 'univ'],
'nexthops': [{
'gateway': 'fe80::8c84:28ff:fe6c:40ae',
'interface': 'eth0',