Skip to content

Commit 2b149b7

Browse files
authored
Merge pull request #2016 from anarkiwi/master
Add lint checking of test directory.
2 parents ed29d43 + 7708f60 commit 2b149b7

8 files changed

+93
-52
lines changed

clib/clib_mininet_test_unit.py

-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
from mininet.net import Mininet
1010

1111
import mininet_test_base
12-
import mininet_test_util
13-
import mininet_test_topo
1412

1513
from tcpdump_helper import TcpdumpHelper
1614
from docker_host import MakeDockerHost

clib/docker_host.py

+32-21
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,6 @@
1313

1414
from mininet_test_util import DEVNULL
1515

16-
def MakeDockerHost(image, prefix='mininet', startup_timeout_ms=None):
17-
18-
class ImageHost(DockerHost):
19-
20-
def __init__(self, *args, **kwargs):
21-
host_name = args[0]
22-
kwargs['image'] = image
23-
assert kwargs['tmpdir'], 'tmpdir required for docker host'
24-
kwargs['tmpdir'] = os.path.join(kwargs['tmpdir'], host_name)
25-
kwargs['prefix'] = prefix
26-
if startup_timeout_ms:
27-
kwargs['startup_timeout_ms'] = startup_timeout_ms
28-
elif 'DOCKER_STARTUP_TIMEOUT_MS' in os.environ:
29-
env_val = os.environ['DOCKER_STARTUP_TIMEOUT_MS']
30-
if env_val:
31-
kwargs['startup_timeout_ms'] = int(env_val)
32-
DockerHost.__init__(self, *args, **kwargs)
33-
return ImageHost
34-
3516

3617
class DockerHost(Host):
3718

@@ -63,12 +44,16 @@ class DockerHost(Host):
6344
pollIn = None
6445
active_log = None
6546

66-
def __init__(self, name, image=None, tmpdir=None, prefix=None, env_vars=[],
67-
vol_maps=[], startup_timeout_ms=STARTUP_TIMEOUT_MS, **kwargs):
47+
def __init__(self, name, image=None, tmpdir=None, prefix=None, env_vars=None,
48+
vol_maps=None, startup_timeout_ms=STARTUP_TIMEOUT_MS, **kwargs):
6849
self.image = image
6950
self.tmpdir = tmpdir
7051
self.prefix = prefix
52+
if env_vars is None:
53+
env_vars = []
7154
self.env_vars = env_vars
55+
if vol_maps is None:
56+
vol_maps = []
7257
self.vol_maps = vol_maps
7358
self.startup_timeout_ms = startup_timeout_ms
7459
Host.__init__(self, name, **kwargs)
@@ -131,6 +116,7 @@ def startShell(self):
131116
self.cmd('unset HISTFILE; stty -echo; set +m') # pylint: disable=no-member
132117

133118
def kill(self, purge=False):
119+
"""Kill a container."""
134120
debug('killing container %s.' % self.container)
135121
if purge:
136122
kill_cmd = ["docker", "rm", "-f", self.container]
@@ -146,6 +132,7 @@ def kill(self, purge=False):
146132
raise
147133

148134
def inspect_pid(self):
135+
"""Return container PID."""
149136
try:
150137
pid_cmd = ["docker", "inspect", "--format={{ .State.Pid }}", self.container]
151138
pid_pipe = self._popen(pid_cmd, stdin=DEVNULL, stdout=PIPE, stderr=STDOUT)
@@ -158,9 +145,11 @@ def inspect_pid(self):
158145
raise
159146

160147
def open_log(self, log_name='activate.log'):
148+
"""Open a log file for writing and return it."""
161149
return open(os.path.join(self.tmpdir, log_name), 'w')
162150

163151
def activate(self, log_name='activate.log'):
152+
"""Active a container and return STDOUT to it."""
164153
assert not self.active_pipe, 'container %s already activated' % self.container
165154
debug('activating container %s.' % self.container)
166155
inspect_cmd = ["docker", "inspect", "--format={{json .Config}}", self.image]
@@ -194,6 +183,7 @@ def activate(self, log_name='activate.log'):
194183
return self.active_pipe
195184

196185
def wait(self):
186+
"""Wait for an activated container to terminate."""
197187
try:
198188
if self.active_pipe_returncode != None:
199189
return self.active_pipe_returncode
@@ -209,6 +199,7 @@ def wait(self):
209199
raise
210200

211201
def read(self, maxbytes=1024):
202+
"""Read from an activated container."""
212203
poll_results = self.pollIn.poll(self.startup_timeout_ms)
213204
data_ready = poll_results and (poll_results[0][1] & select.POLLIN)
214205
assert data_ready, (
@@ -272,3 +263,23 @@ def _popen(self, cmd, **params):
272263
out_fd = pipe.stdout.fileno() if stdout else None
273264
debug('docker pid %d: %s, fd %s' % (pipe.pid, cmd, out_fd))
274265
return pipe
266+
267+
268+
def MakeDockerHost(image, prefix='mininet', startup_timeout_ms=None):
269+
270+
class ImageHost(DockerHost):
271+
272+
def __init__(self, *args, **kwargs):
273+
host_name = args[0]
274+
kwargs['image'] = image
275+
assert kwargs['tmpdir'], 'tmpdir required for docker host'
276+
kwargs['tmpdir'] = os.path.join(kwargs['tmpdir'], host_name)
277+
kwargs['prefix'] = prefix
278+
if startup_timeout_ms:
279+
kwargs['startup_timeout_ms'] = startup_timeout_ms
280+
elif 'DOCKER_STARTUP_TIMEOUT_MS' in os.environ:
281+
env_val = os.environ['DOCKER_STARTUP_TIMEOUT_MS']
282+
if env_val:
283+
kwargs['startup_timeout_ms'] = int(env_val)
284+
DockerHost.__init__(self, *args, **kwargs)
285+
return ImageHost

clib/tcpdump_helper.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
from mininet.log import error, debug
1111

1212

13-
class TcpdumpHelper():
13+
class TcpdumpHelper(object):
14+
"""Run tcpdump on interface, then a list of functions, and return tcpdump's parsed output."""
1415

1516
pipe = None
1617
started = False
@@ -30,8 +31,11 @@ def __init__(self, tcpdump_host, tcpdump_filter, funcs=None,
3031
tcpdump_flags = vflags
3132
tcpdump_flags += ' -c %u' % packets if packets else ''
3233
tcpdump_flags += ' -w %s' % pcap_out if pcap_out else ''
33-
tcpdump_cmd = 'tcpdump -i %s %s -e -n -U %s' % (self.intf_name, tcpdump_flags, tcpdump_filter)
34-
pipe_cmd = mininet_test_util.timeout_soft_cmd(tcpdump_cmd, timeout) if timeout else tcpdump_cmd
34+
tcpdump_cmd = 'tcpdump -i %s %s -e -n -U %s' % (
35+
self.intf_name, tcpdump_flags, tcpdump_filter)
36+
pipe_cmd = tcpdump_cmd
37+
if timeout:
38+
pipe_cmd = mininet_test_util.timeout_soft_cmd(tcpdump_cmd, timeout)
3539

3640
debug(pipe_cmd)
3741
self.pipe = tcpdump_host.popen(
@@ -47,21 +51,25 @@ def __init__(self, tcpdump_host, tcpdump_filter, funcs=None,
4751
self.set_blocking(blocking)
4852

4953
def stream(self):
50-
return self.pipe.stdout if self.pipe else None
54+
"""Return pipe's STDOUT, or None."""
55+
if self.pipe:
56+
return self.pipe.stdout
57+
return None
5158

5259
def set_blocking(self, blocking=True):
53-
fd = self.pipe.stdout.fileno()
54-
flags = fcntl.fcntl(fd, fcntl.F_GETFL)
60+
"""Set blocking on pipe's STDOUT."""
61+
stdout_fd = self.pipe.stdout.fileno()
62+
flags = fcntl.fcntl(stdout_fd, fcntl.F_GETFL)
5563
self.blocking = blocking
5664
if blocking:
5765
flags = flags & ~os.O_NONBLOCK
5866
else:
5967
flags = flags | os.O_NONBLOCK
60-
fcntl.fcntl(fd, fcntl.F_SETFL, flags)
68+
fcntl.fcntl(stdout_fd, fcntl.F_SETFL, flags)
6169

6270
def execute(self):
71+
"""Run the helper and accumulate tcpdump output."""
6372
tcpdump_txt = ''
64-
# Initialize with meaningless truthy value.
6573
line = ' '
6674
while line:
6775
tcpdump_txt += line.strip()
@@ -70,6 +78,7 @@ def execute(self):
7078
return tcpdump_txt
7179

7280
def terminate(self):
81+
"""Terminate the helper."""
7382
if not self.pipe:
7483
return -1
7584

@@ -109,6 +118,7 @@ def readline(self):
109118
return line
110119

111120
def next_line(self):
121+
"""Retrieve next line from helper."""
112122
while True:
113123
try:
114124
line = self.readline()

git-hook/pre-commit

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ BASE=`dirname $0`/../..
1414
cd $BASE || exit 1
1515
BASE=`pwd`
1616
for mypy_file in faucet/faucet.py faucet/gauge.py ; do
17-
PYTHONPATH=$BASE mypy --ignore-missing-imports $mypy_file || exit 1
17+
PYTHONPATH=$BASE:$BASE/clib mypy --ignore-missing-imports $mypy_file || exit 1
1818
done
1919
cd tests
2020
./test_coverage.sh || exit 1

tests/test_config_gauge.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@ def tearDown(self):
4646
shutil.rmtree(self.tmpdir)
4747

4848
def conf_file_name(self, faucet=False):
49+
"""Return path for configuration file."""
4950
if faucet:
5051
return os.path.join(self.tmpdir, 'faucet.yaml')
51-
else:
52-
return os.path.join(self.tmpdir, 'gauge.yaml')
52+
return os.path.join(self.tmpdir, 'gauge.yaml')
5353

5454
def create_config_files(self, config, faucet_config=None):
5555
"""Returns file path to file containing the config parameter."""
@@ -65,10 +65,11 @@ def create_config_files(self, config, faucet_config=None):
6565
return (gauge_file_name, faucet_file_name)
6666

6767
def get_config(self, conf_suffix):
68+
"""Return config file together with header template."""
6869
return self.GAUGE_CONFIG_HEADER + conf_suffix
6970

70-
7171
def test_all_dps(self):
72+
"""Test config applies for all DPs."""
7273
GAUGE_CONF = """
7374
watchers:
7475
port_stats_poller:
@@ -81,7 +82,7 @@ def test_all_dps(self):
8182
type: 'prometheus'
8283
"""
8384
conf = self.get_config(GAUGE_CONF)
84-
gauge_file, faucet_file = self.create_config_files(conf)
85+
gauge_file, _ = self.create_config_files(conf)
8586
watcher_confs = cp.watcher_parser(gauge_file, 'gauge_config_test', None)
8687
self.assertEqual(len(watcher_confs), 2, 'failed to create config for each dp')
8788
for watcher_conf in watcher_confs:
@@ -91,6 +92,7 @@ def test_all_dps(self):
9192
self.assertEqual(watcher_conf.db_type, 'prometheus', msg)
9293

9394
def test_no_faucet_config_file(self):
95+
"""Test missing FAUCET config."""
9496
GAUGE_CONF = """
9597
faucet:
9698
dps:
@@ -111,7 +113,7 @@ def test_no_faucet_config_file(self):
111113
prometheus:
112114
type: 'prometheus'
113115
"""
114-
gauge_file, faucet_file = self.create_config_files(GAUGE_CONF, '')
116+
gauge_file, _ = self.create_config_files(GAUGE_CONF, '')
115117
watcher_conf = cp.watcher_parser(
116118
gauge_file, 'gauge_config_test', None)[0]
117119
msg = 'failed to create watcher correctly when dps configured in gauge.yaml'

tests/test_main.py

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def test_parse_args(self):
3434
self.assertTrue(parse_args(['--verbose']).verbose)
3535

3636
def test_build_ryu_args(self):
37+
"""Test build_ryu_args()."""
3738
self.assertTrue(build_ryu_args(['faucet', '--use-stderr', '--use-syslog', '--verbose']))
3839
self.assertTrue(build_ryu_args(['gauge', '--use-stderr', '--use-syslog', '--verbose']))
3940
self.assertFalse(build_ryu_args(['faucet', '--version']))

tests/test_min_pylint.sh

+12-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
#!/bin/bash
22

33
MINRATING="9.2"
4-
SRC_FILES=`dirname $0`"/../faucet/[a-z]*.py"
4+
FAUCETHOME=`dirname $0`"/.."
5+
PYTHONPATH=$FAUCETHOME:$FAUCETHOME/clib
56

7+
for src_dir in clib faucet tests ; do
8+
src_files=$FAUCETHOME/$src_dir/[a-z]*.py
69

7-
for f in $SRC_FILES ; do
8-
RATING=`pylint $f | grep -ohE "rated at [0-9\.]+" | sed "s/rated at //g"`
9-
echo pylint $f: $RATING
10-
if [ $(bc <<< "$RATING < $MINRATING") -eq 1 ] ; then
11-
echo "$RATING below min ($MINRATING)"
12-
exit 1
13-
fi
10+
for f in $src_files ; do
11+
rating=`PYTHONPATH=$PYTHONPATH pylint --rcfile=/dev/null $f | grep -ohE "rated at [0-9\.]+" | sed "s/rated at //g"`
12+
echo pylint $f: $rating
13+
if [ $(bc <<< "$rating < $MINRATING") -eq 1 ] ; then
14+
echo "$rating below min ($MINRATING)"
15+
exit 1
16+
fi
17+
done
1418
done
1519

1620
exit 0

tests/test_valve.py

+22-7
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ def serialize(layers):
304304

305305

306306
class ValveTestBases:
307+
"""Insulate test base classes from unittest so we can reuse base clases."""
307308

308309

309310
class ValveTestSmall(unittest.TestCase):
@@ -480,6 +481,7 @@ def learn_hosts(self):
480481
'vid': 0x200})
481482

482483
def verify_expiry(self):
484+
"""Verify FIB resolution attempts expire."""
483485
now = time.time()
484486
for _ in range(self.valve.dp.max_host_fib_retry_count + 1):
485487
now += (self.valve.dp.timeout * 2)
@@ -532,8 +534,9 @@ def _verify_flood_to_port(match, port, valve_vlan, port_number=None):
532534
if port == in_port:
533535
self.assertNotEqual(
534536
combinatorial_port_flood, output,
535-
msg='flooding to in_port (%s) not compatible with flood mode (%s)' % (
536-
output, combinatorial_port_flood))
537+
msg=('flooding to in_port (%s) not '
538+
'compatible with flood mode (%s)') % (
539+
output, combinatorial_port_flood))
537540
continue
538541
self.assertTrue(
539542
output,
@@ -579,8 +582,11 @@ def rcv_packet(self, port, vid, match):
579582
'of_packet_ins')
580583
rcv_packet_ofmsgs = self.last_flows_to_dp[self.DP_ID]
581584
self.table.apply_ofmsgs(rcv_packet_ofmsgs)
582-
for valve_service in ('resolve_gateways', 'advertise', 'send_lldp_beacons', 'state_expire'):
583-
ofmsgs = self.valves_manager.valve_flow_services(now, valve_service)
585+
for valve_service in (
586+
'resolve_gateways', 'advertise',
587+
'send_lldp_beacons', 'state_expire'):
588+
ofmsgs = self.valves_manager.valve_flow_services(
589+
now, valve_service)
584590
if ofmsgs:
585591
self.table.apply_ofmsgs(ofmsgs)
586592
self.valves_manager.update_metrics(now)
@@ -624,9 +630,13 @@ def test_oferror(self):
624630

625631
def test_switch_features(self):
626632
"""Test switch features handler."""
627-
self.assertTrue(isinstance(self.valve, TfmValve), msg=type(self.valve))
633+
self.assertTrue(
634+
isinstance(self.valve, TfmValve),
635+
msg=type(self.valve))
628636
features_flows = self.valve.switch_features(None)
629-
tfm_flows = [flow for flow in features_flows if isinstance(flow, valve_of.parser.OFPTableFeaturesStatsRequest)]
637+
tfm_flows = [
638+
flow for flow in features_flows if isinstance(
639+
flow, valve_of.parser.OFPTableFeaturesStatsRequest)]
630640
# TODO: verify TFM content.
631641
self.assertTrue(tfm_flows)
632642

@@ -1255,6 +1265,7 @@ def test_ofdescstats_handler(self):
12551265

12561266

12571267
class ValveTestCase(ValveTestBases.ValveTestBig):
1268+
"""Run complete set of basic tests."""
12581269

12591270
pass
12601271

@@ -1391,6 +1402,7 @@ def setUp(self):
13911402
self.setup_valve(CONFIG)
13921403

13931404
def test_stack_learn(self):
1405+
"""Test host learning on stack root."""
13941406
self.rcv_packet(1, 0x300, {
13951407
'eth_src': self.P1_V300_MAC,
13961408
'eth_dst': self.UNKNOWN_MAC,
@@ -1424,6 +1436,7 @@ def setUp(self):
14241436
self.setup_valve(CONFIG)
14251437

14261438
def test_stack_learn(self):
1439+
"""Test host learning on non-root switch."""
14271440
self.rcv_packet(1, 0x300, {
14281441
'eth_src': self.P1_V300_MAC,
14291442
'eth_dst': self.UNKNOWN_MAC,
@@ -1665,6 +1678,7 @@ def setUp(self):
16651678
self.setup_valve(self.CONFIG)
16661679

16671680
def test_lacp(self):
1681+
"""Test LACP comes up."""
16681682
# TODO: verify LACP state
16691683
self.rcv_packet(1, 0, {
16701684
'actor_system': '0e:00:00:00:00:02',
@@ -1768,7 +1782,8 @@ def setUp(self):
17681782
class RyuAppSmokeTest(unittest.TestCase):
17691783
"""Test bare instantiation of controller classes."""
17701784

1771-
def _fake_dp(self):
1785+
@staticmethod
1786+
def _fake_dp():
17721787
datapath = namedtuple('datapath', 'id')
17731788
datapath.id = 0
17741789
datapath.close = lambda: None

0 commit comments

Comments
 (0)