xref: /unit/test/conftest.py (revision 1654)
11596Szelenkov@nginx.comimport fcntl
21596Szelenkov@nginx.comimport os
31596Szelenkov@nginx.comimport platform
41635Szelenkov@nginx.comimport re
51621Szelenkov@nginx.comimport shutil
61596Szelenkov@nginx.comimport signal
7*1654Szelenkov@nginx.comimport socket
81596Szelenkov@nginx.comimport stat
91596Szelenkov@nginx.comimport subprocess
101596Szelenkov@nginx.comimport sys
111596Szelenkov@nginx.comimport tempfile
121596Szelenkov@nginx.comimport time
13*1654Szelenkov@nginx.comfrom multiprocessing import Process
141596Szelenkov@nginx.com
151635Szelenkov@nginx.comimport pytest
161635Szelenkov@nginx.com
171621Szelenkov@nginx.comfrom unit.check.go import check_go
181621Szelenkov@nginx.comfrom unit.check.node import check_node
191621Szelenkov@nginx.comfrom unit.check.tls import check_openssl
201621Szelenkov@nginx.com
211596Szelenkov@nginx.com
221596Szelenkov@nginx.comdef pytest_addoption(parser):
231596Szelenkov@nginx.com    parser.addoption(
241596Szelenkov@nginx.com        "--detailed",
251596Szelenkov@nginx.com        default=False,
261596Szelenkov@nginx.com        action="store_true",
271596Szelenkov@nginx.com        help="Detailed output for tests",
281596Szelenkov@nginx.com    )
291596Szelenkov@nginx.com    parser.addoption(
301596Szelenkov@nginx.com        "--print_log",
311596Szelenkov@nginx.com        default=False,
321596Szelenkov@nginx.com        action="store_true",
331596Szelenkov@nginx.com        help="Print unit.log to stdout in case of errors",
341596Szelenkov@nginx.com    )
351596Szelenkov@nginx.com    parser.addoption(
361596Szelenkov@nginx.com        "--save_log",
371596Szelenkov@nginx.com        default=False,
381596Szelenkov@nginx.com        action="store_true",
391596Szelenkov@nginx.com        help="Save unit.log after the test execution",
401596Szelenkov@nginx.com    )
411596Szelenkov@nginx.com    parser.addoption(
421596Szelenkov@nginx.com        "--unsafe",
431596Szelenkov@nginx.com        default=False,
441596Szelenkov@nginx.com        action="store_true",
451596Szelenkov@nginx.com        help="Run unsafe tests",
461596Szelenkov@nginx.com    )
471596Szelenkov@nginx.com
481596Szelenkov@nginx.com
491596Szelenkov@nginx.comunit_instance = {}
50*1654Szelenkov@nginx.com_processes = []
511596Szelenkov@nginx.comoption = None
521596Szelenkov@nginx.com
531596Szelenkov@nginx.com
541596Szelenkov@nginx.comdef pytest_configure(config):
551596Szelenkov@nginx.com    global option
561596Szelenkov@nginx.com    option = config.option
571596Szelenkov@nginx.com
581596Szelenkov@nginx.com    option.generated_tests = {}
591596Szelenkov@nginx.com    option.current_dir = os.path.abspath(
601596Szelenkov@nginx.com        os.path.join(os.path.dirname(__file__), os.pardir)
611596Szelenkov@nginx.com    )
621596Szelenkov@nginx.com    option.test_dir = option.current_dir + '/test'
631596Szelenkov@nginx.com    option.architecture = platform.architecture()[0]
641596Szelenkov@nginx.com    option.system = platform.system()
651596Szelenkov@nginx.com
661596Szelenkov@nginx.com    # set stdout to non-blocking
671596Szelenkov@nginx.com
681596Szelenkov@nginx.com    if option.detailed or option.print_log:
691596Szelenkov@nginx.com        fcntl.fcntl(sys.stdout.fileno(), fcntl.F_SETFL, 0)
701596Szelenkov@nginx.com
711596Szelenkov@nginx.com
72*1654Szelenkov@nginx.comdef skip_alert(*alerts):
73*1654Szelenkov@nginx.com    option.skip_alerts.extend(alerts)
74*1654Szelenkov@nginx.com
75*1654Szelenkov@nginx.com
761596Szelenkov@nginx.comdef pytest_generate_tests(metafunc):
771596Szelenkov@nginx.com    cls = metafunc.cls
781596Szelenkov@nginx.com    if not hasattr(cls, 'application_type'):
791596Szelenkov@nginx.com        return
801596Szelenkov@nginx.com
811596Szelenkov@nginx.com    type = cls.application_type
821596Szelenkov@nginx.com
831611Smax.romanov@nginx.com    def generate_tests(versions):
841611Smax.romanov@nginx.com        metafunc.fixturenames.append('tmp_ct')
851630Smax.romanov@nginx.com        metafunc.parametrize('tmp_ct', versions)
861611Smax.romanov@nginx.com
871630Smax.romanov@nginx.com        for version in versions:
881611Smax.romanov@nginx.com            option.generated_tests[
891630Smax.romanov@nginx.com                metafunc.function.__name__ + '[{}]'.format(version)
901611Smax.romanov@nginx.com            ] = (type + ' ' + version)
911611Smax.romanov@nginx.com
921596Szelenkov@nginx.com    # take available module from option and generate tests for each version
931596Szelenkov@nginx.com
941611Smax.romanov@nginx.com    for module, prereq_version in cls.prerequisites['modules'].items():
951596Szelenkov@nginx.com        if module in option.available['modules']:
961596Szelenkov@nginx.com            available_versions = option.available['modules'][module]
971596Szelenkov@nginx.com
981596Szelenkov@nginx.com            if prereq_version == 'all':
991611Smax.romanov@nginx.com                generate_tests(available_versions)
1001596Szelenkov@nginx.com
1011596Szelenkov@nginx.com            elif prereq_version == 'any':
1021596Szelenkov@nginx.com                option.generated_tests[metafunc.function.__name__] = (
1031596Szelenkov@nginx.com                    type + ' ' + available_versions[0]
1041596Szelenkov@nginx.com                )
1051611Smax.romanov@nginx.com            elif callable(prereq_version):
1061611Smax.romanov@nginx.com                generate_tests(
1071611Smax.romanov@nginx.com                    list(filter(prereq_version, available_versions))
1081611Smax.romanov@nginx.com                )
1091611Smax.romanov@nginx.com
1101596Szelenkov@nginx.com            else:
1111611Smax.romanov@nginx.com                raise ValueError(
1121611Smax.romanov@nginx.com                    """
1131611Smax.romanov@nginx.comUnexpected prerequisite version "%s" for module "%s" in %s.
1141611Smax.romanov@nginx.com'all', 'any' or callable expected."""
1151611Smax.romanov@nginx.com                    % (str(prereq_version), module, str(cls))
1161611Smax.romanov@nginx.com                )
1171596Szelenkov@nginx.com
1181596Szelenkov@nginx.com
1191596Szelenkov@nginx.comdef pytest_sessionstart(session):
1201596Szelenkov@nginx.com    option.available = {'modules': {}, 'features': {}}
1211596Szelenkov@nginx.com
1221596Szelenkov@nginx.com    unit = unit_run()
1231596Szelenkov@nginx.com
1241596Szelenkov@nginx.com    # read unit.log
1251596Szelenkov@nginx.com
1261596Szelenkov@nginx.com    for i in range(50):
1271596Szelenkov@nginx.com        with open(unit['temp_dir'] + '/unit.log', 'r') as f:
1281596Szelenkov@nginx.com            log = f.read()
1291596Szelenkov@nginx.com            m = re.search('controller started', log)
1301596Szelenkov@nginx.com
1311596Szelenkov@nginx.com            if m is None:
1321596Szelenkov@nginx.com                time.sleep(0.1)
1331596Szelenkov@nginx.com            else:
1341596Szelenkov@nginx.com                break
1351596Szelenkov@nginx.com
1361596Szelenkov@nginx.com    if m is None:
137*1654Szelenkov@nginx.com        _print_log(log)
1381596Szelenkov@nginx.com        exit("Unit is writing log too long")
1391596Szelenkov@nginx.com
1401596Szelenkov@nginx.com    # discover available modules from unit.log
1411596Szelenkov@nginx.com
1421596Szelenkov@nginx.com    for module in re.findall(r'module: ([a-zA-Z]+) (.*) ".*"$', log, re.M):
1431596Szelenkov@nginx.com        if module[0] not in option.available['modules']:
1441596Szelenkov@nginx.com            option.available['modules'][module[0]] = [module[1]]
1451596Szelenkov@nginx.com        else:
1461596Szelenkov@nginx.com            option.available['modules'][module[0]].append(module[1])
1471596Szelenkov@nginx.com
1481621Szelenkov@nginx.com    # discover modules from check
1491621Szelenkov@nginx.com
1501621Szelenkov@nginx.com    option.available['modules']['openssl'] = check_openssl(unit['unitd'])
1511621Szelenkov@nginx.com    option.available['modules']['go'] = check_go(
1521621Szelenkov@nginx.com        option.current_dir, unit['temp_dir'], option.test_dir
1531621Szelenkov@nginx.com    )
1541621Szelenkov@nginx.com    option.available['modules']['node'] = check_node(option.current_dir)
1551621Szelenkov@nginx.com
1561621Szelenkov@nginx.com    # remove None values
1571621Szelenkov@nginx.com
1581621Szelenkov@nginx.com    option.available['modules'] = {
1591621Szelenkov@nginx.com        k: v for k, v in option.available['modules'].items() if v is not None
1601621Szelenkov@nginx.com    }
1611621Szelenkov@nginx.com
1621596Szelenkov@nginx.com    unit_stop()
1631596Szelenkov@nginx.com
164*1654Szelenkov@nginx.com    shutil.rmtree(unit_instance['temp_dir'])
1651596Szelenkov@nginx.com
166*1654Szelenkov@nginx.com
167*1654Szelenkov@nginx.com@pytest.hookimpl(tryfirst=True, hookwrapper=True)
168*1654Szelenkov@nginx.comdef pytest_runtest_makereport(item, call):
169*1654Szelenkov@nginx.com    # execute all other hooks to obtain the report object
170*1654Szelenkov@nginx.com    outcome = yield
171*1654Szelenkov@nginx.com    rep = outcome.get_result()
172*1654Szelenkov@nginx.com
173*1654Szelenkov@nginx.com    # set a report attribute for each phase of a call, which can
174*1654Szelenkov@nginx.com    # be "setup", "call", "teardown"
175*1654Szelenkov@nginx.com
176*1654Szelenkov@nginx.com    setattr(item, "rep_" + rep.when, rep)
177*1654Szelenkov@nginx.com
178*1654Szelenkov@nginx.com
179*1654Szelenkov@nginx.com@pytest.fixture(autouse=True)
180*1654Szelenkov@nginx.comdef run(request):
181*1654Szelenkov@nginx.com    unit = unit_run()
182*1654Szelenkov@nginx.com    option.temp_dir = unit['temp_dir']
183*1654Szelenkov@nginx.com
1841596Szelenkov@nginx.com    option.skip_alerts = [
1851596Szelenkov@nginx.com        r'read signalfd\(4\) failed',
1861596Szelenkov@nginx.com        r'sendmsg.+failed',
1871596Szelenkov@nginx.com        r'recvmsg.+failed',
1881596Szelenkov@nginx.com    ]
1891596Szelenkov@nginx.com    option.skip_sanitizer = False
1901596Szelenkov@nginx.com
191*1654Szelenkov@nginx.com    yield
192*1654Szelenkov@nginx.com
193*1654Szelenkov@nginx.com    # stop unit
194*1654Szelenkov@nginx.com
195*1654Szelenkov@nginx.com    error = unit_stop()
196*1654Szelenkov@nginx.com
197*1654Szelenkov@nginx.com    if error:
198*1654Szelenkov@nginx.com        _print_log()
199*1654Szelenkov@nginx.com
200*1654Szelenkov@nginx.com    assert error is None, 'stop unit'
201*1654Szelenkov@nginx.com
202*1654Szelenkov@nginx.com    # stop all processes
203*1654Szelenkov@nginx.com
204*1654Szelenkov@nginx.com    error = stop_processes()
205*1654Szelenkov@nginx.com
206*1654Szelenkov@nginx.com    if error:
207*1654Szelenkov@nginx.com        _print_log()
208*1654Szelenkov@nginx.com
209*1654Szelenkov@nginx.com    assert error is None, 'stop unit'
210*1654Szelenkov@nginx.com
211*1654Szelenkov@nginx.com    # check unit.log for alerts
212*1654Szelenkov@nginx.com
213*1654Szelenkov@nginx.com    _check_alerts()
214*1654Szelenkov@nginx.com
215*1654Szelenkov@nginx.com    # print unit.log in case of error
216*1654Szelenkov@nginx.com
217*1654Szelenkov@nginx.com    if request.node.rep_call.failed:
218*1654Szelenkov@nginx.com        _print_log()
219*1654Szelenkov@nginx.com
220*1654Szelenkov@nginx.com    # remove unit.log
221*1654Szelenkov@nginx.com
222*1654Szelenkov@nginx.com    if not option.save_log:
223*1654Szelenkov@nginx.com        shutil.rmtree(unit['temp_dir'])
224*1654Szelenkov@nginx.com
2251596Szelenkov@nginx.comdef unit_run():
2261596Szelenkov@nginx.com    global unit_instance
2271596Szelenkov@nginx.com    build_dir = option.current_dir + '/build'
2281596Szelenkov@nginx.com    unitd = build_dir + '/unitd'
2291596Szelenkov@nginx.com
2301596Szelenkov@nginx.com    if not os.path.isfile(unitd):
2311596Szelenkov@nginx.com        exit('Could not find unit')
2321596Szelenkov@nginx.com
2331596Szelenkov@nginx.com    temp_dir = tempfile.mkdtemp(prefix='unit-test-')
2341596Szelenkov@nginx.com    public_dir(temp_dir)
2351596Szelenkov@nginx.com
2361596Szelenkov@nginx.com    if oct(stat.S_IMODE(os.stat(build_dir).st_mode)) != '0o777':
2371596Szelenkov@nginx.com        public_dir(build_dir)
2381596Szelenkov@nginx.com
2391596Szelenkov@nginx.com    os.mkdir(temp_dir + '/state')
2401596Szelenkov@nginx.com
2411596Szelenkov@nginx.com    with open(temp_dir + '/unit.log', 'w') as log:
2421596Szelenkov@nginx.com        unit_instance['process'] = subprocess.Popen(
2431596Szelenkov@nginx.com            [
2441596Szelenkov@nginx.com                unitd,
2451596Szelenkov@nginx.com                '--no-daemon',
2461596Szelenkov@nginx.com                '--modules',
2471596Szelenkov@nginx.com                build_dir,
2481596Szelenkov@nginx.com                '--state',
2491596Szelenkov@nginx.com                temp_dir + '/state',
2501596Szelenkov@nginx.com                '--pid',
2511596Szelenkov@nginx.com                temp_dir + '/unit.pid',
2521596Szelenkov@nginx.com                '--log',
2531596Szelenkov@nginx.com                temp_dir + '/unit.log',
2541596Szelenkov@nginx.com                '--control',
2551596Szelenkov@nginx.com                'unix:' + temp_dir + '/control.unit.sock',
2561596Szelenkov@nginx.com                '--tmp',
2571596Szelenkov@nginx.com                temp_dir,
2581596Szelenkov@nginx.com            ],
2591596Szelenkov@nginx.com            stderr=log,
2601596Szelenkov@nginx.com        )
2611596Szelenkov@nginx.com
2621596Szelenkov@nginx.com    if not waitforfiles(temp_dir + '/control.unit.sock'):
2631596Szelenkov@nginx.com        _print_log()
2641596Szelenkov@nginx.com        exit('Could not start unit')
2651596Szelenkov@nginx.com
2661596Szelenkov@nginx.com    unit_instance['temp_dir'] = temp_dir
2671596Szelenkov@nginx.com    unit_instance['log'] = temp_dir + '/unit.log'
2681596Szelenkov@nginx.com    unit_instance['control_sock'] = temp_dir + '/control.unit.sock'
2691596Szelenkov@nginx.com    unit_instance['unitd'] = unitd
2701596Szelenkov@nginx.com
2711596Szelenkov@nginx.com    return unit_instance
2721596Szelenkov@nginx.com
2731596Szelenkov@nginx.com
2741596Szelenkov@nginx.comdef unit_stop():
2751596Szelenkov@nginx.com    p = unit_instance['process']
2761596Szelenkov@nginx.com
2771596Szelenkov@nginx.com    if p.poll() is not None:
2781596Szelenkov@nginx.com        return
2791596Szelenkov@nginx.com
2801596Szelenkov@nginx.com    p.send_signal(signal.SIGQUIT)
2811596Szelenkov@nginx.com
2821596Szelenkov@nginx.com    try:
2831596Szelenkov@nginx.com        retcode = p.wait(15)
2841596Szelenkov@nginx.com        if retcode:
2851596Szelenkov@nginx.com            return 'Child process terminated with code ' + str(retcode)
2861596Szelenkov@nginx.com    except:
2871596Szelenkov@nginx.com        p.kill()
2881596Szelenkov@nginx.com        return 'Could not terminate unit'
2891596Szelenkov@nginx.com
2901596Szelenkov@nginx.comdef public_dir(path):
2911596Szelenkov@nginx.com    os.chmod(path, 0o777)
2921596Szelenkov@nginx.com
2931596Szelenkov@nginx.com    for root, dirs, files in os.walk(path):
2941596Szelenkov@nginx.com        for d in dirs:
2951596Szelenkov@nginx.com            os.chmod(os.path.join(root, d), 0o777)
2961596Szelenkov@nginx.com        for f in files:
2971596Szelenkov@nginx.com            os.chmod(os.path.join(root, f), 0o777)
2981596Szelenkov@nginx.com
2991596Szelenkov@nginx.comdef waitforfiles(*files):
3001596Szelenkov@nginx.com    for i in range(50):
3011596Szelenkov@nginx.com        wait = False
3021596Szelenkov@nginx.com        ret = False
3031596Szelenkov@nginx.com
3041596Szelenkov@nginx.com        for f in files:
3051596Szelenkov@nginx.com            if not os.path.exists(f):
3061596Szelenkov@nginx.com                wait = True
3071596Szelenkov@nginx.com                break
3081596Szelenkov@nginx.com
3091596Szelenkov@nginx.com        if wait:
3101596Szelenkov@nginx.com            time.sleep(0.1)
3111596Szelenkov@nginx.com
3121596Szelenkov@nginx.com        else:
3131596Szelenkov@nginx.com            ret = True
3141596Szelenkov@nginx.com            break
3151596Szelenkov@nginx.com
3161596Szelenkov@nginx.com    return ret
3171596Szelenkov@nginx.com
3181596Szelenkov@nginx.com
3191596Szelenkov@nginx.com
320*1654Szelenkov@nginx.comdef _check_alerts(path=None):
321*1654Szelenkov@nginx.com    if path is None:
322*1654Szelenkov@nginx.com        path = unit_instance['log']
3231596Szelenkov@nginx.com
324*1654Szelenkov@nginx.com    with open(path, 'r', encoding='utf-8', errors='ignore') as f:
325*1654Szelenkov@nginx.com        log = f.read()
326*1654Szelenkov@nginx.com
3271596Szelenkov@nginx.com    found = False
3281596Szelenkov@nginx.com
3291596Szelenkov@nginx.com    alerts = re.findall(r'.+\[alert\].+', log)
3301596Szelenkov@nginx.com
3311596Szelenkov@nginx.com    if alerts:
3321596Szelenkov@nginx.com        print('All alerts/sanitizer errors found in log:')
3331596Szelenkov@nginx.com        [print(alert) for alert in alerts]
3341596Szelenkov@nginx.com        found = True
3351596Szelenkov@nginx.com
3361596Szelenkov@nginx.com    if option.skip_alerts:
3371596Szelenkov@nginx.com        for skip in option.skip_alerts:
3381596Szelenkov@nginx.com            alerts = [al for al in alerts if re.search(skip, al) is None]
3391596Szelenkov@nginx.com
3401596Szelenkov@nginx.com    if alerts:
341*1654Szelenkov@nginx.com        _print_log(log)
3421596Szelenkov@nginx.com        assert not alerts, 'alert(s)'
3431596Szelenkov@nginx.com
3441596Szelenkov@nginx.com    if not option.skip_sanitizer:
3451596Szelenkov@nginx.com        sanitizer_errors = re.findall('.+Sanitizer.+', log)
3461596Szelenkov@nginx.com
3471596Szelenkov@nginx.com        if sanitizer_errors:
348*1654Szelenkov@nginx.com            _print_log(log)
3491596Szelenkov@nginx.com            assert not sanitizer_errors, 'sanitizer error(s)'
3501596Szelenkov@nginx.com
3511596Szelenkov@nginx.com    if found:
3521596Szelenkov@nginx.com        print('skipped.')
3531596Szelenkov@nginx.com
3541596Szelenkov@nginx.com
355*1654Szelenkov@nginx.comdef _print_log(data=None):
356*1654Szelenkov@nginx.com    path = unit_instance['log']
3571596Szelenkov@nginx.com
3581621Szelenkov@nginx.com    print('Path to unit.log:\n' + path + '\n')
3591596Szelenkov@nginx.com
3601596Szelenkov@nginx.com    if option.print_log:
3611596Szelenkov@nginx.com        os.set_blocking(sys.stdout.fileno(), True)
3621596Szelenkov@nginx.com        sys.stdout.flush()
3631596Szelenkov@nginx.com
3641596Szelenkov@nginx.com        if data is None:
3651621Szelenkov@nginx.com            with open(path, 'r', encoding='utf-8', errors='ignore') as f:
3661596Szelenkov@nginx.com                shutil.copyfileobj(f, sys.stdout)
3671596Szelenkov@nginx.com        else:
3681596Szelenkov@nginx.com            sys.stdout.write(data)
3691596Szelenkov@nginx.com
3701596Szelenkov@nginx.com
371*1654Szelenkov@nginx.comdef run_process(target, *args):
372*1654Szelenkov@nginx.com    global _processes
373*1654Szelenkov@nginx.com
374*1654Szelenkov@nginx.com    process = Process(target=target, args=args)
375*1654Szelenkov@nginx.com    process.start()
376*1654Szelenkov@nginx.com
377*1654Szelenkov@nginx.com    _processes.append(process)
378*1654Szelenkov@nginx.com
379*1654Szelenkov@nginx.comdef stop_processes():
380*1654Szelenkov@nginx.com    if not _processes:
381*1654Szelenkov@nginx.com        return
382*1654Szelenkov@nginx.com
383*1654Szelenkov@nginx.com    fail = False
384*1654Szelenkov@nginx.com    for process in _processes:
385*1654Szelenkov@nginx.com        if process.is_alive():
386*1654Szelenkov@nginx.com            process.terminate()
387*1654Szelenkov@nginx.com            process.join(timeout=15)
388*1654Szelenkov@nginx.com
389*1654Szelenkov@nginx.com            if process.is_alive():
390*1654Szelenkov@nginx.com                fail = True
391*1654Szelenkov@nginx.com
392*1654Szelenkov@nginx.com    if fail:
393*1654Szelenkov@nginx.com        return 'Fail to stop process(es)'
394*1654Szelenkov@nginx.com
395*1654Szelenkov@nginx.com
396*1654Szelenkov@nginx.comdef waitforsocket(port):
397*1654Szelenkov@nginx.com    ret = False
398*1654Szelenkov@nginx.com
399*1654Szelenkov@nginx.com    for i in range(50):
400*1654Szelenkov@nginx.com        try:
401*1654Szelenkov@nginx.com            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
402*1654Szelenkov@nginx.com            sock.connect(('127.0.0.1', port))
403*1654Szelenkov@nginx.com            ret = True
404*1654Szelenkov@nginx.com            break
405*1654Szelenkov@nginx.com        except:
406*1654Szelenkov@nginx.com            sock.close()
407*1654Szelenkov@nginx.com            time.sleep(0.1)
408*1654Szelenkov@nginx.com
409*1654Szelenkov@nginx.com    sock.close()
410*1654Szelenkov@nginx.com
411*1654Szelenkov@nginx.com    assert ret, 'socket connected'
412*1654Szelenkov@nginx.com
413*1654Szelenkov@nginx.com@pytest.fixture
414*1654Szelenkov@nginx.comdef temp_dir(request):
415*1654Szelenkov@nginx.com    return unit_instance['temp_dir']
416*1654Szelenkov@nginx.com
4171596Szelenkov@nginx.com@pytest.fixture
4181596Szelenkov@nginx.comdef is_unsafe(request):
4191596Szelenkov@nginx.com    return request.config.getoption("--unsafe")
4201596Szelenkov@nginx.com
4211596Szelenkov@nginx.com@pytest.fixture
4221596Szelenkov@nginx.comdef is_su(request):
4231596Szelenkov@nginx.com    return os.geteuid() == 0
4241596Szelenkov@nginx.com
4251596Szelenkov@nginx.comdef pytest_sessionfinish(session):
4261596Szelenkov@nginx.com    unit_stop()
427