1import subprocess
2import fnmatch
3import os
4import sys
5import psutil
6import socket
7
8def network_interface_should_exist(name):
9    if name not in psutil.net_if_addrs():
10        raise Exception('Network interface {} not found.'.format(name))
11
12def network_interface_should_be_up(name):
13    network_interface_should_exist(name)
14    if sys.platform == "linux": # psutil marks tap interface as down, erroneously
15        proc = subprocess.Popen(['ip', 'addr', 'show', name, 'up'], stdout=subprocess.PIPE)
16        (output, err) = proc.communicate()
17        exit_code = proc.wait()
18        if exit_code != 0 or len(output) == 0:
19            raise Exception('Network interface {} is not up.'.format(name))
20    else:
21        if not (name in psutil.net_if_stats() and psutil.net_if_stats()[name].isup):
22            raise Exception('Network interface {} is not up.'.format(name))
23
24def network_interface_should_have_address(name, address):
25    network_interface_should_exist(name)
26    if not (sys.platform == "win32" or sys.platform == "cygwin"):
27        # On Windows, the status of TAP interface depends on the
28        # signals sent to the device file using the DeviceIoControl
29        # function from Win32 API. For this reason it is the Renode
30        # that sets the up/down status instead - and as such for the
31        # automated testing this check is skipped on Windows.
32        network_interface_should_be_up(name)
33    ifaddresses = psutil.net_if_addrs()[name]
34    addresses = []
35    for addr in ifaddresses:
36        if addr.family == socket.AF_INET:
37            addresses.append(addr.address)
38    if address not in addresses:
39        raise Exception('Network interface {0} does not have address {1}.'.format(name, address))
40
41def list_files_in_directory_recursively(directory_name, pattern, excludes=None):
42    files = []
43    for root, dirnames, filenames in os.walk(directory_name, topdown=True):
44        if excludes and os.path.basename(root) in excludes:
45            # this is an `os.walk` trick: when using `topdown=True`
46            # you can modify `dirnames` in place to tell `os.walk`
47            # which folders to visit; in this case - visit nothing
48            dirnames[:] = []
49            continue
50
51        for filename in fnmatch.filter(filenames, pattern):
52            files.append(os.path.join(root, filename))
53    return files
54