Skip to content

Commit e41b4a7

Browse files
authored
Merge pull request FRRouting#16012 from LabNConsulting/chopps/improve-grpc-test
tests: improve the grpc query client and topotest
2 parents e3fceef + 9dc02dd commit e41b4a7

File tree

2 files changed

+106
-32
lines changed

2 files changed

+106
-32
lines changed

tests/topotests/grpc_basic/test_basic_grpc.py

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,18 @@
99
test_basic_grpc.py: Test Basic gRPC.
1010
"""
1111

12+
import json
1213
import logging
1314
import os
15+
import re
1416
import sys
1517

1618
import pytest
17-
1819
from lib.common_config import step
1920
from lib.micronet import commander
2021
from lib.topogen import Topogen, TopoRouter
2122
from lib.topolog import logger
23+
from lib.topotest import json_cmp
2224

2325
CWD = os.path.dirname(os.path.realpath(__file__))
2426

@@ -28,6 +30,7 @@
2830
GRPCP_ISISD = 50054
2931
GRPCP_OSPFD = 50055
3032
GRPCP_PIMD = 50056
33+
GRPCP_MGMTD = 50057
3134

3235
pytestmark = [
3336
pytest.mark.mgmtd,
@@ -59,12 +62,15 @@ def tgen(request):
5962

6063
for rname, router in router_list.items():
6164
router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf", f"-M grpc:{GRPCP_ZEBRA}")
62-
router.load_config(TopoRouter.RD_STATIC, None, f"-M grpc:{GRPCP_STATICD}")
63-
# router.load_config(TopoRouter.RD_BFD, None, f"-M grpc:{GRPCP_BFDD}")
65+
router.load_config(TopoRouter.RD_STATIC, "", f"-M grpc:{GRPCP_STATICD}")
66+
# router.load_config(TopoRouter.RD_BFDD, "", f"-M grpc:{GRPCP_BFDD}")
6467
# router.load_config(TopoRouter.RD_ISIS, None, f"-M grpc:{GRPCP_ISISD}")
6568
# router.load_config(TopoRouter.RD_OSPF, None, f"-M grpc:{GRPCP_OSPFD}")
6669
# router.load_config(TopoRouter.RD_PIM, None, f"-M grpc:{GRPCP_PIMD}")
6770

71+
# This doesn't work yet...
72+
# router.load_config(TopoRouter.RD_MGMTD, "", f"-M grpc:{GRPCP_MGMTD}")
73+
6874
tgen.start_router()
6975
yield tgen
7076

@@ -94,40 +100,94 @@ def run_grpc_client(r, port, commands):
94100

95101

96102
def test_connectivity(tgen):
97-
r1 = tgen.gears["r1"]
98-
output = r1.cmd_raises("ping -c1 192.168.1.2")
99-
logging.info("ping output: %s", output)
103+
tgen.gears["r1"].cmd_raises("ping -c1 192.168.1.2")
100104

101105

102106
def test_capabilities(tgen):
103107
r1 = tgen.gears["r1"]
104-
output = run_grpc_client(r1, GRPCP_ZEBRA, "GETCAP")
105-
logging.info("grpc output: %s", output)
108+
output = run_grpc_client(r1, GRPCP_STATICD, "GETCAP")
109+
logging.debug("grpc output: %s", output)
110+
111+
modules = sorted(re.findall('name: "([^"]+)"', output))
112+
expected = ["frr-interface", "frr-routing", "frr-staticd", "frr-vrf"]
113+
assert modules == expected
114+
115+
encodings = sorted(re.findall("supported_encodings: (.*)", output))
116+
expected = ["JSON", "XML"]
117+
assert encodings == expected
106118

107119

108120
def test_get_config(tgen):
109121
nrepeat = 5
110122
r1 = tgen.gears["r1"]
111123

112-
step("'GET' interface config 10 times, once per invocation")
124+
step("'GET' interface config and state 10 times, once per invocation")
113125

114126
for i in range(0, nrepeat):
115-
output = run_grpc_client(r1, GRPCP_ZEBRA, "GET,/frr-interface:lib")
116-
logging.info("[iteration %s]: grpc GET output: %s", i, output)
127+
output = run_grpc_client(r1, GRPCP_ZEBRA, "GET-CONFIG,/frr-interface:lib")
128+
logging.debug("[iteration %s]: grpc GET output: %s", i, output)
117129

118130
step(f"'GET' YANG {nrepeat} times in one invocation")
119-
commands = ["GET,/frr-interface:lib" for _ in range(0, 10)]
131+
commands = ["GET-CONFIG,/frr-interface:lib" for _ in range(0, 10)]
120132
output = run_grpc_client(r1, GRPCP_ZEBRA, commands)
121-
logging.info("grpc GET*{%d} output: %s", nrepeat, output)
133+
logging.debug("grpc GET*{%d} output: %s", nrepeat, output)
134+
135+
output = run_grpc_client(r1, GRPCP_ZEBRA, commands[0])
136+
out_json = json.loads(output)
137+
expect = json.loads(
138+
"""{
139+
"frr-interface:lib": {
140+
"interface": [
141+
{
142+
"name": "r1-eth0",
143+
"frr-zebra:zebra": {
144+
"ipv4-addrs": [
145+
{
146+
"ip": "192.168.1.1",
147+
"prefix-length": 24
148+
}
149+
],
150+
"evpn-mh": {},
151+
"ipv6-router-advertisements": {}
152+
}
153+
}
154+
]
155+
},
156+
"frr-zebra:zebra": {
157+
"import-kernel-table": {}
158+
}
159+
} """
160+
)
161+
result = json_cmp(out_json, expect, exact=True)
162+
assert result is None
122163

123164

124165
def test_get_vrf_config(tgen):
125166
r1 = tgen.gears["r1"]
126167

127-
step("'GET' get VRF config")
128-
129-
output = run_grpc_client(r1, GRPCP_ZEBRA, "GET,/frr-vrf:lib")
130-
logging.info("grpc GET /frr-vrf:lib output: %s", output)
168+
step("'GET' VRF config and state")
169+
170+
output = run_grpc_client(r1, GRPCP_STATICD, "GET,/frr-vrf:lib")
171+
logging.debug("grpc GET /frr-vrf:lib output: %s", output)
172+
out_json = json.loads(output)
173+
expect = json.loads(
174+
"""{
175+
"frr-vrf:lib": {
176+
"vrf": [
177+
{
178+
"name": "default",
179+
"state": {
180+
"id": 0,
181+
"active": true
182+
}
183+
}
184+
]
185+
}
186+
}
187+
"""
188+
)
189+
result = json_cmp(out_json, expect, exact=True)
190+
assert result is None
131191

132192

133193
def test_shutdown_checks(tgen):

tests/topotests/lib/grpc-query.py

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,16 @@
1818
# This is painful but works if you have installed grpc and grpc_tools would be *way*
1919
# better if we actually built and installed these but ... python packaging.
2020
try:
21-
import grpc
2221
import grpc_tools
2322

23+
import grpc
24+
2425
sys.path.append(os.path.dirname(CWD))
2526
from munet.base import commander
2627

2728
commander.cmd_raises(f"cp {CWD}/../../../grpc/frr-northbound.proto .")
2829
commander.cmd_raises(
29-
f"python3 -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I . frr-northbound.proto"
30+
"python3 -m grpc_tools.protoc --python_out=. --grpc_python_out=. -I . frr-northbound.proto"
3031
)
3132
except Exception as error:
3233
logging.error("can't create proto definition modules %s", error)
@@ -57,16 +58,16 @@ def get_capabilities(self):
5758
logging.debug("GRPC Capabilities: %s", response)
5859
return response
5960

60-
def get(self, xpath):
61+
def get(self, xpath, encoding, gtype):
6162
request = frr_northbound_pb2.GetRequest()
6263
request.path.append(xpath)
63-
request.type = frr_northbound_pb2.GetRequest.ALL
64-
request.encoding = frr_northbound_pb2.XML
65-
xml = ""
64+
request.type = gtype
65+
request.encoding = encoding
66+
result = ""
6667
for r in self.stub.Get(request):
67-
logging.info('GRPC Get path: "%s" value: %s', request.path, r)
68-
xml += str(r.data.data)
69-
return xml
68+
logging.debug('GRPC Get path: "%s" value: %s', request.path, r)
69+
result += str(r.data.data)
70+
return result
7071

7172

7273
def next_action(action_list=None):
@@ -95,6 +96,7 @@ def main(*args):
9596
)
9697
parser.add_argument("-v", "--verbose", action="store_true", help="be verbose")
9798
parser.add_argument("--check", action="store_true", help="check runable")
99+
parser.add_argument("--xml", action="store_true", help="encode XML instead of JSON")
98100
parser.add_argument("actions", nargs="*", help="GETCAP|GET,xpath")
99101
args = parser.parse_args(*args)
100102

@@ -107,20 +109,32 @@ def main(*args):
107109
if args.check:
108110
sys.exit(0)
109111

112+
encoding = frr_northbound_pb2.XML if args.xml else frr_northbound_pb2.JSON
113+
110114
c = GRPCClient(args.server, args.port)
111115

112116
for action in next_action(args.actions):
113117
action = action.casefold()
114-
logging.info("GOT ACTION: %s", action)
118+
logging.debug("GOT ACTION: %s", action)
115119
if action == "getcap":
116120
caps = c.get_capabilities()
117-
print("Capabilities:", caps)
121+
print(caps)
118122
elif action.startswith("get,"):
119-
# Print Interface State and Config
123+
# Get and print config and state
124+
_, xpath = action.split(",", 1)
125+
logging.debug("Get XPath: %s", xpath)
126+
print(c.get(xpath, encoding, gtype=frr_northbound_pb2.GetRequest.ALL))
127+
elif action.startswith("get-config,"):
128+
# Get and print config
129+
_, xpath = action.split(",", 1)
130+
logging.debug("Get Config XPath: %s", xpath)
131+
print(c.get(xpath, encoding, gtype=frr_northbound_pb2.GetRequest.CONFIG))
132+
# for _ in range(0, 1):
133+
elif action.startswith("get-state,"):
134+
# Get and print state
120135
_, xpath = action.split(",", 1)
121-
print("Get XPath: ", xpath)
122-
xml = c.get(xpath)
123-
print("{}: {}".format(xpath, xml))
136+
logging.debug("Get State XPath: %s", xpath)
137+
print(c.get(xpath, encoding, gtype=frr_northbound_pb2.GetRequest.STATE))
124138
# for _ in range(0, 1):
125139

126140

0 commit comments

Comments
 (0)