Skip to content

Commit

Permalink
[tests]: add README, vlan, acl tests (sonic-net#405)
Browse files Browse the repository at this point in the history
* [test]: add --dvsname option to specify the dvs container

* [test]: add test vlan member creation test

* [test]: add acl test

* [test]: add README.md
  • Loading branch information
lguohan authored Dec 4, 2017
1 parent 226f96c commit 26ddada
Show file tree
Hide file tree
Showing 8 changed files with 398 additions and 59 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*.la
*.lo
*.o
*.pyc

# Packaging Files #
###################
Expand Down
54 changes: 54 additions & 0 deletions tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
SWSS Integration Tests

# Introduction

SWSS Integration tests runs on docker-sonic-vs which runs on top of SAI virtual switch. The tests can be run on any Linux machine without real switch ASIC. It is used to test SwSS (Switch State Service) by setting AppDB or ConfigDB and checking corresponding AsicDB entries.

# How to run the tests

- Install docker and pytest on your dev machine
```
sudo pip install --system docker==2.6.1
sudo pip install --system pytest==3.3.0
```
- Compile and install swss common library
````
cd sonic-swss-common
dpkg-buildpackage -us -uc -b
dpkg -i ../libswsscommon_1.0.0_amd64.deb
dpkg -i ../python-swsscommon_1.0.0_amd64.deb
```
- Build and load docker-sonic-vs
```
cd sonic-buildimage
make configure PLATFORM=vs
make all
docker load < target/docker-sonic-vs.gz
```
- Run tests
```
cd sonic-swss/tests
sudo pytest -v
```
# How to setup test development env
To develop new swss features or swss integration tests, you need to setup a virtual switch docker container which
persists.
- Create virtual switch container (name:vs). ```create_vnet.sh``` can be found at [here](https://github.com/Azure/sonic-buildimage/blob/master/platform/vs/create_vnet.sh).
```
docker run -id --name sw debian bash
sudo ./create_vnet.sh sw
docker run --privileged -v /var/run/redis-vs:/var/run/redis --network container:sw -d --name vs docker-sonic-vs
```
- Run test using the existing vs container
```
sudo pytest -v --dvsname=vs
```
163 changes: 129 additions & 34 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,90 @@
import docker
import pytest
import commands
from swsscommon import swsscommon

def pytest_addoption(parser):
parser.addoption("--dvsname", action="store", default=None,
help="dvs name")

class AsicDbValidator(object):
def __init__(self, dvs):
self.adb = swsscommon.DBConnector(1, dvs.redis_sock, 0)

# get default dot1q vlan id
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_VLAN")

keys = atbl.getKeys()
assert len(keys) == 1
self.default_vlan_id = keys[0]

# build port oid to front port name mapping
self.portoidmap = {}
self.portnamemap = {}
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_HOSTIF")
keys = atbl.getKeys()

assert len(keys) == 32
for k in keys:
(status, fvs) = atbl.get(k)

assert status == True

for fv in fvs:
if fv[0] == "SAI_HOSTIF_ATTR_OBJ_ID":
port_oid = fv[1]
elif fv[0] == "SAI_HOSTIF_ATTR_NAME":
port_name = fv[1]

self.portoidmap[port_oid] = port_name
self.portnamemap[port_name] = port_oid

# get default acl table and acl rules
atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_TABLE")
keys = atbl.getKeys()

assert len(keys) == 1
self.default_acl_table = keys[0]

atbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY")
keys = atbl.getKeys()

assert len(keys) == 2
self.default_acl_entries = keys

class VirtualServer(object):
def __init__(self, ctn_name, pid, i):
self.nsname = "%s_srv%d" % (ctn_name, i)
self.nsname = "%s-srv%d" % (ctn_name, i)
self.vifname = "vEthernet%d" % (i * 4)
self.cleanup = True

# create netns
os.system("ip netns add %s" % self.nsname)
if os.path.exists("/var/run/netns/%s" % self.nsname):
self.cleanup = False
else:
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))
# 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 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))
# 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)
if self.cleanup:
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"
def __init__(self, name=None):
self.pnames = ['fpmsyncd',
'intfmgrd',
'intfsyncd',
Expand All @@ -49,25 +103,63 @@ def __init__(self):
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' } })

self.ctn = None
self.cleanup = True
if name != None:
# get virtual switch container
for ctn in self.client.containers.list():
if ctn.name == name:
self.ctn = ctn
(status, output) = commands.getstatusoutput("docker inspect --format '{{.HostConfig.NetworkMode}}' %s" % name)
cnt_sw_id = output.split(':')[1]
self.cleanup = False
if self.ctn == None:
raise NameError("cannot find container %s" % name)

# get base container
for ctn in self.client.containers.list():
if ctn.id == cnt_sw_id:
cnt_sw_name = ctn.name

(status, output) = commands.getstatusoutput("docker inspect --format '{{.State.Pid}}' %s" % cnt_sw_name)
self.cnt_sw_pid = int(output)

# create virtual servers
self.servers = []
for i in range(32):
server = VirtualServer(cnt_sw_name, self.cnt_sw_pid, i)
self.servers.append(server)

self.restart()
else:
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)

# create virtual server
self.servers = []
for i in range(32):
server = VirtualServer(self.ctn_sw.name, self.cnt_sw_pid, i)
self.servers.append(server)

# create virtual switch container
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' } })

self.check_ready()
self.init_asicdb_validator()

def destroy(self):
self.ctn.remove(force=True)
self.ctn_sw.remove(force=True)
for s in self.servers:
del(s)
if self.cleanup:
self.ctn.remove(force=True)
self.ctn_sw.remove(force=True)
for s in self.servers:
del(s)

def ready(self, timeout=30):
def check_ready(self, timeout=30):
'''check if all processes in the dvs is ready'''

re_space = re.compile('\s+')
Expand Down Expand Up @@ -97,19 +189,22 @@ def ready(self, timeout=30):

started += 1
if started > timeout:
print out
raise
raise ValueError(out)

time.sleep(1)

def restart(self):
self.ctn.restart()

def init_asicdb_validator(self):
self.asicdb = AsicDbValidator(self)

def runcmd(self, cmd):
return self.ctn.exec_run(cmd)

@pytest.yield_fixture(scope="module")
def dvs():
dvs = DockerVirtualSwitch()
def dvs(request):
name = request.config.getoption("--dvsname")
dvs = DockerVirtualSwitch(name)
yield dvs
dvs.destroy()
Loading

0 comments on commit 26ddada

Please sign in to comment.