如何让uwsgi以任何失败的子进程的返回码退出

Ger*_*rat 5 python pytest uwsgi docker

我正在编写一些集成测试,涉及在uwsgi下运行的Python应用程序。
为了测试这一方面,我正在运行一个uwsgi假脱机程序,它要求进程正在运行。
如果pytest测试失败,它将返回一个非零的退出代码,这很棒。
没有主进程,整个uwsgi进程也会返回此退出代码,因此我们的持续集成服务器会做出适当的响应。
但是,当主进程运行时,它总是以零退出代码退出-不管测试失败。

如果有一个子进程,我需要它传递子进程的第一个非零退出代码。

注意:我对模拟这个并不是很感兴趣-我需要测试这个功能。

我创建了一个Dockerized 最小,完整和可验证示例,用于说明我的问题:

Dockerfile:

FROM python:3.6.4-slim-stretch

WORKDIR /srv

RUN apt-get update \
    && apt-get install -y build-essential \
    && pip install uwsgi pytest

COPY test_app.py /srv/

CMD ['/bin/bash']
Run Code Online (Sandbox Code Playgroud)

test_app.py:

import pytest

def test_this():
    assert 1==0
Run Code Online (Sandbox Code Playgroud)

给定目录中的以上两个文件,如果我在没有主进程的情况下在uwsgi 运行此失败的测试,则以下显示返回代码:

$ docker build -t=test .
$ docker run test uwsgi --chdir /srv --pyrun /usr/local/bin/pytest
...
============================= test session starts ==============================
platform linux -- Python 3.6.4, pytest-3.3.2, py-1.5.2, pluggy-0.6.0
rootdir: /srv, inifile:
collected 1 item

test_app.py F                                                            [100%]

=================================== FAILURES ===================================
__________________________________ test_this ___________________________________

    def test_this():
>       assert 1==0
E       assert 1 == 0

test_app.py:4: AssertionError
=========================== 1 failed in 0.05 seconds ===========================
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)

注意:您可以看到此过程(最后一行)的返回码根据需要为非零


现在,除了在主进程上运行uwsgi之外,什么都没有做,我们得到以下输出:

$ docker run test uwsgi --set master=true --chdir /srv --pyrun /usr/local/bin/pytest
...
============================= test session starts ==============================
platform linux -- Python 3.6.4, pytest-3.3.2, py-1.5.2, pluggy-0.6.0
rootdir: /srv, inifile:
collected 1 item

test_app.py F                                                            [100%]

=================================== FAILURES ===================================
__________________________________ test_this ___________________________________

    def test_this():
>       assert 1==0
E       assert 1 == 0

test_app.py:4: AssertionError
=========================== 1 failed in 0.05 seconds ===========================
worker 1 buried after 0 seconds
goodbye to uWSGI.
$ echo $?
0
Run Code Online (Sandbox Code Playgroud)

注意:这次测试返回的代码(最后一行)为零-即使测试失败

如何让uwsgi将失败的退出代码转发给主服务器?

Ger*_*rat 1

这可行,但感觉有点hacky。如果有更好的答案,我会很乐意接受。

我通过添加两个附加文件(以及对 Dockerfile 的小更新)来完成这项工作:

Dockerfile

FROM python:3.6.4-slim-stretch

WORKDIR /srv

RUN apt-get update \
    && apt-get install -y build-essential \
    && pip install uwsgi pytest

COPY test_app.py test run_tests.py /srv/

CMD ['/bin/bash']
Run Code Online (Sandbox Code Playgroud)

测试

#!/bin/bash
uwsgi --set master=true --chdir /srv --pyrun /srv/run_tests.py
exit $(cat /tmp/test_results)
Run Code Online (Sandbox Code Playgroud)

运行测试.py

#!/usr/bin/python

import re
import subprocess
import sys

from pytest import main


def write_result(retcode):

    path = r'/tmp/test_results'
    with open(path, 'w') as f:
        f.write(str(retcode))


def run():

    sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
    retcode = 1
    try:
        retcode = main()
    finally:
        write_result(retcode)

    sys.exit(retcode)


if __name__ == '__main__':
    run()
Run Code Online (Sandbox Code Playgroud)

它的工作方式是,我将 pytest 程序复制并调整到run_tests.py,它将测试的返回代码写入临时文件。测试通过 bash 脚本运行:test,该脚本运行 uwsgi,运行测试,然后使用测试的返回代码退出脚本。

结果现在看起来像

$ docker build -t=test .
$ docker run test /srv/test
...
============================= test session starts ==============================
platform linux -- Python 3.6.4, pytest-3.3.2, py-1.5.2, pluggy-0.6.0
rootdir: /srv, inifile:
collected 1 item

test_app.py F                                                            [100%]

=================================== FAILURES ===================================
__________________________________ test_this ___________________________________

    def test_this():
>       assert 1==0
E       assert 1 == 0

test_app.py:4: AssertionError
=========================== 1 failed in 0.05 seconds ===========================
worker 1 buried after 0 seconds
goodbye to uWSGI.
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)