From 226f96c94e76713f48ebdb114759584f0e1357e6 Mon Sep 17 00:00:00 2001 From: lguohan Date: Fri, 1 Dec 2017 20:06:57 -0800 Subject: [PATCH] refactor swss integration test (#404) --- tests/conftest.py | 115 ++++++++++++++++++++++++++++++++++++++++ tests/test_interface.py | 60 +++++++++++++++++++++ tests/test_port.py | 50 +++++++++++++++++ tests/test_route.py | 53 ++++++++++++++++++ tests/test_vs.py | 108 ------------------------------------- 5 files changed, 278 insertions(+), 108 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/test_interface.py create mode 100644 tests/test_port.py create mode 100644 tests/test_route.py delete mode 100644 tests/test_vs.py diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 000000000000..7fb5bed65fbf --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,115 @@ +import os +import re +import time +import docker +import pytest +import commands + +class VirtualServer(object): + def __init__(self, ctn_name, pid, i): + self.nsname = "%s_srv%d" % (ctn_name, i) + self.vifname = "vEthernet%d" % (i * 4) + + # create netns + os.system("ip netns add %s" % self.nsname) + + # create vpeer link + os.system("ip link add %s type veth peer name %s" % (self.nsname[0:12], self.vifname)) + os.system("ip link set %s netns %s" % (self.nsname[0:12], self.nsname)) + os.system("ip link set %s netns %d" % (self.vifname, pid)) + + # bring up link in the virtual server + os.system("ip netns exec %s ip link set dev %s name eth0" % (self.nsname, self.nsname[0:12])) + os.system("ip netns exec %s ip link set dev eth0 up" % (self.nsname)) + + # bring up link in the virtual switch + os.system("nsenter -t %d -n ip link set dev %s up" % (pid, self.vifname)) + + def __del__(self): + os.system("ip netns delete %s" % self.nsname) + + def runcmd(self, cmd): + os.system("ip netns exec %s %s" % (self.nsname, cmd)) + +class DockerVirtualSwitch(object): + def __init__(self): + self.name = "vs" + self.pnames = ['fpmsyncd', + 'intfmgrd', + 'intfsyncd', + 'neighsyncd', + 'orchagent', + 'portsyncd', + 'redis-server', + 'rsyslogd', + 'syncd', + 'teamsyncd', + 'vlanmgrd', + 'zebra'] + self.mount = "/var/run/redis-vs" + self.redis_sock = self.mount + '/' + "redis.sock" + self.client = docker.from_env() + self.ctn_sw = self.client.containers.run('debian:jessie', privileged=True, detach=True, + command="bash", stdin_open=True) + (status, output) = commands.getstatusoutput("docker inspect --format '{{.State.Pid}}' %s" % self.ctn_sw.name) + self.cnt_sw_pid = int(output) + self.servers = [] + for i in range(32): + server = VirtualServer(self.ctn_sw.name, self.cnt_sw_pid, i) + self.servers.append(server) + self.ctn = self.client.containers.run('docker-sonic-vs', privileged=True, detach=True, + network_mode="container:%s" % self.ctn_sw.name, + volumes={ self.mount: { 'bind': '/var/run/redis', 'mode': 'rw' } }) + + def destroy(self): + self.ctn.remove(force=True) + self.ctn_sw.remove(force=True) + for s in self.servers: + del(s) + + def ready(self, timeout=30): + '''check if all processes in the dvs is ready''' + + re_space = re.compile('\s+') + process_status = {} + ready = False + started = 0 + while True: + # get process status + out = self.ctn.exec_run("supervisorctl status") + for l in out.split('\n'): + fds = re_space.split(l) + if len(fds) < 2: + continue + process_status[fds[0]] = fds[1] + + # check if all processes are running + ready = True + for pname in self.pnames: + try: + if process_status[pname] != "RUNNING": + ready = False + except KeyError: + ready = False + + if ready == True: + break + + started += 1 + if started > timeout: + print out + raise + + time.sleep(1) + + def restart(self): + self.ctn.restart() + + def runcmd(self, cmd): + return self.ctn.exec_run(cmd) + +@pytest.yield_fixture(scope="module") +def dvs(): + dvs = DockerVirtualSwitch() + yield dvs + dvs.destroy() diff --git a/tests/test_interface.py b/tests/test_interface.py new file mode 100644 index 000000000000..a70daf51d5f5 --- /dev/null +++ b/tests/test_interface.py @@ -0,0 +1,60 @@ +from swsscommon import swsscommon +import time +import re +import json + +def parse_route_key(rt_key): + (otype, kstr) = rt_key.split(':', 1) + assert otype == "SAI_OBJECT_TYPE_ROUTE_ENTRY" + return json.loads(kstr) + +def test_InterfaceIpChange(dvs): + + dvs.restart() + + dvs.ready() + + dvs.runcmd("ifconfig Ethernet0 10.0.0.0/31 up") + + time.sleep(1) + + # check if route was propagated to ASIC DB + + db = swsscommon.DBConnector(1, dvs.redis_sock, 0) + + tbl = swsscommon.Table(db, "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY") + + keys = tbl.getKeys() + + for k in keys: + rt_key = parse_route_key(k) + + if rt_key['dest'] == "10.0.0.0/31": + subnet_found = True + + if rt_key['dest'] == "10.0.0.0/32": + ip2me_found = True + + assert subnet_found == True and ip2me_found == True + + subnet_found = False + ip2me_found = False + + dvs.runcmd("ifconfig Ethernet0 10.0.0.0/24 up") + + time.sleep(1) + + # check if route was propagated to ASIC DB + + keys = tbl.getKeys() + + for k in keys: + rt_key = parse_route_key(k) + + if rt_key['dest'] == "10.0.0.0/24": + subnet_found = True + + if rt_key['dest'] == "10.0.0.0/32": + ip2me_found = True + + assert subnet_found == True and ip2me_found == True diff --git a/tests/test_port.py b/tests/test_port.py new file mode 100644 index 000000000000..1fff6c9c8cbc --- /dev/null +++ b/tests/test_port.py @@ -0,0 +1,50 @@ +from swsscommon import swsscommon +import time +import os + +def test_PortNotification(dvs): + + dvs.restart() + + dvs.ready() + + dvs.runcmd("ifconfig Ethernet0 10.0.0.0/31 up") == 0 + dvs.runcmd("ifconfig Ethernet4 10.0.0.2/31 up") == 0 + + dvs.servers[0].runcmd("ip link set down dev eth0") == 0 + + time.sleep(1) + + db = swsscommon.DBConnector(0, dvs.redis_sock, 0) + + tbl = swsscommon.Table(db, "PORT_TABLE") + + (status, fvs) = tbl.get("Ethernet0") + + assert status == True + + oper_status = "unknown" + + for v in fvs: + if v[0] == "oper_status": + oper_status = v[1] + break + + assert oper_status == "down" + + dvs.servers[0].runcmd("ip link set up dev eth0") == 0 + + time.sleep(1) + + (status, fvs) = tbl.get("Ethernet0") + + assert status == True + + oper_status = "unknown" + + for v in fvs: + if v[0] == "oper_status": + oper_status = v[1] + break + + assert oper_status == "up" diff --git a/tests/test_route.py b/tests/test_route.py new file mode 100644 index 000000000000..9f9c055225a9 --- /dev/null +++ b/tests/test_route.py @@ -0,0 +1,53 @@ +from swsscommon import swsscommon +import os +import re +import time +import json + +def parse_route_key(rt_key): + (otype, kstr) = rt_key.split(':', 1) + assert otype == "SAI_OBJECT_TYPE_ROUTE_ENTRY" + return json.loads(kstr) + +def test_RouteAdd(dvs): + + dvs.restart() + + dvs.ready() + + dvs.runcmd("ifconfig Ethernet0 10.0.0.0/31 up") + dvs.runcmd("ifconfig Ethernet4 10.0.0.2/31 up") + + dvs.servers[0].runcmd("ifconfig eth0 10.0.0.1/31") + dvs.servers[0].runcmd("ip route add default via 10.0.0.0") + + dvs.servers[1].runcmd("ifconfig eth0 10.0.0.3/31") + dvs.servers[1].runcmd("ip route add default via 10.0.0.2") + + # get neighbor and arp entry + dvs.servers[0].runcmd("ping -c 1 10.0.0.3") + + db = swsscommon.DBConnector(0, dvs.redis_sock, 0) + ps = swsscommon.ProducerStateTable(db, "ROUTE_TABLE") + fvs = swsscommon.FieldValuePairs([("nexthop","10.0.0.1"), ("ifname", "Ethernet0")]) + + ps.set("2.2.2.0/24", fvs) + + time.sleep(1) + + # check if route was propagated to ASIC DB + + db = swsscommon.DBConnector(1, dvs.redis_sock, 0) + + tbl = swsscommon.Table(db, "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY") + + keys = tbl.getKeys() + + found_route = False + for k in keys: + rt_key = parse_route_key(k) + + if rt_key['dest'] == "2.2.2.0/24": + found_route = True + + assert found_route diff --git a/tests/test_vs.py b/tests/test_vs.py deleted file mode 100644 index f59216767ddb..000000000000 --- a/tests/test_vs.py +++ /dev/null @@ -1,108 +0,0 @@ -from swsscommon import swsscommon -import os -import re - -# run docker with command: -# docker run -v /var/run/redis-vs:/var/run/redis --privileged --network container:sw -d docker-sonic-vs -# run test: sudo python -c "import test_vs; test_vs.test_RouteAdd()" - -DOCKER_NAME = "vs" -HOST_REDIS_SOCKET = "/var/run/redis-vs/redis.sock" - -def test_RouteAdd(): - - # bring up interfaces that will be in use - - assert os.system("docker exec -i " + DOCKER_NAME + " ifconfig Ethernet0 10.0.0.0/31 up") == 0 - assert os.system("docker exec -i " + DOCKER_NAME + " ifconfig Ethernet4 10.0.0.2/31 up") == 0 - - assert os.system("ip netns exec sw-srv0 ifconfig eth0 10.0.0.1/31") == 0 - os.system("ip netns exec sw-srv0 ip route add default via 10.0.0.0") == 0 - - assert os.system("ip netns exec sw-srv1 ifconfig eth0 10.0.0.3/31") == 0 - os.system("ip netns exec sw-srv1 ip route add default via 10.0.0.2") == 0 - - # get neighbor and arp entry - assert os.system("ip netns exec sw-srv0 ping -c 1 10.0.0.3") == 0 - - db = swsscommon.DBConnector(0, HOST_REDIS_SOCKET, 0) - ps = swsscommon.ProducerStateTable(db, "ROUTE_TABLE") - fvs = swsscommon.FieldValuePairs([("nexthop","10.0.0.1"), ("ifname", "Ethernet0")]) - - ps.set("2.2.2.0/24", fvs) - - os.system("sleep 1") - - # check if route was propagated to ASIC DB - - db = swsscommon.DBConnector(1, HOST_REDIS_SOCKET, 0) - - tbl = swsscommon.Table(db, "ASIC_STATE:SAI_OBJECT_TYPE_ROUTE_ENTRY") - - keys = tbl.getKeys() - - for k in keys: - - if bool(re.search('{"dest":"2.2.2.0/24"', k)): - - print "PASSED" - return - - print "FAILED - route not found in ASIC db" - assert 1 == 0 - -def test_PortNotification(): - - # bring up interfaces that will be in use - - assert os.system("docker exec -i " + DOCKER_NAME + " ifconfig Ethernet0 10.0.0.0/31 up") == 0 - assert os.system("docker exec -i " + DOCKER_NAME + " ifconfig Ethernet4 10.0.0.2/31 up") == 0 - - assert os.system("ip netns exec sw-srv0 ifconfig eth0 10.0.0.1/31") == 0 - os.system("ip netns exec sw-srv0 ip route add default via 10.0.0.0") == 0 - - assert os.system("ip netns exec sw-srv1 ifconfig eth0 10.0.0.3/31") == 0 - os.system("ip netns exec sw-srv1 ip route add default via 10.0.0.2") == 0 - - # get neighbor and arp entry - assert os.system("ip netns exec sw-srv0 ping -c 1 10.0.0.3") == 0 - - assert os.system("ip netns exec sw-srv0 ip link set down dev eth0") == 0 - - os.system("sleep 1") - - db = swsscommon.DBConnector(0, HOST_REDIS_SOCKET, 0) - - tbl = swsscommon.Table(db, "PORT_TABLE") - - (status, fvs) = tbl.get("Ethernet0") - - assert status == True - - oper_status = "unknown" - - for v in fvs: - if v[0] == "oper_status": - oper_status = v[1] - break - - assert oper_status == "down" - - assert os.system("ip netns exec sw-srv0 ip link set up dev eth0") == 0 - - os.system("sleep 1") - - (status, fvs) = tbl.get("Ethernet0") - - assert status == True - - oper_status = "unknown" - - for v in fvs: - if v[0] == "oper_status": - oper_status = v[1] - break - - assert oper_status == "up" - - print "PASSED"