Basic HIP connectivity test

Set up tests compatible with a newer version of CORE (v7.2.1).
Added instructions on how to setup development of tests and running
them.
This commit is contained in:
Simon Wrede 2020-10-14 01:50:54 +02:00
parent 9af42730ee
commit 25e5e1132c
4 changed files with 177 additions and 0 deletions

2
.gitignore vendored
View File

@ -136,3 +136,5 @@ fabric.properties
.history
# End of https://www.gitignore.io/api/c,clion,visualstudiocode
**/__pycache__

18
test/README.md Normal file
View File

@ -0,0 +1,18 @@
# Running
Scripts must be executed within the core python virtual environment. It is
recommended to use the executable installed with core to start this. Note
that most scripts include editing network interfaces, which require super-user
privileges.
```bash
sudo core-python test_hip.py
```
Also note that core-daemon does NOT have to be running.
# Developing
To fully enjoy the capabilities your IDE provides, you must correctly setup the
`PYTHONPATH` environment variable. This should include the directory in which
core was compiled. As an example, to properly setup VSCode a file with the
following contents named `.env` is sufficient:
```
PYTHONPATH=...path_to_core.../daemon
```

99
test/hipnode.py Normal file
View File

@ -0,0 +1,99 @@
import copy
import re
import uuid
from enum import Enum
from subprocess import PIPE, Popen
from xml.etree import ElementTree
from core.nodes.base import CoreNode
class State(Enum):
IDLE = 0
HITGEN = 1
READY = 2
RUNNING = 3
class HIPNode(CoreNode):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.state = State.IDLE
def shutdown(self):
self.stop()
super().shutdown()
def _state_check(self, *states):
if self.state not in states:
raise RuntimeError(f"Current state {self.state} is not one of {states}")
def hitgen(self, ip=None):
self._state_check(State.IDLE, State.HITGEN, State.READY)
if not ip:
ip = self.get_ifaces()[0].get_ip4().ip
self.cmd(
" && ".join(
[
"mkdir -p usr.local.etc.hip",
"mkdir -p /usr/local/etc/hip",
"mount --bind usr.local.etc.hip /usr/local/etc/hip",
"cd /usr/local/etc/hip",
"hitgen -conf",
f"echo '{uuid.uuid4().hex}' | hitgen",
"hitgen -publish",
]
),
shell=True,
)
tree = ElementTree.parse(
f"{self.nodedir}/usr.local.etc.hip/{self.name}_host_identities.pub.xml"
)
root = tree.getroot()
self.host_identity = copy.deepcopy(root[0])
self.host_identity.append(ElementTree.fromstring(f"<addr>{ip}</addr>"))
self.LSI = self.host_identity.find("LSI").text
self.state = State.HITGEN
def set_known_hosts(self, nodes):
self._state_check(State.HITGEN, State.READY)
khi = ElementTree.Element("known_host_identities")
for node in nodes:
khi.append(node.host_identity)
tree = ElementTree.ElementTree(khi)
tree.write(
f"{self.nodedir}/usr.local.etc.hip/known_host_identities.xml",
encoding="utf-8",
xml_declaration=True,
)
self.state = State.READY
def command(self, cmd, *args, **kwargs):
return Popen(
f"vcmd -c {self.ctrlchnlname} -- {cmd}".split(" "), *args, **kwargs
)
def start(self):
self._state_check(State.READY)
self.hip = self.command(
"hip -v",
stdout=PIPE,
universal_newlines=True,
)
self.state = State.RUNNING
self.find(r".*?HIP threads initialization completed.*?")
def find(self, pattern):
while line := self.hip.stdout.readline():
if match := re.match(pattern, line):
return match
def stop(self):
if self.state == State.RUNNING:
self.hip.kill()
self.hip.wait()
self.state = State.READY

58
test/test_hip.py Normal file
View File

@ -0,0 +1,58 @@
import unittest
from subprocess import PIPE
from unittest import TestCase
from core.emulator.coreemu import CoreEmu
from core.emulator.data import IpPrefixes
from core.emulator.enumerations import EventTypes
from core.nodes.network import SwitchNode
from hipnode import HIPNode
class TestHIP(TestCase):
@classmethod
def setUpClass(cls):
cls.coreemu = CoreEmu()
@classmethod
def tearDownClass(cls):
"""We cannot perform manual cleanup of CoreEmu since it ALWAYS performs
a cleanup on terminating signals."""
pass
def setUp(self):
self.session = self.coreemu.create_session()
self.session.set_state(EventTypes.CONFIGURATION_STATE)
self.ip_prefixes = IpPrefixes(ip4_prefix="10.0.0.0/24")
def tearDown(self):
self.coreemu.delete_session(self.session.id)
def test_basic_connectivity(self):
"""Test that two computers connected by a switch can communicate."""
switch = self.session.add_node(SwitchNode)
n1 = self.session.add_node(HIPNode)
n2 = self.session.add_node(HIPNode)
iface1 = self.ip_prefixes.create_iface(n1)
self.session.add_link(n1.id, switch.id, iface1)
iface2 = self.ip_prefixes.create_iface(n2)
self.session.add_link(n2.id, switch.id, iface2)
self.session.instantiate()
n1.hitgen()
n2.hitgen()
n1.set_known_hosts([n1, n2])
n2.set_known_hosts([n1, n2])
n1.start()
n2.start()
ret = n1.command(f"ping -c 1 {n2.LSI}", stdout=PIPE).wait()
self.assertIsNotNone(n1.find(r".*?HIP exchange complete.*?"))
self.assertIsNotNone(n2.find(r".*?HIP exchange complete.*?"))
self.assertEqual(ret, 0)
if __name__ == "__main__":
unittest.main(verbosity=2, warnings="ignore")