| |
@@ -0,0 +1,220 @@
|
| |
+ #!/usr/bin/env python3
|
| |
+ # SPDX-License-Identifier: LGPL-2.1+
|
| |
+ # ~~~
|
| |
+ # Description: llibndp provides a wrapper for IPv6 Neighbor Discovery Protocol.
|
| |
+ # Author: Susant Sahani <susant@redhat.com>
|
| |
+ # Copyright (c) 2018 Red Hat, Inc.
|
| |
+ # ~~~
|
| |
+
|
| |
+ import errno
|
| |
+ import os
|
| |
+ import sys
|
| |
+ import time
|
| |
+ import unittest
|
| |
+ import subprocess
|
| |
+ import signal
|
| |
+ import shutil
|
| |
+ import psutil
|
| |
+ import socket
|
| |
+ from pyroute2 import IPRoute
|
| |
+
|
| |
+ LIBNDP_CI_DIR='/var/run/libndp-ci'
|
| |
+ NDPTOOL_CI_LOG='/var/run/libndp-ci/ndptool.log'
|
| |
+
|
| |
+ RADVD_CONFIG_FILE='/var/run/libndp-ci/radvd.conf'
|
| |
+ RADVD_PID_FILE='/var/run/libndp-ci/radvd.pid'
|
| |
+ RADVD_LOG_FILE='/var/run/libndp-ci/radvd.log'
|
| |
+
|
| |
+ def setUpModule():
|
| |
+ """Initialize the environment, and perform sanity checks on it."""
|
| |
+
|
| |
+ if shutil.which('ndptool') is None:
|
| |
+ raise OSError(errno.ENOENT, 'ndptool not found')
|
| |
+ if shutil.which('radvd') is None:
|
| |
+ raise OSError(errno.ENOENT, 'radvd not found')
|
| |
+
|
| |
+ def tearDownModule():
|
| |
+ pass
|
| |
+
|
| |
+ class GenericUtilities():
|
| |
+ """Provide a set of utility functions start stop daemons, Setup veth """
|
| |
+
|
| |
+ def StartRadvd(self):
|
| |
+ """Start radvd"""
|
| |
+
|
| |
+ subprocess.check_output(['radvd', '-d5', '-C', RADVD_CONFIG_FILE, '-p', RADVD_PID_FILE, '-l', RADVD_LOG_FILE])
|
| |
+
|
| |
+ def StartNDPTool(self):
|
| |
+ """Start ndptool """
|
| |
+
|
| |
+ subprocess.check_output(['systemctl','start','ndptool-ci.service'])
|
| |
+
|
| |
+ def StopNDPTool(self):
|
| |
+ """Stop ndptool """
|
| |
+
|
| |
+ subprocess.check_output(['systemctl','stop','ndptool-ci.service'])
|
| |
+
|
| |
+ def StopDaemon(self, pid_file):
|
| |
+
|
| |
+ with open(pid_file, 'r') as f:
|
| |
+ pid = f.read().rstrip(' \t\r\n\0')
|
| |
+ os.kill(int(pid), signal.SIGTERM)
|
| |
+
|
| |
+ os.remove(pid_file)
|
| |
+
|
| |
+ def findTextInFile(self, log_file, **kwargs):
|
| |
+
|
| |
+ if kwargs is not None:
|
| |
+ with open (log_file, 'rt') as in_file:
|
| |
+ contents = in_file.read()
|
| |
+ for key in kwargs:
|
| |
+ self.assertRegex(contents, kwargs[key])
|
| |
+
|
| |
+ in_file.close()
|
| |
+
|
| |
+ def EnableIPForwarding(self):
|
| |
+
|
| |
+ with open('/proc/sys/net/ipv6/conf/veth-peer/forwarding', 'a') as the_file:
|
| |
+ the_file.write('1')
|
| |
+
|
| |
+ the_file.close()
|
| |
+
|
| |
+ def SetupVethInterface(self):
|
| |
+ """Setup veth interface"""
|
| |
+
|
| |
+ ip = IPRoute()
|
| |
+
|
| |
+ ip.link('add', ifname='veth-test', peer='veth-peer', kind='veth')
|
| |
+ idx_veth_test = ip.link_lookup(ifname='veth-test')[0]
|
| |
+ idx_veth_peer = ip.link_lookup(ifname='veth-peer')[0]
|
| |
+
|
| |
+ ip.link('set', index=idx_veth_test, address='02:01:02:03:04:08')
|
| |
+ ip.link('set', index=idx_veth_peer, address='02:01:02:03:04:09')
|
| |
+
|
| |
+ ip.link('set', index=idx_veth_test, state='up')
|
| |
+ ip.link('set', index=idx_veth_peer, state='up')
|
| |
+
|
| |
+ ip.close()
|
| |
+
|
| |
+ self.EnableIPForwarding()
|
| |
+
|
| |
+ time.sleep(10)
|
| |
+
|
| |
+ def TearDownVethInterface(self):
|
| |
+
|
| |
+ ip = IPRoute()
|
| |
+
|
| |
+ ip.link('del', index=ip.link_lookup(ifname='veth-test')[0])
|
| |
+ ip.close()
|
| |
+
|
| |
+ class LibNdpTests(unittest.TestCase, GenericUtilities):
|
| |
+
|
| |
+ def setUp(self):
|
| |
+ self.SetupVethInterface()
|
| |
+
|
| |
+ def tearDown(self):
|
| |
+ self.StopDaemon(RADVD_PID_FILE)
|
| |
+ self.TearDownVethInterface()
|
| |
+
|
| |
+ def test_ndptool_gets_default_router_preference(self):
|
| |
+ """ ndptool gets router preference """
|
| |
+
|
| |
+ self.StartRadvd()
|
| |
+
|
| |
+ time.sleep(10)
|
| |
+
|
| |
+ self.StartNDPTool()
|
| |
+
|
| |
+ time.sleep(30)
|
| |
+
|
| |
+ self.StopNDPTool()
|
| |
+
|
| |
+ self.findTextInFile(NDPTOOL_CI_LOG,
|
| |
+ router_pref='Default router preference: high')
|
| |
+
|
| |
+ def test_ndptool_gets_link_source_address(self):
|
| |
+ """ ndptool gets link source address """
|
| |
+
|
| |
+ self.StartRadvd()
|
| |
+
|
| |
+ time.sleep(10)
|
| |
+
|
| |
+ self.StartNDPTool()
|
| |
+
|
| |
+ time.sleep(30)
|
| |
+
|
| |
+ self.StopNDPTool()
|
| |
+
|
| |
+ self.findTextInFile(NDPTOOL_CI_LOG,
|
| |
+ source_link_addr='Source linkaddr: 02:01:02:03:04:09')
|
| |
+
|
| |
+ def test_ndptool_gets_lifetime(self):
|
| |
+ """ ndptool gets lifetime """
|
| |
+
|
| |
+ self.StartRadvd()
|
| |
+
|
| |
+ time.sleep(10)
|
| |
+
|
| |
+ self.StartNDPTool()
|
| |
+
|
| |
+ time.sleep(30)
|
| |
+
|
| |
+ self.StopNDPTool()
|
| |
+
|
| |
+ self.findTextInFile(NDPTOOL_CI_LOG,
|
| |
+ prefix='Prefix: 2001:db8:1::/64, valid_time: 30s, preferred_time: 30s',
|
| |
+ dns_lifetime='Recursive DNS Servers: 2001:db8::1, 2001:db8::2, lifetime: 15s',
|
| |
+ search_lifetime='DNS Search List: branch.example.com example.com, lifetime: 15s',
|
| |
+ router_lifetime='Router lifetime: 30s')
|
| |
+
|
| |
+ def test_ndptool_gets_mtu(self):
|
| |
+ """ ndptool gets MTU=1280 """
|
| |
+
|
| |
+ self.StartRadvd()
|
| |
+
|
| |
+ time.sleep(10)
|
| |
+
|
| |
+ self.StartNDPTool()
|
| |
+
|
| |
+ time.sleep(30)
|
| |
+
|
| |
+ self.StopNDPTool()
|
| |
+
|
| |
+ self.findTextInFile(NDPTOOL_CI_LOG,
|
| |
+ prefix='Prefix: 2001:db8:1::/64',
|
| |
+ mtu='MTU: 1280')
|
| |
+
|
| |
+ def test_ndptool_gets_rdnss_dnssl(self):
|
| |
+ """ ndptool gets the RDNSS DNSSL """
|
| |
+
|
| |
+ self.StartRadvd()
|
| |
+
|
| |
+ time.sleep(10)
|
| |
+
|
| |
+ self.StartNDPTool()
|
| |
+
|
| |
+ time.sleep(30)
|
| |
+
|
| |
+ self.StopNDPTool()
|
| |
+
|
| |
+ self.findTextInFile(NDPTOOL_CI_LOG,
|
| |
+ Prefix='Prefix: 2001:db8:1::/64',
|
| |
+ rdnss='Recursive DNS Servers: 2001:db8::1, 2001:db8::2',
|
| |
+ dnssl='DNS Search List: branch.example.com example.com')
|
| |
+
|
| |
+ def test_ndptool_gets_prefix(self):
|
| |
+
|
| |
+ self.StartRadvd()
|
| |
+
|
| |
+ time.sleep(10)
|
| |
+
|
| |
+ self.StartNDPTool()
|
| |
+ time.sleep(10)
|
| |
+ self.StopNDPTool()
|
| |
+
|
| |
+ self.findTextInFile(NDPTOOL_CI_LOG,
|
| |
+ prefix='Prefix: 2001:db8:1::/64')
|
| |
+
|
| |
+ if __name__ == '__main__':
|
| |
+ unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
|
| |
+ verbosity=3))
|
| |
Add tests according to the CI
justification
Adds tests according to the CI wiki specifically the standard test interface in the spec.
The playbook includes Tier1 level test cases that have been tested in the following contexts and
is passing reliably: Classic. Test logs are stored in the artifacts directory.
The following steps are used to execute the tests using the standard test interface:
Test environment
Make sure you have installed packages from the spec