225 lines
5.8 KiB
Python
225 lines
5.8 KiB
Python
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
#
|
|
# February 21 2022, Christian Hopps <chopps@labn.net>
|
|
#
|
|
# Copyright (c) 2022, LabN Consulting, L.L.C.
|
|
#
|
|
"""
|
|
test_basic_grpc.py: Test Basic gRPC.
|
|
"""
|
|
|
|
import json
|
|
import logging
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
import pytest
|
|
from lib.common_config import step
|
|
from lib.micronet import commander
|
|
from lib.topogen import Topogen, TopoRouter
|
|
from lib.topotest import json_cmp
|
|
|
|
CWD = os.path.dirname(os.path.realpath(__file__))
|
|
|
|
GRPCP_ZEBRA = 50051
|
|
GRPCP_STATICD = 50052
|
|
GRPCP_BFDD = 50053
|
|
GRPCP_ISISD = 50054
|
|
GRPCP_OSPFD = 50055
|
|
GRPCP_PIMD = 50056
|
|
GRPCP_MGMTD = 50057
|
|
|
|
pytestmark = [
|
|
pytest.mark.mgmtd,
|
|
# pytest.mark.bfdd,
|
|
# pytest.mark.isisd,
|
|
# pytest.mark.ospfd,
|
|
# pytest.mark.pimd,
|
|
pytest.mark.staticd,
|
|
]
|
|
|
|
script_path = os.path.realpath(os.path.join(CWD, "../lib/grpc-query.py"))
|
|
|
|
try:
|
|
commander.cmd_raises([script_path, "--check"])
|
|
except Exception:
|
|
pytest.skip(
|
|
"skipping; cannot create or import gRPC proto modules", allow_module_level=True
|
|
)
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def tgen(request):
|
|
"Setup/Teardown the environment and provide tgen argument to tests"
|
|
topodef = {"s1": ("r1", "r2")}
|
|
tgen = Topogen(topodef, request.module.__name__)
|
|
|
|
tgen.start_topology()
|
|
router_list = tgen.routers()
|
|
|
|
for _, router in router_list.items():
|
|
router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf", f"-M grpc:{GRPCP_ZEBRA}")
|
|
router.load_config(TopoRouter.RD_STATIC, "", f"-M grpc:{GRPCP_STATICD}")
|
|
# router.load_config(TopoRouter.RD_BFDD, "", f"-M grpc:{GRPCP_BFDD}")
|
|
# router.load_config(TopoRouter.RD_ISIS, None, f"-M grpc:{GRPCP_ISISD}")
|
|
# router.load_config(TopoRouter.RD_OSPF, None, f"-M grpc:{GRPCP_OSPFD}")
|
|
# router.load_config(TopoRouter.RD_PIM, None, f"-M grpc:{GRPCP_PIMD}")
|
|
|
|
# This doesn't work yet...
|
|
# router.load_config(TopoRouter.RD_MGMTD, "", f"-M grpc:{GRPCP_MGMTD}")
|
|
|
|
tgen.start_router()
|
|
yield tgen
|
|
|
|
logging.info("Stopping all routers (no assert on error)")
|
|
tgen.stop_topology()
|
|
|
|
|
|
# Let's not do this so we catch errors
|
|
# Fixture that executes before each test
|
|
@pytest.fixture(autouse=True)
|
|
def skip_on_failure(tgen):
|
|
if tgen.routers_have_failure():
|
|
pytest.skip("skipped because of previous test failure")
|
|
|
|
|
|
# ===================
|
|
# The tests functions
|
|
# ===================
|
|
|
|
|
|
def run_grpc_client(r, port, commands):
|
|
if not isinstance(commands, str):
|
|
commands = "\n".join(commands) + "\n"
|
|
if not commands.endswith("\n"):
|
|
commands += "\n"
|
|
return r.cmd_raises([script_path, f"--port={port}"], stdin=commands)
|
|
|
|
|
|
def test_connectivity(tgen):
|
|
tgen.gears["r1"].cmd_raises("ping -c1 192.168.1.2")
|
|
|
|
|
|
def test_capabilities(tgen):
|
|
r1 = tgen.gears["r1"]
|
|
output = run_grpc_client(r1, GRPCP_STATICD, "GETCAP")
|
|
logging.debug("grpc output: %s", output)
|
|
|
|
modules = sorted(re.findall('name: "([^"]+)"', output))
|
|
expected = ["frr-interface", "frr-routing", "frr-staticd", "frr-vrf"]
|
|
assert modules == expected
|
|
|
|
encodings = sorted(re.findall("supported_encodings: (.*)", output))
|
|
expected = ["JSON", "XML"]
|
|
assert encodings == expected
|
|
|
|
|
|
def test_get_config(tgen):
|
|
nrepeat = 5
|
|
r1 = tgen.gears["r1"]
|
|
|
|
step("'GET' interface config and state 10 times, once per invocation")
|
|
|
|
for i in range(0, nrepeat):
|
|
output = run_grpc_client(r1, GRPCP_ZEBRA, "GET-CONFIG,/frr-interface:lib")
|
|
logging.debug("[iteration %s]: grpc GET output: %s", i, output)
|
|
|
|
step(f"'GET' YANG {nrepeat} times in one invocation")
|
|
commands = ["GET-CONFIG,/frr-interface:lib" for _ in range(0, 10)]
|
|
output = run_grpc_client(r1, GRPCP_ZEBRA, commands)
|
|
logging.debug("grpc GET*{%d} output: %s", nrepeat, output)
|
|
|
|
output = run_grpc_client(r1, GRPCP_ZEBRA, commands[0])
|
|
out_json = json.loads(output)
|
|
expect = json.loads(
|
|
"""{
|
|
"frr-interface:lib": {
|
|
"interface": [
|
|
{
|
|
"name": "r1-eth0",
|
|
"frr-zebra:zebra": {
|
|
"ipv4-addrs": [
|
|
{
|
|
"ip": "192.168.1.1",
|
|
"prefix-length": 24
|
|
}
|
|
],
|
|
"evpn-mh": {},
|
|
"ipv6-router-advertisements": {}
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"frr-zebra:zebra": {
|
|
"import-kernel-table": {}
|
|
}
|
|
} """
|
|
)
|
|
result = json_cmp(out_json, expect, exact=True)
|
|
assert result is None
|
|
|
|
|
|
def test_get_vrf_config(tgen):
|
|
r1 = tgen.gears["r1"]
|
|
|
|
step("'GET' VRF config and state")
|
|
|
|
output = run_grpc_client(r1, GRPCP_STATICD, "GET,/frr-vrf:lib")
|
|
logging.debug("grpc GET /frr-vrf:lib output: %s", output)
|
|
out_json = json.loads(output)
|
|
expect = json.loads(
|
|
"""{
|
|
"frr-vrf:lib": {
|
|
"vrf": [
|
|
{
|
|
"name": "default",
|
|
"state": {
|
|
"id": 0,
|
|
"active": true
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
"""
|
|
)
|
|
result = json_cmp(out_json, expect, exact=True)
|
|
assert result is None
|
|
|
|
|
|
def test_shutdown_checks(tgen):
|
|
# Start a process rnuning that will fetch bunches of data then shut the routers down
|
|
# and check for cores.
|
|
nrepeat = 100
|
|
r1 = tgen.gears["r1"]
|
|
commands = ["GET,/frr-interface:lib" for _ in range(0, nrepeat)]
|
|
p = r1.popen([script_path, f"--port={GRPCP_ZEBRA}"] + commands)
|
|
import time
|
|
|
|
time.sleep(1)
|
|
try:
|
|
for r in tgen.routers().values():
|
|
r.net.stopRouter(False)
|
|
r.net.checkRouterCores()
|
|
finally:
|
|
if p:
|
|
p.terminate()
|
|
p.wait()
|
|
|
|
|
|
# Memory leak test template
|
|
# Not compatible with the shutdown check above
|
|
def _test_memory_leak(tgen):
|
|
"Run the memory leak test and report results."
|
|
|
|
if not tgen.is_memleak_enabled():
|
|
pytest.skip("Memory leak test/report is disabled")
|
|
|
|
tgen.report_memory_leaks()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
args = ["-s"] + sys.argv[1:]
|
|
sys.exit(pytest.main(args))
|