1#!/usr/local/bin/python3.8
2#
3# Copyright 2015-2016 Ettus Research LLC
4# Copyright 2018 Ettus Research, a National Instruments Company
5#
6# SPDX-License-Identifier: GPL-3.0-or-later
7#
8"""
9Device test runner.
10"""
11
12import os
13import sys
14import subprocess
15import argparse
16import logging
17from usrp_probe import get_usrp_list
18
19def setup_parser():
20    """ Set up argparser """
21    parser = argparse.ArgumentParser(description="Test utility for UHD/USRP.")
22    parser.add_argument('--devtest-pattern', '-p', default='*', help='e.g. b2xx')
23    parser.add_argument('--args', '-a', default='', help='Device address arguments')
24    parser.add_argument('--log-dir', '-l', default='.')
25    parser.add_argument('--src-dir', default='.',
26                        help='Directory where the test sources are stored')
27    parser.add_argument('--build-dir', help='Build dir (where examples/ and utils/ are)')
28    parser.add_argument('--build-type', default='Release')
29    parser.add_argument('--python-interp', default=sys.executable)
30    return parser
31
32def setup_env(args):
33    " Add build dir into lib + exe paths, depending on OS "
34    def setup_env_win(env, build_dir, build_type):
35        " Add build dir into paths (Windows)"
36        env['PATH'] = "{build_dir}/lib/{build_type};" + \
37                      "{build_dir}/examples/{build_type};" + \
38                      "{build_dir}/utils/{build_type};{path}".format(
39                          build_dir=build_dir,
40                          build_type=build_type,
41                          path=env.get('PATH', ''))
42        env['LIBPATH'] = "{build_dir}/lib/{build_type};{path}".format(
43            build_dir=build_dir, build_type=build_type, path=env.get('LIBPATH', '')
44        )
45        env['LIB'] = "{build_dir}/lib/{build_type};{path}".format(
46            build_dir=build_dir, build_type=build_type, path=env.get('LIB', '')
47        )
48        env['PYTHONPATH'] = "{build_dir}/python".format(build_dir=build_dir)
49        return env
50    def setup_env_unix(env, build_dir):
51        " Add build dir into paths (Unices)"
52        env['PATH'] = "{build_dir}/examples:{build_dir}/utils:{path}".format(
53            build_dir=build_dir, path=env.get('PATH', '')
54        )
55        env['LD_LIBRARY_PATH'] = "{build_dir}/lib:{path}".format(
56            build_dir=build_dir, path=env.get('LD_LIBRARY_PATH', '')
57        )
58        env['PYTHONPATH'] = "{build_dir}/python".format(build_dir=build_dir)
59        return env
60    def setup_env_osx(env, build_dir):
61        " Add build dir into paths (OS X)"
62        env['PATH'] = "{build_dir}/examples:{build_dir}/utils:{path}".format(
63            build_dir=build_dir, path=env.get('PATH', '')
64        )
65        env['DYLD_LIBRARY_PATH'] = "{build_dir}/lib:{path}".format(
66            build_dir=build_dir, path=env.get('DYLD_LIBRARY_PATH', '')
67        )
68        env['PYTHONPATH'] = "{build_dir}/python".format(build_dir=build_dir)
69        return env
70    ### Go
71    env = os.environ
72    if sys.platform.startswith('linux'):
73        env = setup_env_unix(env, args.build_dir)
74    elif sys.platform.startswith('win'):
75        env = setup_env_win(env, args.build_dir, args.build_type)
76    elif sys.platform.startswith('darwin'):
77        env = setup_env_osx(env, args.build_dir)
78    else:
79        print("Devtest not supported on this platform ({0})."
80              .format(sys.platform))
81        exit(1)
82    return env
83
84def main():
85    " Go, go, go! "
86    args = setup_parser().parse_args()
87    env = setup_env(args)
88    devtest_pattern = "devtest_{p}.py".format(p=args.devtest_pattern)
89    uhd_args_list = get_usrp_list(args.args, env)
90    if len(uhd_args_list) == 0:
91        print("No devices found. Exiting.")
92        exit(1)
93    tests_passed = True
94    for uhd_idx, uhd_info in enumerate(uhd_args_list):
95        print('--- Running all tests for device {dev} ({prod}, Serial: {ser}).'.format(
96            dev=uhd_idx,
97            prod=uhd_info.get('product', 'USRP'),
98            ser=uhd_info.get('serial')
99        ))
100        print('--- This will take some time. Better grab a cup of tea.')
101        sys.stdout.flush()
102        args_str = uhd_info['args']
103        env['_UHD_TEST_ARGS_STR'] = args_str
104        logfile_name = "log{}.log".format(
105            args_str.replace('type=', '_').replace('serial=', '_').replace(',', '')
106        )
107        resultsfile_name = "results{}.log".format(
108            args_str.replace('type=', '_').replace('serial=', '_').replace(',', '')
109        )
110        env['_UHD_TEST_LOGFILE'] = os.path.join(args.log_dir, logfile_name)
111        env['_UHD_TEST_RESULTSFILE'] = os.path.join(args.log_dir, resultsfile_name)
112        env['_UHD_TEST_LOG_LEVEL'] = str(logging.INFO)
113        env['_UHD_TEST_PRINT_LEVEL'] = str(logging.WARNING)
114        env['_UHD_BUILD_DIR'] = str(args.build_dir)
115        env['_UHD_DEVTEST_SRC_DIR'] = str(args.src_dir)
116        proc = subprocess.Popen(
117            [
118                args.python_interp, "-m", "unittest", "discover", "-v",
119                "-s", args.src_dir,
120                "-p", devtest_pattern,
121            ],
122            env=env,
123            stdin=subprocess.PIPE,
124            stdout=subprocess.PIPE,
125            stderr=subprocess.STDOUT,
126            universal_newlines=True
127        )
128        print(proc.communicate()[0])
129        sys.stdout.flush()
130        if proc.returncode != 0:
131            tests_passed = False
132    print('--- Done testing all attached devices.')
133    return tests_passed
134
135if __name__ == "__main__":
136    exit(not main())
137