aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorRabi Shanker Guha <guha.rabishankar@gmail.com>2015-01-09 20:39:51 +0530
committerRabi Shanker Guha <guha.rabishankar@gmail.com>2015-01-09 20:39:51 +0530
commit2a6d218d97858342eae3266798085d95c3d31c83 (patch)
tree45d2c198bb1c7707caf697deced439ad7eaad98d /test
parentUpdate Makefiles to reflect changes (diff)
downloadnetifrc-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/bond9
-rw-r--r--test/conf.d/bridge9
-rw-r--r--test/conf.d/eth_dhcp1
-rw-r--r--test/conf.d/eth_static2
-rw-r--r--test/conf.d/vlan3
-rw-r--r--test/config.ini28
-rw-r--r--test/requirements.txt2
-rw-r--r--test/specs/bond.yaml23
-rw-r--r--test/specs/bridge.yaml11
-rw-r--r--test/specs/eth_dhcp.yaml14
-rw-r--r--test/specs/eth_static.yaml14
-rw-r--r--test/specs/vlan.yaml11
-rw-r--r--test/src/file.py21
-rwxr-xr-xtest/src/netifrc.py227
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)