Skip to content

Commit d23924f

Browse files
authored
[gearbox] Add gearbox unit test (#1920)
* Add test_gearbox * Add DVS_ENV for module specific dvs env variables
1 parent 3249cdb commit d23924f

File tree

4 files changed

+162
-21
lines changed

4 files changed

+162
-21
lines changed

tests/conftest.py

+17-19
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ def __init__(
244244
name: str = None,
245245
imgname: str = None,
246246
keeptb: bool = False,
247-
fakeplatform: str = None,
247+
env: list = [],
248248
log_path: str = None,
249249
max_cpu: int = 2,
250250
forcedvs: bool = None,
@@ -356,8 +356,6 @@ def __init__(
356356
self.mount = f"/var/run/redis-vs/{self.ctn_sw.name}"
357357
ensure_system(f"mkdir -p {self.mount}")
358358

359-
self.environment = [f"fake_platform={fakeplatform}"] if fakeplatform else []
360-
361359
kwargs = {}
362360
if newctnname:
363361
kwargs["name"] = newctnname
@@ -372,7 +370,7 @@ def __init__(
372370
self.ctn = self.client.containers.run(imgname,
373371
privileged=True,
374372
detach=True,
375-
environment=self.environment,
373+
environment=env,
376374
network_mode=f"container:{self.ctn_sw.name}",
377375
cpu_count=max_cpu,
378376
**kwargs)
@@ -1235,7 +1233,7 @@ def __init__(
12351233
namespace=None,
12361234
imgname=None,
12371235
keeptb=False,
1238-
fakeplatform=None,
1236+
env=[],
12391237
log_path=None,
12401238
max_cpu=2,
12411239
forcedvs=None,
@@ -1244,7 +1242,7 @@ def __init__(
12441242
self.ns = namespace
12451243
self.chassbr = "br4chs"
12461244
self.keeptb = keeptb
1247-
self.fakeplatform = fakeplatform
1245+
self.env = env
12481246
self.topoFile = topoFile
12491247
self.imgname = imgname
12501248
self.ctninfo = {}
@@ -1303,7 +1301,7 @@ def find_all_ctns(self):
13031301
for ctn in docker.from_env().containers.list():
13041302
if ctn.name.endswith(suffix):
13051303
self.dvss[ctn.name] = DockerVirtualSwitch(ctn.name, self.imgname, self.keeptb,
1306-
self.fakeplatform, log_path=ctn.name,
1304+
self.env, log_path=ctn.name,
13071305
max_cpu=self.max_cpu, forcedvs=self.forcedvs,
13081306
vct=self)
13091307
if self.chassbr is None and len(self.dvss) > 0:
@@ -1421,7 +1419,7 @@ def create_vct_ctn(self, ctndir):
14211419
if ctnname not in self.dvss:
14221420
self.dvss[ctnname] = DockerVirtualSwitch(name=None, imgname=self.imgname,
14231421
keeptb=self.keeptb,
1424-
fakeplatform=self.fakeplatform,
1422+
env=self.env,
14251423
log_path=self.log_path,
14261424
max_cpu=self.max_cpu,
14271425
forcedvs=self.forcedvs,
@@ -1598,18 +1596,18 @@ def manage_dvs(request) -> str:
15981596
buffer_model = request.config.getoption("--buffer_model")
15991597
force_recreate = request.config.getoption("--force-recreate-dvs")
16001598
dvs = None
1601-
curr_fake_platform = None # lgtm[py/unused-local-variable]
1599+
curr_dvs_env = [] # lgtm[py/unused-local-variable]
16021600

16031601
if using_persistent_dvs and force_recreate:
16041602
pytest.fail("Options --dvsname and --force-recreate-dvs are mutually exclusive")
16051603

1606-
def update_dvs(log_path, new_fake_platform=None):
1604+
def update_dvs(log_path, new_dvs_env=[]):
16071605
"""
16081606
Decides whether or not to create a new DVS
16091607
16101608
Create a new the DVS in the following cases:
16111609
1. CLI option `--force-recreate-dvs` was specified (recreate for every module)
1612-
2. The fake_platform has changed (this can only be set at container creation,
1610+
2. The dvs_env has changed (this can only be set at container creation,
16131611
so it is necessary to spin up a new DVS)
16141612
3. No DVS currently exists (i.e. first time startup)
16151613
@@ -1618,18 +1616,18 @@ def update_dvs(log_path, new_fake_platform=None):
16181616
Returns:
16191617
(DockerVirtualSwitch) a DVS object
16201618
"""
1621-
nonlocal curr_fake_platform, dvs
1619+
nonlocal curr_dvs_env, dvs
16221620
if force_recreate or \
1623-
new_fake_platform != curr_fake_platform or \
1621+
new_dvs_env != curr_dvs_env or \
16241622
dvs is None:
16251623

16261624
if dvs is not None:
16271625
dvs.get_logs()
16281626
dvs.destroy()
16291627

1630-
dvs = DockerVirtualSwitch(name, imgname, keeptb, new_fake_platform, log_path, max_cpu, forcedvs, buffer_model = buffer_model)
1628+
dvs = DockerVirtualSwitch(name, imgname, keeptb, new_dvs_env, log_path, max_cpu, forcedvs, buffer_model = buffer_model)
16311629

1632-
curr_fake_platform = new_fake_platform
1630+
curr_dvs_env = new_dvs_env
16331631

16341632
else:
16351633
# First generate GCDA files for GCov
@@ -1654,11 +1652,11 @@ def update_dvs(log_path, new_fake_platform=None):
16541652

16551653
@pytest.yield_fixture(scope="module")
16561654
def dvs(request, manage_dvs) -> DockerVirtualSwitch:
1657-
fakeplatform = getattr(request.module, "DVS_FAKE_PLATFORM", None)
1655+
dvs_env = getattr(request.module, "DVS_ENV", [])
16581656
name = request.config.getoption("--dvsname")
16591657
log_path = name if name else request.module.__name__
16601658

1661-
return manage_dvs(log_path, fakeplatform)
1659+
return manage_dvs(log_path, dvs_env)
16621660

16631661
@pytest.yield_fixture(scope="module")
16641662
def vct(request):
@@ -1669,11 +1667,11 @@ def vct(request):
16691667
imgname = request.config.getoption("--imgname")
16701668
max_cpu = request.config.getoption("--max_cpu")
16711669
log_path = vctns if vctns else request.module.__name__
1672-
fakeplatform = getattr(request.module, "DVS_FAKE_PLATFORM", None)
1670+
dvs_env = getattr(request.module, "DVS_ENV", [])
16731671
if not topo:
16741672
# use ecmp topology as default
16751673
topo = "virtual_chassis/chassis_with_ecmp_neighbors.json"
1676-
vct = DockerVirtualChassisTopology(vctns, imgname, keeptb, fakeplatform, log_path, max_cpu,
1674+
vct = DockerVirtualChassisTopology(vctns, imgname, keeptb, dvs_env, log_path, max_cpu,
16771675
forcedvs, topo)
16781676
yield vct
16791677
vct.get_logs(request.module.__name__)

tests/test_gearbox.py

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
# This test suite covers the functionality of gearbox feature
2+
import time
3+
import os
4+
import pytest
5+
from swsscommon import swsscommon
6+
from dvslib.dvs_database import DVSDatabase
7+
from dvslib.dvs_common import PollingConfig, wait_for_result
8+
9+
# module specific dvs env variables
10+
DVS_ENV = ["HWSKU=brcm_gearbox_vs"]
11+
12+
class Gearbox(object):
13+
def __init__(self, dvs):
14+
db = swsscommon.DBConnector(swsscommon.APPL_DB, dvs.redis_sock, 0)
15+
t = swsscommon.Table(db, "_GEARBOX_TABLE")
16+
assert len(t.getKeys()) > 0
17+
sr = t.getTableNameSeparator()
18+
19+
# "_GEARBOX_TABLE:phy:1"
20+
# "_GEARBOX_TABLE:phy:1:ports:0"
21+
# "_GEARBOX_TABLE:phy:1:lanes:200"
22+
self.phys = {}
23+
phy_table = swsscommon.Table(db, sr.join([t.getKeyName(""), "phy"]))
24+
for i in [x for x in phy_table.getKeys() if sr not in x]:
25+
(status, fvs) = phy_table.get(i)
26+
assert status == True
27+
self.phys[i] = {"attrs" : dict(fvs)}
28+
29+
port_table = swsscommon.Table(db, sr.join([phy_table.getKeyName(i), "ports"]))
30+
port_list = [x for x in port_table.getKeys() if sr not in x]
31+
self.phys[i]["port_table"] = port_table
32+
self.phys[i]["ports"] = {}
33+
for j in port_list:
34+
(status, fvs) = port_table.get(j)
35+
assert status == True
36+
self.phys[i]["ports"][j] = dict(fvs)
37+
38+
lane_table = swsscommon.Table(db, sr.join([phy_table.getKeyName(i), "lanes"]))
39+
lane_list = [x for x in lane_table.getKeys() if sr not in x]
40+
self.phys[i]["lanes"] = {}
41+
for j in lane_list:
42+
(status, fvs) = lane_table.get(j)
43+
assert status == True
44+
self.phys[i]["lanes"][j] = dict(fvs)
45+
46+
# "_GEARBOX_TABLE:interface:0"
47+
self.interfaces = {}
48+
intf_table = swsscommon.Table(db, sr.join([t.getKeyName(""), "interface"]))
49+
for i in [x for x in intf_table.getKeys() if sr not in x]:
50+
(status, fvs) = intf_table.get(i)
51+
assert status == True
52+
self.interfaces[i] = {"attrs" : dict(fvs)}
53+
54+
def SanityCheck(self, dvs, testlog):
55+
"""
56+
Verify data integrity of Gearbox objects in APPL_DB
57+
"""
58+
for i in self.interfaces:
59+
phy_id = self.interfaces[i]["attrs"]["phy_id"]
60+
assert phy_id in self.phys
61+
assert self.interfaces[i]["attrs"]["index"] in self.phys[phy_id]["ports"]
62+
63+
for lane in self.interfaces[i]["attrs"]["system_lanes"].split(','):
64+
assert lane in self.phys[phy_id]["lanes"]
65+
for lane in self.interfaces[i]["attrs"]["line_lanes"].split(','):
66+
assert lane in self.phys[phy_id]["lanes"]
67+
68+
class GBAsic(DVSDatabase):
69+
def __init__(self, db_id: int, connector: str, gearbox: Gearbox):
70+
DVSDatabase.__init__(self, db_id, connector)
71+
self.gearbox = gearbox
72+
self.ports = {}
73+
self._wait_for_gb_asic_db_to_initialize()
74+
75+
for connector in self.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT_CONNECTOR"):
76+
fvs = self.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT_CONNECTOR", connector)
77+
system_port_oid = fvs.get("SAI_PORT_CONNECTOR_ATTR_SYSTEM_SIDE_PORT_ID")
78+
line_port_oid = fvs.get("SAI_PORT_CONNECTOR_ATTR_LINE_SIDE_PORT_ID")
79+
80+
fvs = self.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", system_port_oid)
81+
system_lanes = fvs.get("SAI_PORT_ATTR_HW_LANE_LIST").split(":")[-1]
82+
83+
fvs = self.get_entry("ASIC_STATE:SAI_OBJECT_TYPE_PORT", line_port_oid)
84+
line_lanes = fvs.get("SAI_PORT_ATTR_HW_LANE_LIST").split(":")[-1]
85+
86+
for i in self.gearbox.interfaces:
87+
intf = self.gearbox.interfaces[i]
88+
if intf["attrs"]["system_lanes"] == system_lanes:
89+
assert intf["attrs"]["line_lanes"] == line_lanes
90+
self.ports[intf["attrs"]["index"]] = (system_port_oid, line_port_oid)
91+
92+
assert len(self.ports) == len(self.gearbox.interfaces)
93+
94+
def _wait_for_gb_asic_db_to_initialize(self) -> None:
95+
"""Wait up to 30 seconds for the default fields to appear in ASIC DB."""
96+
def _verify_db_contents():
97+
if len(self.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_SWITCH")) != \
98+
len(self.gearbox.phys):
99+
return (False, None)
100+
101+
if len(self.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT")) != \
102+
2 * len(self.gearbox.interfaces):
103+
return (False, None)
104+
105+
if len(self.get_keys("ASIC_STATE:SAI_OBJECT_TYPE_PORT_CONNECTOR")) != \
106+
len(self.gearbox.interfaces):
107+
return (False, None)
108+
109+
return (True, None)
110+
111+
# Verify that GB ASIC DB has been fully initialized
112+
init_polling_config = PollingConfig(2, 30, strict=True)
113+
wait_for_result(_verify_db_contents, init_polling_config)
114+
115+
116+
class TestGearbox(object):
117+
def test_GearboxSanity(self, dvs, testlog):
118+
Gearbox(dvs).SanityCheck(dvs, testlog)
119+
120+
def test_GbAsicFEC(self, dvs, testlog):
121+
gbasic = GBAsic(swsscommon.GB_ASIC_DB, dvs.redis_sock, Gearbox(dvs))
122+
123+
# set fec rs on port 0 of phy 1
124+
fvs = swsscommon.FieldValuePairs([("system_fec","rs")])
125+
gbasic.gearbox.phys["1"]["port_table"].set("0", fvs)
126+
fvs = swsscommon.FieldValuePairs([("line_fec","rs")])
127+
gbasic.gearbox.phys["1"]["port_table"].set("0", fvs)
128+
129+
"""FIXME: uncomment it after GearboxOrch is implemented
130+
# validate if fec rs is pushed to system/line port in gb asic db
131+
system_port_oid, line_port_oid = gbasic.ports["0"]
132+
expected_fields = {"SAI_PORT_ATTR_FEC_MODE":"SAI_PORT_FEC_MODE_RS"}
133+
gbasic.wait_for_field_match("ASIC_STATE:SAI_OBJECT_TYPE_PORT", \
134+
system_port_oid, expected_fields)
135+
gbasic.wait_for_field_match("ASIC_STATE:SAI_OBJECT_TYPE_PORT", \
136+
line_port_oid, expected_fields)
137+
"""
138+
139+
140+
# Add Dummy always-pass test at end as workaroud
141+
# for issue when Flaky fail on final test it invokes module tear-down before retrying
142+
def test_nonflaky_dummy():
143+
pass

tests/test_mirror_ipv6_combined.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from swsscommon import swsscommon
55

6-
DVS_FAKE_PLATFORM = "broadcom"
6+
DVS_ENV = ["fake_platform=broadcom"]
77

88

99
class TestMirror(object):

tests/test_mirror_ipv6_separate.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from swsscommon import swsscommon
55

6-
DVS_FAKE_PLATFORM = "mellanox"
6+
DVS_ENV = ["fake_platform=mellanox"]
77

88

99
class TestMirror(object):

0 commit comments

Comments
 (0)