mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-14 04:26:12 +00:00
tests: add opaque api test
Signed-off-by: Christian Hopps <chopps@labn.net>
This commit is contained in:
parent
9191ac86fd
commit
ad9c18f375
137
tests/topotests/ospfapi/ctester.py
Executable file
137
tests/topotests/ospfapi/ctester.py
Executable file
@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
|
||||
#
|
||||
# January 17 2022, Christian Hopps <chopps@labn.net>
|
||||
#
|
||||
# Copyright 2022, LabN Consulting, L.L.C.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
import argparse
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
|
||||
CLIENTDIR = os.path.abspath(os.path.join(CWD, "../../../ospfclient"))
|
||||
if not os.path.exists(CLIENTDIR):
|
||||
CLIENTDIR = os.path.join(CWD, "/usr/lib/frr")
|
||||
assert os.path.exists(
|
||||
os.path.join(CLIENTDIR, "ospfclient.py")
|
||||
), "can't locate ospfclient.py"
|
||||
|
||||
sys.path[0:0] = [CLIENTDIR]
|
||||
|
||||
import ospfclient as api # pylint: disable=E0401 # noqa: E402
|
||||
|
||||
|
||||
async def do_wait(c, args):
|
||||
cv = asyncio.Condition()
|
||||
|
||||
async def cb(added, removed):
|
||||
logging.debug("callback: added: %s removed: %s", added, removed)
|
||||
sys.stdout.flush()
|
||||
async with cv:
|
||||
cv.notify_all()
|
||||
|
||||
logging.debug("API using callback")
|
||||
await c.monitor_reachable(callback=cb)
|
||||
|
||||
for w in args.wait:
|
||||
check = ",".join(sorted(list(w.split(","))))
|
||||
logging.info("Waiting for %s", check)
|
||||
|
||||
while True:
|
||||
async with cv:
|
||||
got = ",".join(sorted([str(x) for x in c.reachable_routers]))
|
||||
if check == got:
|
||||
break
|
||||
logging.debug("expected '%s' != '%s'\nwaiting on notify", check, got)
|
||||
await cv.wait()
|
||||
|
||||
logging.info("SUCCESS: %s", check)
|
||||
print("SUCCESS: {}".format(check))
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
async def async_main(args):
|
||||
c = api.OspfOpaqueClient(args.server)
|
||||
await c.connect()
|
||||
if sys.version_info[1] > 6:
|
||||
asyncio.create_task(c._handle_msg_loop()) # pylint: disable=W0212
|
||||
else:
|
||||
asyncio.get_event_loop().create_task(
|
||||
c._handle_msg_loop() # pylint: disable=W0212
|
||||
)
|
||||
|
||||
if args.wait:
|
||||
await do_wait(c, args)
|
||||
return 0
|
||||
|
||||
|
||||
def main(*args):
|
||||
ap = argparse.ArgumentParser(args)
|
||||
ap.add_argument("--server", default="localhost", help="OSPF API server")
|
||||
ap.add_argument(
|
||||
"--wait", action="append", help="wait for comma-sep set of reachable routers"
|
||||
)
|
||||
ap.add_argument("-v", "--verbose", action="store_true", help="be verbose")
|
||||
args = ap.parse_args()
|
||||
|
||||
level = logging.DEBUG if args.verbose else logging.INFO
|
||||
logging.basicConfig(
|
||||
level=level, format="%(asctime)s %(levelname)s: TESTER: %(name)s: %(message)s"
|
||||
)
|
||||
|
||||
# We need to flush this output to stdout right away
|
||||
h = logging.StreamHandler(sys.stdout)
|
||||
h.flush = sys.stdout.flush
|
||||
f = logging.Formatter("%(asctime)s %(name)s: %(levelname)s: %(message)s")
|
||||
h.setFormatter(f)
|
||||
logger = logging.getLogger("ospfclient")
|
||||
logger.addHandler(h)
|
||||
logger.propagate = False
|
||||
|
||||
logging.info("ctester: starting")
|
||||
sys.stdout.flush()
|
||||
|
||||
status = 3
|
||||
try:
|
||||
if sys.version_info[1] > 6:
|
||||
status = asyncio.run(async_main(args))
|
||||
else:
|
||||
loop = asyncio.get_event_loop()
|
||||
try:
|
||||
status = loop.run_until_complete(async_main(args))
|
||||
finally:
|
||||
loop.close()
|
||||
except KeyboardInterrupt:
|
||||
logging.info("Exiting, received KeyboardInterrupt in main")
|
||||
except Exception as error:
|
||||
logging.info("Exiting, unexpected exception %s", error, exc_info=True)
|
||||
else:
|
||||
logging.info("api: clean exit")
|
||||
|
||||
return status
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit_status = main()
|
||||
sys.exit(exit_status)
|
1
tests/topotests/ospfapi/lib
Symbolic link
1
tests/topotests/ospfapi/lib
Symbolic link
@ -0,0 +1 @@
|
||||
../lib
|
10
tests/topotests/ospfapi/r1/ospfd.conf
Normal file
10
tests/topotests/ospfapi/r1/ospfd.conf
Normal file
@ -0,0 +1,10 @@
|
||||
!
|
||||
interface r1-eth0
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 1.2.3.4
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 192.168.0.1
|
||||
capability opaque
|
||||
!
|
4
tests/topotests/ospfapi/r1/zebra.conf
Normal file
4
tests/topotests/ospfapi/r1/zebra.conf
Normal file
@ -0,0 +1,4 @@
|
||||
!
|
||||
interface r1-eth0
|
||||
ip address 10.0.1.1/24
|
||||
!
|
15
tests/topotests/ospfapi/r2/ospfd.conf
Normal file
15
tests/topotests/ospfapi/r2/ospfd.conf
Normal file
@ -0,0 +1,15 @@
|
||||
!
|
||||
interface r2-eth0
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 1.2.3.4
|
||||
!
|
||||
interface r2-eth1
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 1.2.3.4
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 192.168.0.2
|
||||
capability opaque
|
||||
!
|
7
tests/topotests/ospfapi/r2/zebra.conf
Normal file
7
tests/topotests/ospfapi/r2/zebra.conf
Normal file
@ -0,0 +1,7 @@
|
||||
!
|
||||
interface r2-eth0
|
||||
ip address 10.0.1.2/24
|
||||
!
|
||||
interface r2-eth1
|
||||
ip address 10.0.2.2/24
|
||||
!
|
15
tests/topotests/ospfapi/r3/ospfd.conf
Normal file
15
tests/topotests/ospfapi/r3/ospfd.conf
Normal file
@ -0,0 +1,15 @@
|
||||
!
|
||||
interface r3-eth0
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 1.2.3.4
|
||||
!
|
||||
interface r3-eth1
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 1.2.3.4
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 192.168.0.3
|
||||
capability opaque
|
||||
!
|
7
tests/topotests/ospfapi/r3/zebra.conf
Normal file
7
tests/topotests/ospfapi/r3/zebra.conf
Normal file
@ -0,0 +1,7 @@
|
||||
!
|
||||
interface r3-eth0
|
||||
ip address 10.0.2.3/24
|
||||
!
|
||||
interface r3-eth1
|
||||
ip address 10.0.3.3/24
|
||||
!
|
10
tests/topotests/ospfapi/r4/ospfd.conf
Normal file
10
tests/topotests/ospfapi/r4/ospfd.conf
Normal file
@ -0,0 +1,10 @@
|
||||
!
|
||||
interface r4-eth0
|
||||
ip ospf hello-interval 2
|
||||
ip ospf dead-interval 10
|
||||
ip ospf area 1.2.3.4
|
||||
!
|
||||
router ospf
|
||||
ospf router-id 192.168.0.4
|
||||
capability opaque
|
||||
!
|
4
tests/topotests/ospfapi/r4/zebra.conf
Normal file
4
tests/topotests/ospfapi/r4/zebra.conf
Normal file
@ -0,0 +1,4 @@
|
||||
!
|
||||
interface r4-eth0
|
||||
ip address 10.0.3.4/24
|
||||
!
|
470
tests/topotests/ospfapi/test_ospf_clientapi.py
Normal file
470
tests/topotests/ospfapi/test_ospf_clientapi.py
Normal file
@ -0,0 +1,470 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
|
||||
#
|
||||
# Copyright (c) 2021, LabN Consulting, L.L.C.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; see the file COPYING; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
|
||||
"""
|
||||
test_ospf_clientapi.py: Test the OSPF client API.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import signal
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import pytest
|
||||
|
||||
from lib.common_config import retry, run_frr_cmd, step
|
||||
from lib.micronet import comm_error
|
||||
from lib.topogen import Topogen, TopoRouter
|
||||
from lib.topotest import interface_set_status, json_cmp
|
||||
|
||||
pytestmark = [pytest.mark.ospfd]
|
||||
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
TESTDIR = os.path.abspath(CWD)
|
||||
|
||||
CLIENTDIR = os.path.abspath(os.path.join(CWD, "../../../ospfclient"))
|
||||
if not os.path.exists(CLIENTDIR):
|
||||
CLIENTDIR = os.path.join(CWD, "/usr/lib/frr")
|
||||
|
||||
assert os.path.exists(
|
||||
os.path.join(CLIENTDIR, "ospfclient.py")
|
||||
), "can't locate ospfclient.py"
|
||||
|
||||
|
||||
# ----------
|
||||
# Test Setup
|
||||
# ----------
|
||||
|
||||
|
||||
@pytest.fixture(scope="function", name="tgen")
|
||||
def _tgen(request):
|
||||
"Setup/Teardown the environment and provide tgen argument to tests"
|
||||
nrouters = request.param
|
||||
topodef = {f"sw{i}": (f"r{i}", f"r{i+1}") for i in range(1, nrouters)}
|
||||
|
||||
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")
|
||||
router.load_config(TopoRouter.RD_OSPF, "ospfd.conf")
|
||||
router.net.daemons_options["ospfd"] = "--apiserver"
|
||||
|
||||
tgen.start_router()
|
||||
|
||||
yield tgen
|
||||
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
# 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")
|
||||
|
||||
|
||||
# ------------
|
||||
# Test Utility
|
||||
# ------------
|
||||
|
||||
|
||||
@retry(retry_timeout=45)
|
||||
def verify_ospf_database(tgen, dut, input_dict, cmd="show ip ospf database json"):
|
||||
del tgen
|
||||
show_ospf_json = run_frr_cmd(dut, cmd, isjson=True)
|
||||
if not bool(show_ospf_json):
|
||||
return "ospf is not running"
|
||||
result = json_cmp(show_ospf_json, input_dict)
|
||||
return str(result) if result else None
|
||||
|
||||
|
||||
def myreadline(f):
|
||||
buf = b""
|
||||
while True:
|
||||
# logging.info("READING 1 CHAR")
|
||||
c = f.read(1)
|
||||
if not c:
|
||||
return buf if buf else None
|
||||
buf += c
|
||||
# logging.info("READ CHAR: '%s'", c)
|
||||
if c == b"\n":
|
||||
return buf
|
||||
|
||||
|
||||
def _wait_output(p, regex, timeout=120):
|
||||
retry_until = datetime.now() + timedelta(seconds=timeout)
|
||||
while datetime.now() < retry_until:
|
||||
# line = p.stdout.readline()
|
||||
line = myreadline(p.stdout)
|
||||
if not line:
|
||||
assert None, "Timeout waiting for '{}'".format(regex)
|
||||
line = line.decode("utf-8")
|
||||
line = line.rstrip()
|
||||
if line:
|
||||
logging.debug("GOT LINE: '%s'", line)
|
||||
m = re.search(regex, line)
|
||||
if m:
|
||||
return m
|
||||
assert None, "Failed to get output withint {}s".format(timeout)
|
||||
|
||||
|
||||
# -----
|
||||
# Tests
|
||||
# -----
|
||||
|
||||
|
||||
def _test_reachability(tgen, testbin):
|
||||
waitlist = [
|
||||
"192.168.0.1,192.168.0.2,192.168.0.4",
|
||||
"192.168.0.2,192.168.0.4",
|
||||
"192.168.0.1,192.168.0.2,192.168.0.4",
|
||||
]
|
||||
r2 = tgen.gears["r2"]
|
||||
r3 = tgen.gears["r3"]
|
||||
|
||||
wait_args = [f"--wait={x}" for x in waitlist]
|
||||
|
||||
p = None
|
||||
try:
|
||||
step("reachable: check for initial reachability")
|
||||
p = r3.popen(
|
||||
["/usr/bin/timeout", "120", testbin, "-v", *wait_args],
|
||||
encoding=None, # don't buffer
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
_wait_output(p, "SUCCESS: {}".format(waitlist[0]))
|
||||
|
||||
step("reachable: check for modified reachability")
|
||||
interface_set_status(r2, "r2-eth0", False)
|
||||
_wait_output(p, "SUCCESS: {}".format(waitlist[1]))
|
||||
|
||||
step("reachable: check for restored reachability")
|
||||
interface_set_status(r2, "r2-eth0", True)
|
||||
_wait_output(p, "SUCCESS: {}".format(waitlist[2]))
|
||||
except Exception as error:
|
||||
logging.error("ERROR: %s", error)
|
||||
raise
|
||||
finally:
|
||||
if p:
|
||||
p.terminate()
|
||||
p.wait()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tgen", [4], indirect=True)
|
||||
def test_ospf_reachability(tgen):
|
||||
testbin = os.path.join(TESTDIR, "ctester.py")
|
||||
rc, o, e = tgen.gears["r2"].net.cmd_status([testbin, "--help"])
|
||||
logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", testbin, rc, o, e)
|
||||
_test_reachability(tgen, testbin)
|
||||
|
||||
|
||||
def _test_add_data(tgen, apibin):
|
||||
"Test adding opaque data to domain"
|
||||
|
||||
r1 = tgen.gears["r1"]
|
||||
|
||||
step("add opaque: add opaque link local")
|
||||
|
||||
p = None
|
||||
try:
|
||||
p = r1.popen([apibin, "-v", "add,9,10.0.1.1,230,2,00000202"])
|
||||
input_dict = {
|
||||
"routerId": "192.168.0.1",
|
||||
"areas": {
|
||||
"1.2.3.4": {
|
||||
"linkLocalOpaqueLsa": [
|
||||
{
|
||||
"lsId": "230.0.0.2",
|
||||
"advertisedRouter": "192.168.0.1",
|
||||
"sequenceNumber": "80000001",
|
||||
}
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
# Wait for it to show up
|
||||
assert verify_ospf_database(tgen, r1, input_dict) is None
|
||||
|
||||
input_dict = {
|
||||
"linkLocalOpaqueLsa": {
|
||||
"areas": {
|
||||
"1.2.3.4": [
|
||||
{
|
||||
"linkStateId": "230.0.0.2",
|
||||
"advertisingRouter": "192.168.0.1",
|
||||
"lsaSeqNumber": "80000001",
|
||||
"opaqueData": "00000202",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
# verify content
|
||||
json_cmd = "show ip ospf da opaque-link json"
|
||||
assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None
|
||||
|
||||
step("reset client, add opaque area, verify link local flushing")
|
||||
|
||||
p.send_signal(signal.SIGINT)
|
||||
time.sleep(2)
|
||||
p.wait()
|
||||
p = None
|
||||
p = r1.popen([apibin, "-v", "add,10,1.2.3.4,231,1,00010101"])
|
||||
input_dict = {
|
||||
"routerId": "192.168.0.1",
|
||||
"areas": {
|
||||
"1.2.3.4": {
|
||||
"linkLocalOpaqueLsa": [
|
||||
{
|
||||
"lsId": "230.0.0.2",
|
||||
"advertisedRouter": "192.168.0.1",
|
||||
"sequenceNumber": "80000001",
|
||||
"lsaAge": 3600,
|
||||
}
|
||||
],
|
||||
"areaLocalOpaqueLsa": [
|
||||
{
|
||||
"lsId": "231.0.0.1",
|
||||
"advertisedRouter": "192.168.0.1",
|
||||
"sequenceNumber": "80000001",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
# Wait for it to show up
|
||||
assert verify_ospf_database(tgen, r1, input_dict) is None
|
||||
|
||||
input_dict = {
|
||||
"areaLocalOpaqueLsa": {
|
||||
"areas": {
|
||||
"1.2.3.4": [
|
||||
{
|
||||
"linkStateId": "231.0.0.1",
|
||||
"advertisingRouter": "192.168.0.1",
|
||||
"lsaSeqNumber": "80000001",
|
||||
"opaqueData": "00010101",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
# verify content
|
||||
json_cmd = "show ip ospf da opaque-area json"
|
||||
assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None
|
||||
|
||||
step("reset client, add opaque AS, verify area flushing")
|
||||
|
||||
p.send_signal(signal.SIGINT)
|
||||
time.sleep(2)
|
||||
p.wait()
|
||||
p = None
|
||||
|
||||
p = r1.popen([apibin, "-v", "add,11,232,3,deadbeaf01234567"])
|
||||
input_dict = {
|
||||
"routerId": "192.168.0.1",
|
||||
"areas": {
|
||||
"1.2.3.4": {
|
||||
"areaLocalOpaqueLsa": [
|
||||
{
|
||||
"lsId": "231.0.0.1",
|
||||
"advertisedRouter": "192.168.0.1",
|
||||
"sequenceNumber": "80000001",
|
||||
"lsaAge": 3600,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
"asExternalOpaqueLsa": [
|
||||
{
|
||||
"lsId": "232.0.0.3",
|
||||
"advertisedRouter": "192.168.0.1",
|
||||
"sequenceNumber": "80000001",
|
||||
},
|
||||
],
|
||||
}
|
||||
# Wait for it to show up
|
||||
assert verify_ospf_database(tgen, r1, input_dict) is None
|
||||
|
||||
input_dict = {
|
||||
"asExternalOpaqueLsa": [
|
||||
{
|
||||
"linkStateId": "232.0.0.3",
|
||||
"advertisingRouter": "192.168.0.1",
|
||||
"lsaSeqNumber": "80000001",
|
||||
"opaqueData": "deadbeaf01234567",
|
||||
},
|
||||
]
|
||||
}
|
||||
# verify content
|
||||
json_cmd = "show ip ospf da opaque-as json"
|
||||
assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None
|
||||
|
||||
step("stop client, verify AS flushing")
|
||||
|
||||
p.send_signal(signal.SIGINT)
|
||||
time.sleep(2)
|
||||
p.wait()
|
||||
p = None
|
||||
|
||||
input_dict = {
|
||||
"routerId": "192.168.0.1",
|
||||
"asExternalOpaqueLsa": [
|
||||
{
|
||||
"lsId": "232.0.0.3",
|
||||
"advertisedRouter": "192.168.0.1",
|
||||
"sequenceNumber": "80000001",
|
||||
"lsaAge": 3600,
|
||||
},
|
||||
],
|
||||
}
|
||||
# Wait for it to be flushed
|
||||
assert verify_ospf_database(tgen, r1, input_dict) is None
|
||||
|
||||
step("start client adding opaque domain, verify new sequence number and data")
|
||||
|
||||
# Originate it again
|
||||
p = r1.popen([apibin, "-v", "add,11,232,3,ebadf00d"])
|
||||
input_dict = {
|
||||
"routerId": "192.168.0.1",
|
||||
"asExternalOpaqueLsa": [
|
||||
{
|
||||
"lsId": "232.0.0.3",
|
||||
"advertisedRouter": "192.168.0.1",
|
||||
"sequenceNumber": "80000002",
|
||||
},
|
||||
],
|
||||
}
|
||||
assert verify_ospf_database(tgen, r1, input_dict) is None
|
||||
|
||||
input_dict = {
|
||||
"asExternalOpaqueLsa": [
|
||||
{
|
||||
"linkStateId": "232.0.0.3",
|
||||
"advertisingRouter": "192.168.0.1",
|
||||
"lsaSeqNumber": "80000002",
|
||||
"opaqueData": "ebadf00d",
|
||||
},
|
||||
]
|
||||
}
|
||||
# verify content
|
||||
json_cmd = "show ip ospf da opaque-as json"
|
||||
assert verify_ospf_database(tgen, r1, input_dict, json_cmd) is None
|
||||
|
||||
p.send_signal(signal.SIGINT)
|
||||
time.sleep(2)
|
||||
p.wait()
|
||||
p = None
|
||||
|
||||
except Exception:
|
||||
if p:
|
||||
p.terminate()
|
||||
if p.wait():
|
||||
comm_error(p)
|
||||
p = None
|
||||
raise
|
||||
finally:
|
||||
if p:
|
||||
p.terminate()
|
||||
p.wait()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tgen", [2], indirect=True)
|
||||
def test_ospf_opaque_add_data3(tgen):
|
||||
apibin = os.path.join(CLIENTDIR, "ospfclient.py")
|
||||
rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"])
|
||||
logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e)
|
||||
_test_add_data(tgen, apibin)
|
||||
|
||||
|
||||
def _test_opaque_add_del(tgen, apibin):
|
||||
"Test adding opaque data to domain"
|
||||
|
||||
r1 = tgen.gears["r1"]
|
||||
r2 = tgen.gears["r2"]
|
||||
|
||||
p = None
|
||||
pread = None
|
||||
try:
|
||||
step("reachable: check for add notification")
|
||||
pread = r2.popen(
|
||||
["/usr/bin/timeout", "120", apibin, "-v"],
|
||||
encoding=None, # don't buffer
|
||||
stdin=subprocess.DEVNULL,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
)
|
||||
p = r1.popen([apibin, "-v", "add,11,232,3,ebadf00d"])
|
||||
|
||||
# Wait for add notification
|
||||
# RECV: LSA update msg for LSA 232.0.0.3 in area 0.0.0.0 seq 0x80000001 len 24 age 9
|
||||
|
||||
ls_id = "232.0.0.3"
|
||||
waitfor = "RECV:.*update msg.*LSA {}.*age ([0-9]+)".format(ls_id)
|
||||
_ = _wait_output(pread, waitfor)
|
||||
|
||||
p.terminate()
|
||||
if p.wait():
|
||||
comm_error(p)
|
||||
|
||||
# step("reachable: check for flush/age out")
|
||||
# # Wait for max age notification
|
||||
# waitfor = "RECV:.*update msg.*LSA {}.*age 3600".format(ls_id)
|
||||
# _wait_output(pread, waitfor)
|
||||
|
||||
step("reachable: check for delete")
|
||||
# Wait for delete notification
|
||||
waitfor = "RECV:.*delete msg.*LSA {}.*".format(ls_id)
|
||||
_wait_output(pread, waitfor)
|
||||
except Exception:
|
||||
if p:
|
||||
p.terminate()
|
||||
if p.wait():
|
||||
comm_error(p)
|
||||
p = None
|
||||
raise
|
||||
finally:
|
||||
if pread:
|
||||
pread.terminate()
|
||||
pread.wait()
|
||||
if p:
|
||||
p.terminate()
|
||||
p.wait()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("tgen", [2], indirect=True)
|
||||
def test_ospf_opaque_delete_data3(tgen):
|
||||
apibin = os.path.join(CLIENTDIR, "ospfclient.py")
|
||||
rc, o, e = tgen.gears["r2"].net.cmd_status([apibin, "--help"])
|
||||
logging.info("%s --help: rc: %s stdout: '%s' stderr: '%s'", apibin, rc, o, e)
|
||||
_test_opaque_add_del(tgen, apibin)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
Loading…
Reference in New Issue
Block a user