diff options
author | Rabi Shanker Guha <guha.rabishankar@gmail.com> | 2015-01-09 20:39:51 +0530 |
---|---|---|
committer | Rabi Shanker Guha <guha.rabishankar@gmail.com> | 2015-01-09 20:39:51 +0530 |
commit | 2a6d218d97858342eae3266798085d95c3d31c83 (patch) | |
tree | 45d2c198bb1c7707caf697deced439ad7eaad98d /test | |
parent | Update Makefiles to reflect changes (diff) | |
download | netifrc-2a6d218d97858342eae3266798085d95c3d31c83.tar.gz netifrc-2a6d218d97858342eae3266798085d95c3d31c83.tar.bz2 netifrc-2a6d218d97858342eae3266798085d95c3d31c83.zip |
Test Suite
Run it using
sudo python3 test/src/netifrc.py test/specs/config.yaml
to generate the test output
and
sudo MODE=slave python3 test/src/netifrc.py test/specs/config.yaml
to match the output on a system-system against the output generated
on the previous openrc system
Diffstat (limited to 'test')
-rw-r--r-- | test/conf.d/bond | 9 | ||||
-rw-r--r-- | test/conf.d/bridge | 9 | ||||
-rw-r--r-- | test/conf.d/eth_dhcp | 1 | ||||
-rw-r--r-- | test/conf.d/eth_static | 2 | ||||
-rw-r--r-- | test/conf.d/vlan | 3 | ||||
-rw-r--r-- | test/config.ini | 28 | ||||
-rw-r--r-- | test/requirements.txt | 2 | ||||
-rw-r--r-- | test/specs/bond.yaml | 23 | ||||
-rw-r--r-- | test/specs/bridge.yaml | 11 | ||||
-rw-r--r-- | test/specs/eth_dhcp.yaml | 14 | ||||
-rw-r--r-- | test/specs/eth_static.yaml | 14 | ||||
-rw-r--r-- | test/specs/vlan.yaml | 11 | ||||
-rw-r--r-- | test/src/file.py | 21 | ||||
-rwxr-xr-x | test/src/netifrc.py | 227 |
14 files changed, 375 insertions, 0 deletions
diff --git a/test/conf.d/bond b/test/conf.d/bond new file mode 100644 index 0000000..49bbb24 --- /dev/null +++ b/test/conf.d/bond @@ -0,0 +1,9 @@ +# Bonded Interface Configuration +#config_$$BOND_IFACE_1$$="null" +#config_$$BOND_IFACE_2$$="null" + +slaves_$$BOND$$="$$BOND_IFACE_1$$ $$BOND_IFACE_2$$" +config_$$BOND$$="null" +# config_$$BOND$$="192.168.1.100" +# routes_$$BOND$$="default via 192.168.1.1" +rc_net_$$BOND$$_need="net.$$BOND_IFACE_1$$ net.$$BOND_IFACE_2$$" diff --git a/test/conf.d/bridge b/test/conf.d/bridge new file mode 100644 index 0000000..d49455b --- /dev/null +++ b/test/conf.d/bridge @@ -0,0 +1,9 @@ +config_$$BRIDGE_IFACE_1$$="null" +config_$$BRIDGE_IFACE_2$$="null" + +# bridge +config_$$BRIDGE$$="dhcp" +brctl_$$BRIDGE$$="setfd 0 +sethello 10 +stp off" +bridge_$$BRIDGE$$="$$BRIDGE_IFACE_1$$ $$BRIDGE_IFACE_2$$"
\ No newline at end of file diff --git a/test/conf.d/eth_dhcp b/test/conf.d/eth_dhcp new file mode 100644 index 0000000..4d97c5f --- /dev/null +++ b/test/conf.d/eth_dhcp @@ -0,0 +1 @@ +config_$$WIRED$$="dhcp" diff --git a/test/conf.d/eth_static b/test/conf.d/eth_static new file mode 100644 index 0000000..cc0fb23 --- /dev/null +++ b/test/conf.d/eth_static @@ -0,0 +1,2 @@ +config_$$WIRED$$="172.27.3.82/21" +routes_$$WIRED$$="default via 172.27.7.254" diff --git a/test/conf.d/vlan b/test/conf.d/vlan new file mode 100644 index 0000000..8d6a936 --- /dev/null +++ b/test/conf.d/vlan @@ -0,0 +1,3 @@ +vlans_$$VLAN_IFACE_1$$="1" +config_$$VLAN_IFACE_1$$="null" +config_$$VLAN_IFACE_1$$_1="192.168.2.1/24"
\ No newline at end of file diff --git a/test/config.ini b/test/config.ini new file mode 100644 index 0000000..286adb3 --- /dev/null +++ b/test/config.ini @@ -0,0 +1,28 @@ +[GLOBALS] +MODE_MASTER = master +MODE_SLAVE = slave +CONFIG_FILE = /etc/conf.d/net +CONFIG_FILE_BACKUP = /etc/conf.d/net.backup +DELAY = 5 +TIMEOUT = 5 + +[FILE] +KEYSTORE = /tmp/netifrc_test.py + +[SPECS] +DUMMY = dummy0 +WIRED = eth0 +WIRELESS = wlp3s0 + +# [BONDING] +BOND = bond0 +BOND_IFACE_1 = %(WIRED)s +BOND_IFACE_2 = %(DUMMY)s + +# [VLan] +VLAN_IFACE_1 = %(WIRED)s + +# [Bridge] +BRIDGE = br0 +BRIDGE_IFACE_1 = %(WIRED)s +BRIDGE_IFACE_2 = %(DUMMY)s diff --git a/test/requirements.txt b/test/requirements.txt new file mode 100644 index 0000000..f5a24b9 --- /dev/null +++ b/test/requirements.txt @@ -0,0 +1,2 @@ +pyyaml +termcolor diff --git a/test/specs/bond.yaml b/test/specs/bond.yaml new file mode 100644 index 0000000..46bc312 --- /dev/null +++ b/test/specs/bond.yaml @@ -0,0 +1,23 @@ +name: Bond Test Suite +description: Test to check the functioning of net.bond0 +net_config: conf.d/bond +interface: $$BOND$$ +tests: + - name: Check Bond Interface + command: ifconfig $$BOND$$ + keys: + - name: status + type: boolean + value: grep -q UP + - name: IP + value: "grep 'inet ' | sed -e 's/^[ \t]*//' | cut -d ' ' -f2" + match: "r'\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b'" + - name: "Check /proc/net file" + command: "cat /proc/net/bonding/$$BOND$$" + keys: + - name: Slave $$BOND_IFACE_1$$ status + type: boolean + value: "grep -A 1 'Slave Interface: $$BOND_IFACE_1$$' | grep Status | grep -q -i up" + - name: Slave $$BOND_IFACE_2$$ status + type: boolean + value: "grep -A 1 'Slave Interface: $$BOND_IFACE_2$$' | grep Status | grep -q -i up"
\ No newline at end of file diff --git a/test/specs/bridge.yaml b/test/specs/bridge.yaml new file mode 100644 index 0000000..681bbda --- /dev/null +++ b/test/specs/bridge.yaml @@ -0,0 +1,11 @@ +name: Bridge Test Suite +description: Test to check the functioning of Bridge +net_config: conf.d/bridge +interface: $$BRIDGE$$ +tests: + - name: Check Bridged Interfaces + command: brctl show + keys: + - name: Bridge $$BRIDGE$$ status + type: boolean + value: grep -q $$BRIDGE$$
\ No newline at end of file diff --git a/test/specs/eth_dhcp.yaml b/test/specs/eth_dhcp.yaml new file mode 100644 index 0000000..ed67cc7 --- /dev/null +++ b/test/specs/eth_dhcp.yaml @@ -0,0 +1,14 @@ +name: DHCP +description: A battery of tests to check the correction functioning of static +net_config: conf.d/eth_dhcp +interface: $$WIRED$$ +tests: + - name: Check DHCP + command: ifconfig $$WIRED$$ + keys: + - name: status + type: boolean + value: grep -q UP + - name: IP + value: "grep 'inet ' | sed -e 's/^[ \t]*//' | cut -d ' ' -f2" + match: "r'\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b'" diff --git a/test/specs/eth_static.yaml b/test/specs/eth_static.yaml new file mode 100644 index 0000000..5b6ea25 --- /dev/null +++ b/test/specs/eth_static.yaml @@ -0,0 +1,14 @@ +name: Static Ethernet Test Suite +description: A battery of tests to check the correction functioning of static net.eth0 +net_config: conf.d/eth_static +interface: $$WIRED$$ +tests: + - name: Check DHCP + command: ifconfig $$WIRED$$ + keys: + - name: status + type: boolean + value: grep -q UP + - name: IP + value: "grep 'inet ' | sed -e 's/^[ \t]*//' | cut -d ' ' -f2" + match: "r'\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b'" diff --git a/test/specs/vlan.yaml b/test/specs/vlan.yaml new file mode 100644 index 0000000..83eb66d --- /dev/null +++ b/test/specs/vlan.yaml @@ -0,0 +1,11 @@ +name: Vlan Test Suite +description: Test to check the functioning of Virtual LAN +net_config: conf.d/vlan +interface: $$VLAN_IFACE_1$$ +tests: + - name: Check Bond Interface + command: ip -d link show $$VLAN_IFACE_1$$.1 + keys: + - name: vlan status + type: boolean + value: grep -q vlan
\ No newline at end of file diff --git a/test/src/file.py b/test/src/file.py new file mode 100644 index 0000000..e1e6ed8 --- /dev/null +++ b/test/src/file.py @@ -0,0 +1,21 @@ +import configparser +import os + +BASEDIR = os.path.normpath(os.path.join(os.path.dirname(__file__), os.pardir)) + +_config = configparser.ConfigParser() +_config.read(os.path.join(BASEDIR, 'config.ini')) +config = _config['FILE'] + + +def save(key, value): + with open(config['KEYSTORE'], "a") as keystore: + keystore.write("{} = {}\n".format(key, value)) + + +def fetch(key): + with open(config['KEYSTORE'], "r") as keystore: + for line in keystore: + if(line.startswith(key + " = ")): + val = line[line.index("=")+2:] + return val.strip() diff --git a/test/src/netifrc.py b/test/src/netifrc.py new file mode 100755 index 0000000..8840583 --- /dev/null +++ b/test/src/netifrc.py @@ -0,0 +1,227 @@ +#!/usr/bin/python3 + +import configparser +import os +import re +import sys +import subprocess +from termcolor import colored +import time +from yaml import load as yamlLoad + +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + + +BASEDIR = os.path.normpath(os.path.join(os.path.dirname(__file__), os.pardir)) + +config = configparser.ConfigParser() +config.read(os.path.join(BASEDIR, 'config.ini')) +defaults = config['GLOBALS'] + +from file import save as backend_save, fetch as backend_retrieve + + +def get_mode(): + if(os.path.exists("/var/run/openrc")): + return defaults['MODE_MASTER'] + return defaults['MODE_SLAVE'] + + +def normalize(*args): + return '_'.join(''.join(c for c in arg if c.isalnum()) for arg in args) + + +def _service_call(iface, command): + if(os.path.exists("/var/run/openrc")): + subprocess.check_call(["rc-service", "net."+iface, command]) + elif(os.path.exists("/run/systemd")): + subprocess.check_call(["systemctl", command, "net@"+iface]) + + +def stop_iface(iface): + _service_call(iface, "stop") + + +def start_iface(iface): + _service_call(iface, "start") + + +def restart_iface(iface): + _service_call(iface, "restart") + + +def init(data): + print(colored("Backing up {}".format(defaults['CONFIG_FILE']), + "yellow")) + try: + if(os.path.isfile(defaults['CONFIG_FILE'])): + subprocess.check_call(["mv", defaults['CONFIG_FILE'], + defaults['CONFIG_FILE_BACKUP']]) + + except subprocess.CalledProcessError: + print("Could not backup Config File") + sys.exit(1) + + with open(BASEDIR + "/" + data['net_config'], 'r') as current_config_file: + current_config = current_config_file.read() + # Replace with the variables defined in SPECS + for var in config['SPECS']: + current_config = current_config.replace( + "$${}$$".format(var.upper()), + config['SPECS'][var]) + + with open(defaults['CONFIG_FILE'], 'w') as config_file: + config_file.write(current_config) + + try: + restart_iface(data['interface']) + except subprocess.CalledProcessError: + print("Could not effectively start interface "+data['interface']) + sys.exit(1) + else: + time.sleep(float(defaults['DELAY'])) + +def finalize(data): + print(colored("Restoring {}".format(defaults['CONFIG_FILE']), + 'yellow')) + try: + subprocess.check_call(["mv", + defaults['CONFIG_FILE_BACKUP'], + defaults['CONFIG_FILE']]) + except subprocess.CalledProcessError: + print("Could not Restore Config File") + sys.exit(1) + + try: + stop_iface(data['interface']) + except subprocess.CalledProcessError: + print("Could not effectively stop interface " + data['interface']) + sys.exit(1) + + +def failure(value, backend_value): + print(colored("[ FAIL ]", 'red')) + err = " Backend value {} does not match {}" + print(colored(err.format(backend_value, value), + 'red')) + sys.exit(1) + + +def success(value, backend_value): + print(colored("[ PASS ]", 'green')) + + +def test(data, mode): + print(colored(data['name'], 'green')) + for test in data['tests']: + command = subprocess.Popen(test['command'], stdout=subprocess.PIPE, + shell=True) + try: + command.wait(float(defaults['TIMEOUT'])) + if(command.returncode != 0): + raise subprocess.CalledProcessError( + command.returncode, test['command']) + (out, err) = command.communicate(timeout=int(defaults['TIMEOUT'])) + + except subprocess.TimeoutExpired: + print(colored("Command {} Expired".format(test['command']), 'red')) + command.kill() + command.communicate() + except subprocess.CalledProcessError as err: + print(colored(" {}: {}".format(test['name'], test['command']), + 'red')) + + else: + print(colored(" {}: {}".format(test['name'], test['command']), + 'green')) + for key in test['keys']: + print(colored(" Extracting {}:".format(key['name']), + 'green'), end=" ", flush=True) + key_command = subprocess.Popen(key['value'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + shell=True) + try: + (stdout, stderr) = key_command.communicate( + input=out, + timeout=int(defaults['TIMEOUT'])) + + except subprocess.TimeoutExpired: + print(colored("Trying to find the value of {} timed out" + .format(key['name']), 'red')) + key_command.kill() + key_command.communicate() + except subprocess.CalledProcessError as err: + print(colored("Command failed: " + err.cmd, 'red')) + + else: + if('type' in key and key['type'] == "boolean"): + value = str(key_command.returncode) + else: + value = stdout.decode("utf-8").strip() + + if('match' in key): + if(key['match'][0] == 'r'): + match = re.match(key['match'][2:-1], value) + if(match is None): + failure(value, key['match']) + else: + try: + assert value == key['match'] + except AssertionError: + failure(value, key['match']) + + print(colored(value, 'green'), end=" ", flush=True) + + if(mode == defaults['MODE_MASTER']): + backend_save(normalize(data['name'], + test['name'], + key['name']), value) + print() + else: + backend_value = backend_retrieve( + normalize(data['name'], test['name'], key['name'])) + + if(backend_value[0] == 'r'): + match = re.match(backend_value[2:-1], value) + if(match is None): + failure(value, backend_value) + else: + success(value, backend_value) + else: + try: + assert value == backend_value + except AssertionError: + failure(value, backend_value) + else: + success(value, backend_value) + + +for file in sys.argv[1:]: + with open(file, 'r') as f: + document = f.read() + + # Replace with the variables defined in SPECS + for var in config['SPECS']: + document = document.replace("$${}$$".format(var.upper()), + config['SPECS'][var]) + + # Parse the yaml file + data = yamlLoad(document, Loader=Loader) + + try: + mode = os.environ['MODE'] + except KeyError: + mode = "" + + if(mode != defaults['MODE_MASTER'] and mode != defaults['MODE_SLAVE']): + mode = get_mode() + + try: + init(data) + test(data, mode=mode) + finally: + finalize(data) |