topotest: add new run_and_expect variant

The new `run_and_expect` variant - called `run_and_expect_type` - tests
the return value type of the test function and optionally the return
value.

Now we can implement tests from test functions that return different
return types.

Signed-off-by: Rafael Zalamena <rzalamena@opensourcerouting.org>
This commit is contained in:
Rafael Zalamena 2019-07-22 13:12:08 -03:00
parent 3857e52f12
commit a6fd124a2a
2 changed files with 122 additions and 0 deletions

View File

@ -0,0 +1,74 @@
#!/usr/bin/env python
#
# test_run_and_expect.py
# Tests for library function: run_and_expect(_type)().
#
# Copyright (c) 2019 by
# Network Device Education Foundation, Inc. ("NetDEF")
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
Tests for the `run_and_expect(_type)()` functions.
"""
import os
import sys
import pytest
# Save the Current Working Directory to find lib files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, '../../'))
# pylint: disable=C0413
from lib.topotest import run_and_expect_type
def test_run_and_expect_type():
"Test basic `run_and_expect_type` functionality."
def return_true():
"Test function that returns `True`."
return True
# Test value success.
success, value = run_and_expect_type(return_true, bool, count=1, wait=0, avalue=True)
assert success is True
assert value is True
# Test value failure.
success, value = run_and_expect_type(return_true, bool, count=1, wait=0, avalue=False)
assert success is False
assert value is True
# Test type success.
success, value = run_and_expect_type(return_true, bool, count=1, wait=0)
assert success is True
assert value is True
# Test type failure.
success, value = run_and_expect_type(return_true, str, count=1, wait=0)
assert success is False
assert value is True
# Test type failure, return correct type.
success, value = run_and_expect_type(return_true, str, count=1, wait=0, avalue=True)
assert success is False
assert value is True
if __name__ == '__main__':
sys.exit(pytest.main())

View File

@ -252,6 +252,54 @@ def run_and_expect(func, what, count=20, wait=3):
return (False, result) return (False, result)
def run_and_expect_type(func, etype, count=20, wait=3, avalue=None):
"""
Run `func` and compare the result with `etype`. Do it for `count` times
waiting `wait` seconds between tries. By default it tries 20 times with
3 seconds delay between tries.
This function is used when you want to test the return type and,
optionally, the return value.
Returns (True, func-return) on success or
(False, func-return) on failure.
"""
start_time = time.time()
func_name = "<unknown>"
if func.__class__ == functools.partial:
func_name = func.func.__name__
else:
func_name = func.__name__
logger.info(
"'{}' polling started (interval {} secs, maximum wait {} secs)".format(
func_name, wait, int(wait * count)))
while count > 0:
result = func()
if not isinstance(result, etype):
logger.debug("Expected result type '{}' got '{}' instead".format(etype, type(result)))
time.sleep(wait)
count -= 1
continue
if etype != type(None) and avalue != None and result != avalue:
logger.debug("Expected value '{}' got '{}' instead".format(avalue, result))
time.sleep(wait)
count -= 1
continue
end_time = time.time()
logger.info("'{}' succeeded after {:.2f} seconds".format(
func_name, end_time - start_time))
return (True, result)
end_time = time.time()
logger.error("'{}' failed after {:.2f} seconds".format(
func_name, end_time - start_time))
return (False, result)
def int2dpid(dpid): def int2dpid(dpid):
"Converting Integer to DPID" "Converting Integer to DPID"