]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/lib/ltemplate.py
tests: Fix for frr-bot style issues
[mirror_frr.git] / tests / topotests / lib / ltemplate.py
CommitLineData
df437d25
LB
1#!/usr/bin/env python
2
3#
4# Part of NetDEF Topology Tests
5#
6# Copyright (c) 2017 by
7# Network Device Education Foundation, Inc. ("NetDEF")
8#
9# Permission to use, copy, modify, and/or distribute this software
10# for any purpose with or without fee is hereby granted, provided
11# that the above copyright notice and this permission notice appear
12# in all copies.
13#
14# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
15# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
17# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
18# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
20# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21# OF THIS SOFTWARE.
22#
23
24"""
25ltemplate.py: LabN template for FRR tests.
26"""
27
28import os
29import sys
89b9abd9 30import platform
49581587 31
df437d25
LB
32import pytest
33
34# pylint: disable=C0413
35# Import topogen and topotest helpers
36from lib import topotest
37from lib.topogen import Topogen, TopoRouter, get_topogen
38from lib.topolog import logger
39from lib.lutil import *
40
41# Required to instantiate the topology builder class.
9e219b9a
LB
42
43customize = None
44
a53c08bc 45
701a0192 46class LTemplate:
9e219b9a
LB
47 test = None
48 testdir = None
850de337
LB
49 scriptdir = None
50 logdir = None
89b9abd9
LB
51 prestarthooksuccess = True
52 poststarthooksuccess = True
53 iproute2Ver = None
9e219b9a
LB
54
55 def __init__(self, test, testdir):
49581587 56 pathname = os.path.join(testdir, "customize.py")
9e219b9a 57 global customize
49581587
CH
58 if sys.version_info >= (3, 5):
59 import importlib.util
a53c08bc 60
49581587
CH
61 spec = importlib.util.spec_from_file_location("customize", pathname)
62 customize = importlib.util.module_from_spec(spec)
63 spec.loader.exec_module(customize)
64 else:
65 import imp
a53c08bc 66
49581587 67 customize = imp.load_source("customize", pathname)
9e219b9a
LB
68 self.test = test
69 self.testdir = testdir
850de337 70 self.scriptdir = testdir
49581587 71 self.logdir = ""
701a0192 72 logger.info("LTemplate: " + test)
9e219b9a
LB
73
74 def setup_module(self, mod):
75 "Sets up the pytest environment"
76 # This function initiates the topology build with Topogen...
e82b531d 77 tgen = Topogen(customize.build_topo, mod.__name__)
9e219b9a
LB
78 # ... and here it calls Mininet initialization functions.
79 tgen.start_topology()
49581587
CH
80
81 self.logdir = tgen.logdir
9e219b9a 82
701a0192 83 logger.info("Topology started")
9e219b9a 84 try:
89b9abd9
LB
85 self.prestarthooksuccess = customize.ltemplatePreRouterStartHook()
86 except AttributeError:
701a0192 87 # not defined
9e219b9a 88 logger.debug("ltemplatePreRouterStartHook() not defined")
af01532c 89 if self.prestarthooksuccess != True:
701a0192 90 logger.info("ltemplatePreRouterStartHook() failed, skipping test")
af01532c 91 return
9e219b9a
LB
92
93 # This is a sample of configuration loading.
94 router_list = tgen.routers()
95
b515c81a 96 # For all registered routers, load the zebra configuration file
e5f0ed14 97 for rname, router in router_list.items():
a38f0083
LB
98 logger.info("Setting up %s" % rname)
99 for rd_val in TopoRouter.RD:
701a0192 100 config = os.path.join(
101 self.testdir, "{}/{}.conf".format(rname, TopoRouter.RD[rd_val])
102 )
a38f0083
LB
103 prog = os.path.join(tgen.net[rname].daemondir, TopoRouter.RD[rd_val])
104 if os.path.exists(config):
105 if os.path.exists(prog):
106 router.load_config(rd_val, config)
107 else:
701a0192 108 logger.warning(
109 "{} not found, but have {}.conf file".format(
110 prog, TopoRouter.RD[rd_val]
111 )
112 )
9e219b9a
LB
113
114 # After loading the configurations, this function loads configured daemons.
701a0192 115 logger.info("Starting routers")
9e219b9a
LB
116 tgen.start_router()
117 try:
89b9abd9
LB
118 self.poststarthooksuccess = customize.ltemplatePostRouterStartHook()
119 except AttributeError:
701a0192 120 # not defined
9e219b9a 121 logger.debug("ltemplatePostRouterStartHook() not defined")
850de337 122 luStart(baseScriptDir=self.scriptdir, baseLogDir=self.logdir, net=tgen.net)
9e219b9a 123
701a0192 124
125# initialized by ltemplate_start
9e219b9a 126_lt = None
df437d25 127
701a0192 128
df437d25 129def setup_module(mod):
9e219b9a
LB
130 global _lt
131 root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
701a0192 132 test = mod.__name__[: mod.__name__.rfind(".")]
9e219b9a
LB
133 testdir = os.path.join(root, test)
134
701a0192 135 # don't do this for now as reload didn't work as expected
136 # fixup sys.path, want test dir there only once
137 # try:
9e219b9a 138 # sys.path.remove(testdir)
701a0192 139 # except ValueError:
9e219b9a 140 # logger.debug(testdir+" not found in original sys.path")
701a0192 141 # add testdir
142 # sys.path.append(testdir)
9e219b9a 143
701a0192 144 # init class
9e219b9a
LB
145 _lt = LTemplate(test, testdir)
146 _lt.setup_module(mod)
147
701a0192 148 # drop testdir
149 # sys.path.remove(testdir)
150
df437d25
LB
151
152def teardown_module(mod):
850de337 153 global _lt
df437d25
LB
154 "Teardown the pytest environment"
155 tgen = get_topogen()
156
af01532c 157 if _lt != None and _lt.scriptdir != None and _lt.prestarthooksuccess == True:
dccb75bb 158 luShowResults(logger.info)
850de337
LB
159 print(luFinish())
160
df437d25
LB
161 # This function tears down the whole topology.
162 tgen.stop_topology()
850de337 163 _lt = None
df437d25 164
701a0192 165
166def ltemplateTest(
167 script, SkipIfFailed=True, CallOnFail=None, CheckFuncStr=None, KeepGoing=False
168):
af01532c
LB
169 global _lt
170 if _lt == None or _lt.prestarthooksuccess != True:
171 return
172
df437d25
LB
173 tgen = get_topogen()
174 if not os.path.isfile(script):
175 if not os.path.isfile(os.path.join(_lt.scriptdir, script)):
701a0192 176 logger.error("Could not find script file: " + script)
177 assert "Could not find script file: " + script
df437d25
LB
178 logger.info("Starting template test: " + script)
179 numEntry = luNumFail()
180
181 if SkipIfFailed and tgen.routers_have_failure():
182 pytest.skip(tgen.errors)
183 if numEntry > 0:
11761ab0
MS
184 if not KeepGoing:
185 pytest.skip("Have %d errors" % numEntry)
df437d25
LB
186
187 if CheckFuncStr != None:
188 check = eval(CheckFuncStr)
189 if check != True:
701a0192 190 pytest.skip("Check function '" + CheckFuncStr + "' returned: " + check)
df437d25 191
8ab91133
LB
192 if CallOnFail != None:
193 CallOnFail = eval(CallOnFail)
194 luInclude(script, CallOnFail)
df437d25
LB
195 numFail = luNumFail() - numEntry
196 if numFail > 0:
197 luShowFail()
198 fatal_error = "%d tests failed" % numFail
11761ab0 199 if not KeepGoing:
701a0192 200 assert (
201 "scripts/cleanup_all.py failed" == "See summary output above"
202 ), fatal_error
203
df437d25
LB
204
205# Memory leak test template
206def test_memory_leak():
207 "Run the memory leak test and report results."
208 tgen = get_topogen()
209 if not tgen.is_memleak_enabled():
701a0192 210 pytest.skip("Memory leak test/report is disabled")
df437d25
LB
211
212 tgen.report_memory_leaks()
213
701a0192 214
215class ltemplateRtrCmd:
89b9abd9
LB
216 def __init__(self):
217 self.resetCounts()
218
701a0192 219 def doCmd(self, tgen, rtr, cmd, checkstr=None):
1b9ebabb 220 logger.info("doCmd: {} {}".format(rtr, cmd))
89b9abd9
LB
221 output = tgen.net[rtr].cmd(cmd).strip()
222 if len(output):
223 self.output += 1
224 if checkstr != None:
225 ret = re.search(checkstr, output)
226 if ret == None:
227 self.nomatch += 1
228 else:
229 self.match += 1
230 return ret
701a0192 231 logger.info("output: " + output)
1b9ebabb
LB
232 else:
233 logger.info("No output")
234 self.none += 1
89b9abd9
LB
235 return None
236
237 def resetCounts(self):
238 self.match = 0
239 self.nomatch = 0
240 self.output = 0
241 self.none = 0
242
243 def getMatch(self):
244 return self.match
245
246 def getNoMatch(self):
247 return self.nomatch
248
249 def getOutput(self):
250 return self.output
251
252 def getNone(self):
253 return self.none
254
701a0192 255
256def ltemplateVersionCheck(
257 vstr, rname="r1", compstr="<", cli=False, kernel="4.9", iproute2=None, mpls=True
258):
89b9abd9
LB
259 tgen = get_topogen()
260 router = tgen.gears[rname]
261
262 if cli:
701a0192 263 logger.info("calling mininet CLI")
89b9abd9 264 tgen.mininet_cli()
701a0192 265 logger.info("exited mininet CLI")
89b9abd9
LB
266
267 if _lt == None:
701a0192 268 ret = "Template not initialized"
89b9abd9
LB
269 return ret
270
271 if _lt.prestarthooksuccess != True:
701a0192 272 ret = "ltemplatePreRouterStartHook failed"
89b9abd9
LB
273 return ret
274
275 if _lt.poststarthooksuccess != True:
701a0192 276 ret = "ltemplatePostRouterStartHook failed"
89b9abd9
LB
277 return ret
278
279 if mpls == True and tgen.hasmpls != True:
701a0192 280 ret = "MPLS not initialized"
89b9abd9
LB
281 return ret
282
283 if kernel != None:
284 krel = platform.release()
285 if topotest.version_cmp(krel, kernel) < 0:
701a0192 286 ret = "Skipping tests, old kernel ({} < {})".format(krel, kernel)
89b9abd9
LB
287 return ret
288
289 if iproute2 != None:
290 if _lt.iproute2Ver == None:
701a0192 291 # collect/log info on iproute2
89b9abd9 292 cc = ltemplateRtrCmd()
701a0192 293 found = cc.doCmd(
48f05b23 294 tgen, rname, "apt-cache policy iproute2", r"Installed: ([\d\.]*)"
701a0192 295 )
89b9abd9
LB
296 if found != None:
297 iproute2Ver = found.group(1)
298 else:
701a0192 299 iproute2Ver = "0-unknown"
300 logger.info("Have iproute2 version=" + iproute2Ver)
89b9abd9
LB
301
302 if topotest.version_cmp(iproute2Ver, iproute2) < 0:
701a0192 303 ret = "Skipping tests, old iproute2 ({} < {})".format(iproute2Ver, iproute2)
89b9abd9
LB
304 return ret
305
306 ret = True
307 try:
308 if router.has_version(compstr, vstr):
701a0192 309 ret = "Skipping tests, old FRR version {} {}".format(compstr, vstr)
89b9abd9
LB
310 return ret
311 except:
312 ret = True
313
314 return ret
315
701a0192 316
317# for testing
318if __name__ == "__main__":
df437d25
LB
319 args = ["-s"] + sys.argv[1:]
320 sys.exit(pytest.main(args))